You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

188 lines
29 KiB

import { addBanner, addArticle, addChapterTitle, addHeader, addParagraph, addSubHeader } from "/scripts/article.js";
import { addInset, addInsetList, addInsetCodeListing, addInsetBulletList } from "/scripts/inset.js";
import { addImageWithCaption, addButtonGroup } from "/scripts/visuals.js";
import { menu } from "/scripts/buttongroups.js";
const main = document.querySelector("main");
main.append(addBanner("<a href=https://www.linkedin.com/learning/docker-for-windows>Docker For Windows</a>", "David Davies", "November 2018"))
main.append(addArticle())
const article = document.querySelector("article");
article.append(addChapterTitle("DEPLOYING AND CONFIGURING CONTAINERS"))
article.append(addHeader("RUNNING WINDOWS IN A CONTAINER"))
article.append(addParagraph("the Microsoft documentation is probably the best source for documentation relating to using these in windows and you can find it at <a href='https"))
article.append(addParagraph("As with Linux containers, however, the best place to find images is the <a href='https"))
article.append(addParagraph("In the quickstarts section of the docs, there is a quick tutorial on how to do this under <a href='https"))
article.append(addParagraph("To start with, we will open PowerShell and run the command"))
article.append(addParagraph("This will download the image and we can verify that it was downloaded with the command"))
article.append(addInset("docker images"))
article.append(addParagraph(" we can then run the container with the command"))
article.append(addParagraph("when the container is running, you will see that the prompt changes to reflect the content of the container. From here, we can run a command that is going to generate a text file with something like"))
article.append(addInset("echo \"Hello World!\" &gt; Hello.txt"))
article.append(addParagraph("we can then exit from the container with the exit command and run"))
article.append(addInset("docker ps -a"))
article.append(addParagraph("to get the idea of our container. Note that if we run the container again, it will start a new container and we will not be able to see the changes (that is, the file we created) in that container."))
article.append(addParagraph("However, we can use the ID to create a new container that will include our changes and we do that with the docker commit command."))
article.append(addParagraph("If we run the command"))
article.append(addInset("docker images"))
article.append(addParagraph("We should see that we have a couple of images, the one we downloaded and the new one we just committed with our own changes. This is shown in Figure 10."))
article.append(addImageWithCaption("./images/figure10.jpg", "Figure 10 - the docker images command with our new container."))
article.append(addParagraph("We can run the container with the command"))
article.append(addParagraph("This is doing several things. It runs the container, outputs the contents of the file Hello.txt and then closes the container. The --rm ption deletes the container automatically but you can omit it if you want to keep the container and the cmd.exe is a command prompt started by docker for the purpose of reading our file."))
article.append(addParagraph("So that's a brief tester of running Windows containers. I try to avoid too much detail because I guess the course will cover some of the more important aspects of this."))
article.append(addHeader("RUNNING WINDOWS IN A CONTAINER"))
article.append(addParagraph("In theory, it is possible to download and run Windows in a container. In the course video, these containers seem to be coming from Microsoft directly, or at least were produced by Microsoft."))
article.append(addParagraph("I Had a few problems trying to get a Windows Server container but eventually managed with hanhongwen86/windowsserver2016 from the docker hub. Note that although containers are generally on the small side due to the fact that they don't have an OS, this image contains a Windows Server OS so it is fairly large at 11GB."))
article.append(addParagraph("You can run the container with the command"))
article.append(addInset("docker run hanhongwen86/windowsserver2016"))
article.append(addParagraph("and you might notice that we get a C prompt, which is the server and then the container exits. You can confirm that by running the command"))
article.append(addInset("docker ps -a"))
article.append(addParagraph("This is shown in figure 11."))
article.append(addImageWithCaption("./images/figure11.jpg", "Figure 11 - Running a Windows Server 2016 container."))
article.append(addParagraph("If We run that command again and add -it, the container will run and will give us an interactive terminal."))
article.append(addInset("docker run -it hanhongwen86/windowsserver2016"))
article.append(addParagraph("We can run DOS commands here to demonstrate the fact that this is a Windows Server 2016 system rather than a command prompt on the host system. For example, we can run dir or tasklist and we get far less output then we would if we run the same command on the host system."))
article.append(addParagraph("If We run a dir command, you will see a file called Licence.txt which you can see in figure 12."))
article.append(addImageWithCaption("./images/figure12.jpg", "Figure 12 - the License.txt file in Windows Server 2016."))
article.append(addParagraph("So this shows us that what we are looking at is a contender which is licenced by Microsoft. It's unlikely that you would want to run something like this in a container unless you were going to take advantages of the features of Windows Server 2016 because of its size and how long it takes to run it. The image is 11GB so it's too big if you just want to experiment with windows in a container if that's the case, Windows nanoserver might be a better option because it is much smaller."))
article.append(addParagraph("I downloaded an image, nanoserver/wamp-wordpress, partly out of curiosity and this is fairly large for a nanoserver image at 3GB. However, it does start up reasonably quickly with the command"))
article.append(addInset("docker run -it nanoserver/wamp-wordpress"))
article.append(addParagraph("We I can mess around with this a little and since it is a WAMP container, we can look at the config files for Apache and the default website and so on we can see that it seems to be reasonably complete. However, bear in mind that this is a cut down version of Windows server so it won't be able to do everything we could do with the Server Core 2016. As an example, we can't run task list here so we don't have any way to check what tasks are running."))
article.append(addParagraph("There are different ways to exit from a running container and one way is to press control and P followed by control and Q. If we do that, we can then run the command"))
article.append(addParagraph("This Should show us something like that shown in figure 13."))
article.append(addImageWithCaption("./images/figure13.jpg", "Figure 13 - Executing docker ps after exiting from a running container."))
article.append(addParagraph("The Interesting thing to note here is that it shows that the container was created 17 hours ago and has been up for 17 hours, but it doesn't tell us when it was stopped. This is because exiting in this way actually doesn't stop the container from running."))
article.append(addParagraph("We can reattach the container with the attached command and the randomly generated container name which you can see under names and figure 13. So that is"))
article.append(addInset("docker attach magical_kilby"))
article.append(addParagraph("This Texas back to the container so we could continue with the previous task if we wanted to. We will exit again, this time with the command"))
article.append(addInset("exit"))
article.append(addParagraph("and we can then run the docker ps command to show that there are no containers running."))
article.append(addHeader("DEPLOYING MICROSOFT IIS IN A CONTAINER"))
article.append(addParagraph("We'll take a look at a Microsoft IIS container which can be a little bit different. I've downloaded an image, nanoserver/iis and we can run this with"))
article.append(addInset("docker run -d -p 80:80 nanoserver/iis"))
article.append(addParagraph("The command is a little bit different to what we have seen previously. Notice that there is no -it option for an interactive terminal although we could have used it if we wanted to go and configure the web server for example, assuming IIS can be configured from a command line."))
article.append(addParagraph("Instead, We used the -d option to start IIS running as a daemon. We have also used the -p option which provides a network address translation by mapping port 80 on the local machine to port 80 in the container. In theory, that should mean that we can access the web page being served up by IIS in the container on our local machine."))
article.append(addParagraph("I was not able to access it with localhost, but I was able to access it using the containers IP address, and you can see this in figure 14."))
article.append(addImageWithCaption("./images/figure14.jpg", "Figure 14 - The IIS default page being served up from a container."))
article.append(addParagraph("As You might expect, it is possible to create a docker file to hold your own website and you can get more info on that in the <a href='https"))
article.append(addParagraph("The pitch also provides a command you can use to run the container with both the -d and -p options. It also shows you how to access the web page from your local machine and it specifies the IP address rather than localhost for that so that may be a change in the way docker works."))
article.append(addParagraph("You can also find information on how to run the <a href='https"))
article.append(addParagraph("It Might be worth pointing out that our interest in IIS is only in so far as it demonstrates how docker works, so we're not covering how to host your own website in a docker container, but it is something you can investigate further if you are interested. Of course, there are lots of other applications such as Redis, WordPress, Drupal and so on as well as programming languages that you can experiment with in a container."))
article.append(addParagraph("Another image we can download that is both interesting and a useful learning opportunity is MySQL and I've downloaded a nanoserver version from the <a href='https"))
article.append(addParagraph("To start with, command is"))
article.append(addInset("docker pull nanoserver/mysql"))
article.append(addParagraph("We can run this with the command"))
article.append(addInset("docker run --name mysql -d -it -p 80:80 nanoserver/mysql"))
article.append(addParagraph("This looks similar to the command we used for IIS. In this case, we are running it as a container and we have also asked for an interactive terminal. The name option is quite interesting, this allows us to specify a name for the container so we don't have to use the name that docker randomly generates."))
article.append(addParagraph(" Following the instructions from the docker hub page, we will use the docker images command to get a list of images. We can then use the command"))
article.append(addParagraph("and this will list all running containers for us. We can run the command"))
article.append(addInset("docker run --name mysql -d -it -p 80:80 nanoserver/mysql"))
article.append(addParagraph("and this will return the container's IP address and similarly, we can use the command"))
article.append(addInset(""))
article.append(addParagraph("Since we have the container's IP address, we can access its web page via the URL"))
article.append(addInset("http://172.21.139.7/info.php"))
article.append(addParagraph("Of course, you would have to insert the correct IP address for the container here. You can also check what web server is running by removing info.php from the URL. This is assuming that this will give you the web server 's default page, which it does in this case. It gives you the default page for IIS."))
article.append(addParagraph("This has been a bit of a digression from the course video but I think it was quite interesting and part of the reason for doing that was because I couldn't find the Microsoft download going back to the videos, David does mention that you can go to the <a href='https://www.microsoft.com/en-gb/sql-server/sql-server-downloads'>SQL Server Downloads</a> page and Scroll down to see the Docker image as shown in figure 15."))
article.append(addImageWithCaption("./images/figure15.jpg", "Figure 15 - the SQL Server downloads page."))
article.append(addParagraph("You can select Choose your installation setup to bring up the window shown in figure 16."))
article.append(addImageWithCaption("./images/figure16.jpg", "Figure 16 - the Choose your installation setup window."))
article.append(addParagraph("From here, we can select the first option which is for a windows container and this takes us to the <a href='https://hub.docker.com/_/microsoft-mssql-server'>Microsoft SQL Server - Ubuntu based images</a> page in the docker hub. At this point, I am getting the impression that Microsoft doesn't really want us to use windows containers anymore."))
article.append(addParagraph("I had intended to switch back to using Linux containers on my Windows 11 machine and use Windows containers on my Windows 10 machine. However, I found that although I could switch to Windows containers on the Windows 10 machine, Docker then refused to start because on Windows 10 Home edition, you can only use Linux containers. Unfortunately, I couldn't find a way to switch back because of the fact that it wouldn't start so I reinstalled it which should sort that out and going forward, I will use Windows containers on Window 11 (Pro Edition) and Linux containers on my old Windows 10 machine!"))
article.append(addParagraph("I did manage to find a fork of the official microsoft/mssql-server-windows-express image at <a href='https://hub.docker.com/r/octopusdeploy/mssql-server-windows-express'>octopusdeploy/mssql-server-windows-express</a> so I will try using that for this part of the course. This is a Windows image."))
article.append(addParagraph("I also downloaded a Linux image for mysql and this is the official Docker image which you can get from <a href='https://hub.docker.com/_/mysql'>MySQL - Docker Hub</a>."))
article.append(addParagraph("To run the Windows container, we will use the command"))
article.append(addInset("docker container run -d -p 1433:1433 --name sqlserver -e sa_password=Sqlserver1! -e ACCEPT_EULA=Y -v c:\sqldata:c:\data octopusdeploy/mssql-server-windows-express"))
article.append(addParagraph("We will look at some of the more interesting options here."))
article.append(addInset("-d"))
article.append(addParagraph("This is going to run the container as a daemon, this is sometimes referred to as detached mode."))
article.append(addInset("-p 1433:1433"))
article.append(addParagraph("Port 1433 is the MySQL port and we are mapping this port on the host to the same port inside the container."))
article.append(addInset("-e sa_password=Sqlserver1!"))
article.append(addParagraph("Here, we are using an environment variable to setup a passwird for the sysadmin."))
article.append(addInset("-e ACCEPT_EULA=Y"))
article.append(addParagraph("This is also an environment variable used to accept the End User License Agreement."))
article.append(addInset("c:\sqldata:c:\data"))
article.append(addParagraph("This maps the directory, sqldata in the host machine's c drive to a directory inside the container."))
article.append(addParagraph("Note that in Docker, you can't run more than one container with the same name so if you have forgotten that you have already run this command, you will get an error if you try running it again using the same name and the error will look a little bit like the image shown in figure 17."))
article.append(addImageWithCaption("./images/figure17.jpg", "Figure 17 - getting an error because the container name is already in use."))
article.append(addParagraph("Of course, we can run multiple containers from a single image if we want to, that's not a problem unless we have some sort og conflict such as with the container name. The port number can also cause a conflict so if we just tried the command with a different name, we would get a similar error because of that. It will still run the container, but the network address translation will fail and this will probably not work as you would expect if you try to use it like that."))
article.append(addParagraph("If we want to run this as a new command, we will need to get rid of the existing container which, in this case, we can do with the command"))
article.append(addInset("docker rm sqlserver --force"))
article.append(addInset("Note that David didn't use the --force option but when I tried to run it in the same way that he did, I got an error saying that you can't remover a running container unless you use this option, so I did."))
article.append(addParagraph("You can also stop the container with a command such as"))
article.append(addInset("docker stop sqlserver"))
article.append(addParagraph("and you can then use the rm command without the --force option."))
article.append(addParagraph("You will also see an error with this command if the sqldata directory doesn't already exist so you can just go ahead and"))
article.append(addInset("mkdir c:\sqldata"))
article.append(addParagraph("to resolve that problem. Once you have sorted out all of these problems, you can run the command again and you should see a container id before being returned to your command prompt - remember, we haven't requested an interactive terminal."))
article.append(addParagraph("Now that this is running, we will test is using the SQL Server Management Studio (SSMS) which you can download from <a href='https://learn.microsoft.com/en-gb/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver16'>Learn Microsoft</a>. I already have this downloaded and installed and when it runs you should see something similar to figure 18."))
article.append(addImageWithCaption("./images/figure18.jpg", "Figure 18 - starting up the SQL Server Management Studio."))
article.append(addParagraph("For the Server Name, we can use the container's IP address. Normally, we would get that with ipconfig but we need to get the address for the container. The command"))
article.append(addInset("docker exec"))
article.append(addParagraph("Allows us to run a command as if it were being run inside the container. We can use that with the container name, in this case sqlserver and the command we want to run, in this case ipconfig so that gives us"))
article.append(addInset("docker exec sqlserver ipconfig"))
article.append(addParagraph("The result of running this is shown in figure 19."))
article.append(addImageWithCaption("./images/figure19.jpg", "Figure 19 - using docker exec to run a command, ipconfig, on the slqserver container."))
article.append(addParagraph("In SQL Server Management Studio, we will insert the IP address into the Server name field. It defaults to Windows Authentication and we want to change that to SQL Server Authentication. Remember that when we ran the container, we used an environment variable to specify both a username and a password:"))
article.append(addInset("-e sa_password=Sqlserver1!"))
article.append(addParagraph("so we can use sa as the username and Sqlserver1! as the password and this connects us to SQL Server as shown in figure 20."))
article.append(addImageWithCaption("./images/figure20.jpg", "Figure 20 - successfully connected to SQL Server."))
article.append(addParagraph("To test this, we can right-click on Databases and select New Database and we will call it ilovedocker. The paths shown for the database files are the paths inside the container so we want to set these to"))
article.append(addInset("C:\data"))
article.append(addParagraph("so that our database and the logs will both be saved there. When we ran the container, we also included a mapping for that directory"))
article.append(addInset("c:\sqldata:c:\data"))
article.append(addParagraph("so we can click on OK to save the database. We can then cd to the sqldata directory on the local machine and we will see the database is saved there. This is shown in figure 21."))
article.append(addImageWithCaption("./images/figure21.jpg", "Figure 21 - the database saved in our local folder, sqldata."))
article.append(addParagraph("To summarise what we are doing here, we are creating and editing a database using SQL Server Management Studio which in turn is using SQL Server running in a Docker container. That is important because it demonstrates how Docker can be used in a very practical way to allow you to make use of an application like SQL Server without having to install it on your local machine."))
article.append(addHeader("TIPS AND TRICKS FOR ADMINISTERING CONTAINERS"))
article.append(addParagraph("We've already seen the docker version command but let's just take a brief look at it again. Figures 22 and 23 show the result of running the command on my Windows 11 and Windows 10 machines respectively."))
article.append(addImageWithCaption("./images/figure22.jpg", "Figure 22 - the docker version command on my Windows 11 machine."))
article.append(addImageWithCaption("./images/figure23.jpg", "Figure 23 - the docker version command on my Windows 10 machine."))
article.append(addParagraph("There are a couple of interesting points here. Firstly, notice that the version on Windows 10 is slightly more up to date because it was installed a little after I installed it on Windows 11. On each machine, if you compare the client build with the server build, you will see that the versions are the same and this is because we are basically using the same installation as both the client and server. These can be different if you are, for example, running docker locally but using a remote server."))
article.append(addParagraph("One difference you will see between the two is in the OS Arch shown under the server. On the Windows 11 machine, this is"))
article.append(addInset("OS/Arch: windows/amd64"))
article.append(addParagraph("On the Windows 10 machine, this is shown as"))
article.append(addInset("OS/Arch: linux/amd64"))
article.append(addParagraph("This is because I am running Windows containers in Windows 11 and Linux containers in Windows 10. Another item of useful info, remember when we we installed Docker, David selected the version on the Edge channel which I didn't have the option to do and I assumed that as there was only one version available, it would likely be the stable version. Under docker version, notice that in both cases, Experimental is set to false which indicates that this is indeed the stable version."))
article.append(addParagraph("So we can get a lot of useful info from the docker version command. Another similar command is docker info and figures 24 and 25 shows the outout I get from running this on both my installations."))
article.append(addImageWithCaption("./images/figure24.jpg", "Figure 24 - the docker info command on my Windows 11 machine."))
article.append(addImageWithCaption("./images/figure25.jpg", "Figure 25 - the docker info command on my Windows 10 machine."))
article.append(addParagraph("As you can see, I have 17 containers on the Windows 11 machine and 12 images. Of those containers, only 1 is currently running and 16 are in the stopped state. I just reinstalled Docker on the Windows 10 machine and this is reflected in the fact that there are no containers and just one image which is the mysql image I downloaded in the previous section and it hasn't been run as yet. There is a lot of useful information here including details of the OS, number of CPUs and so on and there is a confirmation that we are running the Community Edition of Docker."))
article.append(addParagraph("Another useful command is docker logs. For example, if I want to see the logs for my sqlserver command, I can run the command"))
article.append(addInset("docker logs sqlserver"))
article.append(addParagraph("and the command"))
article.append(addInset("docker logs --help"))
article.append(addParagraph("will show you the small help file for the docker logs command. Figure 26 shows you the sort of output you might expect to see if you run both of these commands."))
article.append("./images/figure26.jpg", "Figure 26 - the output from 'the docker logs sqlserver' and 'docker logs --help' commands.")
article.append(addParagraph("We have seen the docker images command which lists images but there is also a docker image command where image acts like a kind of adjective in that you also need to add an action onto the end of it. If you omit it and just enter the command"))
article.append(addInset("docker image"))
article.append(addParagraph("you will get the docker image help file which shows you what actions can be added. For example, we can run the command"))
article.append(addInset("docker image ls"))
article.append(addParagraph("and this will give you the same output as you would get from docker images."))
article.append(addParagraph("We can use rm with docker image to remove an image. These docker image commands are demonstrated in figure 27."))
article.append("./images/figure27.jpg", "Figure 27 - the docker image command.")
article.append(addParagraph("Notice that I tried to remove the sqlserver image which is still running in a container so not surprisingly, this returned an error. I tried the same command with the nanoserver.mysql image which isn't currently in a running container, but it is referenced by a container so this also returned an error. I then ran the same command with the -f option to force the removal and as you can see, I got a message back confirming that the image has been deleted. This can be confirmed, of course, by getting a list of images again and you will see the image is no longer listed."))
article.append(addParagraph("This is just a brief sample of some of the commands you can use to help administer docker and you can get more information in the online docs. There are also a number of cheat sheets online including <a href='https://docs.docker.com/get-started/docker_cheatsheet.pdf'>this one</a> from the online docs."))
article.append(addHeader("CONFIGURING CONTAINER STORAGE"))
article.append(addParagraph("A good starting point for info on Docker container storage is the <a href='https"))
article.append(addParagraph("It is important to remember that images are read-only. Basically, this means that when you start up a container from an image, any changes you make are not written back to the image. The container uses a read/write layer, effectively a virtual file system called the Docker Union File System."))
article.append(addParagraph("So, if you write any changes in the container, they will not be written to the original image but you can write them to a new image file."))
article.append(addParagraph("The page on learn.microsoft.com also provides an introduction to <a href='https"))
article.append(addParagraph("All of the information you need to configure container storage is on the pages linked to above and you can also get more information form the Docker docs, specifically on the page entitled <a href='https"))
article.append(addHeader("CONFIGURE CONTAINER NETWORKING"))
article.append(addParagraph("By default, the networking is a container is isolated from the network on the host machine which is why we need to use something like a network address translation to map a port in the container to a port on the host machine which we have already seen a couple of times. That<EFBFBD>s probably the simplest way to configure networking between the container and the host."))
article.append(addParagraph("As with storage, you can get a good overview of how networking works from the <a href='https"))
article.append(addParagraph("Essentially, networking in a container is the same as networking in a Virtual Machine and you have the same options which Network Address Translation, Transparent, Overlay, Layer 2 Bridging and Layer 2 Tunnelling."))
article.append(addParagraph("Networks in Docker are configured using the docker network command as show in figure 28."))
article.append(addImageWithCaption("./images/figure28.jpg", "Figure 28 - the docker network command."))
article.append(addParagraph("As you can see, the command"))
article.append(addInset("docker network"))
article.append(addParagraph("Will display the commands you can run and this includes the "))
article.append(addInset("docker network ls"))
article.append(addParagraph("command which lists all of the networks configured in docker. The list in figure 28 shows the networks that docker creates by default so we have the bridge network, the host network and the none network."))
article.append(addParagraph("If we run the inspect command on a container, we get a lot of information including a list of the networks that container is attached to and an example of that is shown in figure 29."))
article.append(addImageWithCaption("./images/figure29.jpg", "Figure 29 - the docker container inspect command."))
article.append(addParagraph("In this example, I have a sql container with the name mysql1 running on my Windows machine, so I can inspect it with the command"))
article.append(addInset("docker container inspect mysql1"))
article.append(addParagraph("This command generates a lot of output and we can only see the last part of this in figure 29. There is also some useful information here relating to storage being used for that container. The important thing here is that it shows us the id and type (nat) of the network as well as the IP address (172.20.103.94) for the container."))
article.append(addParagraph("By default, a docker container will be connected to the nat network."))
main.append(menu("dockerfw"))