import { addBanner, addArticle, addTitle, addHeader, addParagraph, addSubHeader } from '/scripts/article.js';
import { addInset, addInsetList, addInsetCodeListing, addInsetBulletList } from '/scripts/inset.js';
import { addImageWithCaption, addButtonGroup } from '/scripts/visuals.js';
import { addSidebar} from '/scripts/sidebar.js';
import { addSyntax } from '/scripts/code.js';
const heading = document.querySelector(".heading");
const global = document.querySelector(".global_menu");
const local = document.querySelector(".local_menu");
const sidebar = document.querySelector(".sidebar");
const main = document.querySelector(".main_content");
heading.append(addTitle("Docker For Windows"));
heading.append(addParagraph("David Davis - LinkedIn Learning - November 2018"));
heading.append(addParagraph("Chapter 3 - DEPLOYING AND CONFIGURING CONTAINERS"));;
main.append(addHeader("RUNNING WINDOWS IN A CONTAINER"));
main.append(addParagraph("the Microsoft documentation is probably the best source for documentation relating to using these in windows and you can find it at SQL Server Downloads page and Scroll down to see the Docker image as shown in figure 15."));
main.append(addImageWithCaption("./images/figure15.jpg", "Figure 15 - the SQL Server downloads page."));
main.append(addParagraph("You can select Choose your installation setup to bring up the window shown in figure 16."));
main.append(addImageWithCaption("./images/figure16.jpg", "Figure 16 - the Choose your installation setup window."));
main.append(addParagraph("From here, we can select the first option which is for a windows container and this takes us to the Microsoft SQL Server - Ubuntu based images 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."));
main.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!"));
main.append(addParagraph("I did manage to find a fork of the official microsoft/mssql-server-windows-express image at octopusdeploy/mssql-server-windows-express so I will try using that for this part of the course. This is a Windows image."));
main.append(addParagraph("I also downloaded a Linux image for mysql and this is the official Docker image which you can get from MySQL - Docker Hub."));
main.append(addParagraph("To run the Windows container, we will use the command"));
main.append(addSyntax("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"));
main.append(addParagraph("We will look at some of the more interesting options here."));
main.append(addSyntax("-d"));
main.append(addParagraph("This is going to run the container as a daemon, this is sometimes referred to as detached mode."));
main.append(addSyntax("-p 1433:1433"));
main.append(addParagraph("Port 1433 is the MySQL port and we are mapping this port on the host to the same port inside the container."));
main.append(addSyntax("-e sa_password=Sqlserver1!"));
main.append(addParagraph("Here, we are using an environment variable to setup a passwird for the sysadmin."));
main.append(addSyntax("-e ACCEPT_EULA=Y"));
main.append(addParagraph("This is also an environment variable used to accept the End User License Agreement."));
main.append(addSyntax("c:\sqldata:c:\data"));
main.append(addParagraph("This maps the directory, sqldata in the host machine's c drive to a directory inside the container."));
main.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."));
main.append(addImageWithCaption("./images/figure17.jpg", "Figure 17 - getting an error because the container name is already in use."));
main.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."));
main.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"));
main.append(addSyntax("docker rm sqlserver --force"));
main.append(addSyntax("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."));
main.append(addParagraph("You can also stop the container with a command such as"));
main.append(addSyntax("docker stop sqlserver"));
main.append(addParagraph("and you can then use the rm command without the --force option."));
main.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"));
main.append(addSyntax("mkdir c:\sqldata"));
main.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."));
main.append(addParagraph("Now that this is running, we will test is using the SQL Server Management Studio (SSMS) which you can download from Learn Microsoft. I already have this downloaded and installed and when it runs you should see something similar to figure 18."));
main.append(addImageWithCaption("./images/figure18.jpg", "Figure 18 - starting up the SQL Server Management Studio."));
main.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"));
main.append(addSyntax("docker exec"));
main.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"));
main.append(addSyntax("docker exec sqlserver ipconfig"));
main.append(addParagraph("The result of running this is shown in figure 19."));
main.append(addImageWithCaption("./images/figure19.jpg", "Figure 19 - using docker exec to run a command, ipconfig, on the slqserver container."));
main.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:"));
main.append(addSyntax("-e sa_password=Sqlserver1!"));
main.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."));
main.append(addImageWithCaption("./images/figure20.jpg", "Figure 20 - successfully connected to SQL Server."));
main.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"));
main.append(addSyntax("C:\data"));
main.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"));
main.append(addSyntax("c:\sqldata:c:\data"));
main.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."));
main.append(addImageWithCaption("./images/figure21.jpg", "Figure 21 - the database saved in our local folder, sqldata."));
main.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."));
main.append(addHeader("TIPS AND TRICKS FOR ADMINISTERING CONTAINERS"));
main.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."));
main.append(addImageWithCaption("./images/figure22.jpg", "Figure 22 - the docker version command on my Windows 11 machine."));
main.append(addImageWithCaption("./images/figure23.jpg", "Figure 23 - the docker version command on my Windows 10 machine."));
main.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."));
main.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"));
main.append(addSyntax("OS/Arch: windows/amd64"));
main.append(addParagraph("On the Windows 10 machine, this is shown as"));
main.append(addSyntax("OS/Arch: linux/amd64"));
main.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."));
main.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."));
main.append(addImageWithCaption("./images/figure24.jpg", "Figure 24 - the docker info command on my Windows 11 machine."));
main.append(addImageWithCaption("./images/figure25.jpg", "Figure 25 - the docker info command on my Windows 10 machine."));
main.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."));
main.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"));
main.append(addSyntax("docker logs sqlserver"));
main.append(addParagraph("and the command"));
main.append(addSyntax("docker logs --help"));
main.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."));
main.append("./images/figure26.jpg", "Figure 26 - the output from 'the docker logs sqlserver' and 'docker logs --help' commands.")
main.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"));
main.append(addSyntax("docker image"));
main.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"));
main.append(addSyntax("docker image ls"));
main.append(addParagraph("and this will give you the same output as you would get from docker images."));
main.append(addParagraph("We can use rm with docker image to remove an image. These docker image commands are demonstrated in figure 27."));
main.append("./images/figure27.jpg", "Figure 27 - the docker image command.")
main.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."));
main.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 this one from the online docs."));
main.append(addHeader("CONFIGURING CONTAINER STORAGE"));
main.append(addParagraph("A good starting point for info on Docker container storage is the