Spending the day going over Docker topics.
Containers are really just about running software with all the things required bundled in and ready to go. When getting started, use that as the basis for why you’d use them, everything else complicates the discussion (but there are other benefits). The container means we can deploy and the user can assume the required things are included and ready to go.
Docker for Windows uses Hyper-V to be able to run the Linux containers. (That’s why you need Hyper-V to install). The benefit is that Windows can run both Windows and Linux containers. You’ll also need Hardware Virtualization available. There’s a few ways to check, but the quickest is just in task manager.
Once installed, we can use docker info
to get the details about the Docker environment. One note that seems odd at first is that we see that Docker for Windows is ready to run Linux containers. We can use docker version
to see the information about the client (which will be Windows).
docker run -dp 80:80 docker/getting-started
Will get a test container up and running. It’ll drag it down from the Docker repo, then start it on port 80 on localhost. (80:80
mapping is host:container)
We can also use the format
docker run -p 8080:80 nginx
Then, we use docker ps
to see the running containers.
We can use docker stop d86
where d86
is the start of a container Id (or name).
We can use docker ps -a
to see all installed containers, where ps
on its own only shows running containers.
We can use docker rm d86
to remove a container. You can string multiple together like docker rm d86 d99 t44
What about Windows Containers though?
You switch modes to get the Windows containers in a desktop environment:
Then we could do something like docker run -p 8080:80 -d --name iis microsoft/iis:nanoserver
where nanoserver
is the tag. Leaving it default would have used full server core because it is the image assigned to the default tag.
BUT! That’s for us to mess about. For a production environment, you’d configure a windows server to host Windows containers or a Linux server to run Linux containers.
docker inspect 6ac
can show us the detail of the container. The container IP is interesting for example - its the IP that the container apps are bound to, you can connect to them via that IP as well (or ping it etc).
c:\temp>docker inspect 6a
[
{
"Id": "6ac057b18be4703a92928dca90ddfa9953a4efc01ca337c194c469966a831567",
"Created": "2020-05-25T17:11:48.370351Z",
"Path": "C:\\ServiceMonitor.exe",
"Args": [
"w3svc"
<< snip >>
"Networks": {
"nat": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "661669bb21c5ac004fdb0ec6ddec297403af311de07aedf6425717ab6b754b97",
"EndpointID": "6f34e274c25df87366504b964095f5d021106f162e62ec6b7c306f15ef69ac31",
"Gateway": "172.20.16.1",
"IPAddress": "172.20.23.68",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "00:15:5d:98:91:7b",
"DriverOpts": null
}
}
}
}
]
Platform Component Differences
For Linux Containers:
- Proxy: com.docker.proxy
- VM on Hyper-V
- “docker run nginx” –> com.docker.proxy –> Linux VM –> container
For Windows (Desktop) Containers:
- dockerd.exe (docker engine for Windows)
- com.docker.proxy
- “docker run iis” –> com.docker.proxy –> dockerd.exe –> container
For Windows Containers:
- dockerd.exe
- “docker run iis” –> dockerd.exe –> container
Installing for Windows Server
Install-Module DockerMsftProvider -Force
Install-Package Docker -ProviderName DockerMsftProvider -Force
WARNING: A restart is required to enable the containers feature. Please restart your machine.
Name Version Source Summary
---- ------- ------ -------
Docker 19.03.5 DockerDefault Contains Docker EE for use with Windows Server.
(Installs dockerd.exe and docker.exe in c:\program files\docker
and configures dockerd as a service)
Jumping ‘into’ a Windows container
docker run -it mcr.microsoft.com/windows/servercore:1809
Remember that all containers on the host are sharing the same kernel.
The container is the usermode binaries. Even in windows case, this will be the win32 libraries that the apps use, that make the system calls to the kernels.
We use layers in containers to share some of the common libraries between containers. Docker uses read only layers for the base OS things.
Windows Container Compatibility
Here’s the matrix showing which containers run on which hosts. “As we’ve been improving the Windows container features, we’ve had to make some changes that can affect compatibility. Older containers will run the same on newer hosts with Hyper-V isolation, and will use the same (older) kernel version. However, if you want to run a container based on a newer Windows build, it can only run on the newer host build.”
It’s actually pretty strict for process isolation without Hyper-V; the pattern below repeats for all the OS tabs. You need to match the container and host OS release.
While it makes sense with the shared kernel and all, it puts a bit of a downer in the container benefits column for Windows. When you get it wrong, it looks like this:
PS C:\Users\administrator.JMPESP> docker run -it microsoft/dotnet:nanoserver
C:\Program Files\Docker\docker.exe: Error response from daemon: hcsshim::CreateComputeSystem 8f5ff8b49acbdedaba339474e101cf5ab640a195013cbf03c4010b3a35300a42: The container operating system does not match the host operating system.
(extra info: {"SystemType":"Container","Name":"8f5ff8b49acbdedaba339474e101cf5ab640a195013cbf03c4010b3a35300a42","Owner":"docker","VolumePath":"\\\\?\\Volume{7a71c6ab-6183-4bf0-8485-f70f9e853e12}","IgnoreFlushesDuringBoot":true,"LayerFolderPath":"C:\\ProgramData\\docker\\windowsfilter\\8f5ff8b49acbdedaba339474e101cf5ab640a195013cbf03c4010b3a35300a42","Layers":[{"ID":"64412752-35ed-5a44-bc8e-2c828a2d0086","Path":"C:\\ProgramData\\docker\\windowsfilter\\48a2a6bd0296616476652b32588fd4dd687d6309aeb21ff351c1ed372ddd216d"},{"ID":"882f1b68-9839-5672-a0b7-4ec6c4b0c48b","Path":"C:\\ProgramData\\docker\\windowsfilter\\24bfe125698be2d11a0f25c1c47e8921a30bc33cf3af5a3c60f2ca29bf131707"},{"ID":"6c2e4657-f2ee-58bf-b849-396d6492ae9f","Path":"C:\\ProgramData\\docker\\windowsfilter\\a03f1a7ba9c37165e258a1d7c8bfc8b9224961dfb8214ea25e2c47dd433fed79"},{"ID":"207587ea-8db4-57b5-b258-c531ad292776","Path":"C:\\ProgramData\\docker\\windowsfilter\\2d717da57f8ab8aa6552b580645ab563bcd850b59039f59930e6c5c47010fb02"},{"ID":"714f130d-03cb-590f-ae06-516cd25fef1c","Path":"C:\\ProgramData\\docker\\windowsfilter\\7e149efdd60f07074b26448db7448e1c08ffcca209e7fcfc579224574f8c8f82"},{"ID":"e7a6ef02-1675-5324-8ec7-9f5411a68950","Path":"C:\\ProgramData\\docker\\windowsfilter\\89eba2053a56a03c0de6afc623273987bdf3ae97ced6f843eba9e337f3e4ea9e"},{"ID":"b2d97b4d-dc64-567b-ba20-34ddbd0482ce","Path":"C:\\ProgramData\\docker\\windowsfilter\\93dbd7e7f05ed00ccaea9811236d5c1c4f7bd50eb930b4471b850cd42077b2f4"},{"ID":"3049dd7e-a22d-5571-a379-cacde34905b5","Path":"C:\\ProgramData\\docker\\windowsfilter\\b226494957ff6a6e975b6f82671976690f11160ecf90341f4e52a41d07917b52"},{"ID":"d7b20a56-b3a2-5798-a252-eed5c6c3c220","Path":"C:\\ProgramData\\docker\\windowsfilter\\9ba3b245bf59aa766f4f2e375608224ad77928e99e6b97a562f4076c500e8732"}],"HostName":"8f5ff8b49acb","HvPartition":false,"EndpointList":["E19A9E42-D3B3-4ACD-A3DA-2820A67B5639"],"AllowUnqualifiedDNSQuery":true}).
Isolation
- Windows Server containers use isolation similar to the Linux approach (process isolation). This wont run on the client SKU’s, requires server SKU.
- Windows Hyper-V containers have isolation via the Hypervisor (vm isolation). If the machine has Hyper-V components installed the container can be launched with
--isolation=hyperv
to force this mode.
Save image:
docker save mcr.microsoft.com/dotnet/framework/runtime:4.8-20200527-windowsservercore-2004 -o windows.rar
Building images:
You’ll speed it up and also know if the architecture will run on your platform if you try to run the base of your new container first. Like:
docker run mcr.microsoft.com/windows/servercore:ltsc2019
Then, customize a Dockerfile
file:
# escape=`
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN powershell -Command `
Add-WindowsFeature Web-Server; `
Invoke-WebRequest -UseBasicParsing -Uri "https://dotnetbinaries.blob.core.windows.net/servicemonitor/2.0.1.6/ServiceMonitor.exe" -OutFile "C:\ServiceMonitor.exe"
EXPOSE 80
ENTRYPOINT ["C:\ServiceMonitor.exe", "w3svc"]
^ or a more simple example might be copying in some content for a websute in a folder called “app”
FROM mcr.microsoft.com/windows/servercore/iis
COPY app c:/inetpub/wwwroot
Then from the location you saved Dockerfile
run:
docker build -t iis_test .
(iis_test is the new name for our container)
It will hopefully look like this:
PS C:\Users\Administrator\Desktop> docker build -t iis_test .
Sending build context to Docker daemon 4.608kB
Step 1/4 : FROM mcr.microsoft.com/windows/servercore:ltsc2019
---> 561b89eac394
Step 2/4 : RUN powershell -Command Add-WindowsFeature Web-Server; Invoke-WebRequest -UseBasicParsing -Uri "https://dotnetbinaries.blob.core.windows.net/servicemonitor/2.0.1.6/ServiceMonitor.exe" -OutFile "C:\ServiceMonitor.exe"
---> Running in 426c47316627
Success Restart Needed Exit Code Feature Result
------- -------------- --------- --------------
True No Success {Common HTTP Features, Default Documen...
Removing intermediate container 426c47316627
---> 10c16f5d1b79
Step 3/4 : EXPOSE 80
---> Running in cf424cb1fac7
Removing intermediate container cf424cb1fac7
---> 97b3f30fc866
Step 4/4 : ENTRYPOINT ["C:\ServiceMonitor.exe", "w3svc"]
---> Running in beb6bf91fcca
Removing intermediate container beb6bf91fcca
---> 5912408a16eb
Successfully built 5912408a16eb
Successfully tagged iis_test:latest
PS C:\Users\Administrator\Desktop>
We should be able to run it like this:
docker run -p 8080:80 -d iis_test:latest
Because i’m on Windows i have that issue with accessing it on the local host via the port i just mapped. For that i can use the internal address. I can either create a shell (docker exec {identifier} -it powershell
)into the machine or do something like docker inspect
Removing all the stopped containers in the lab
docker container prune
Docker Compose
Build sets of related docker containers from a .yaml file.
docker-compose up
Do the yaml.
We get an embedded DNS server for internal resolution of the machine names which will work on the internal docker engine switch. That allows us to pass them as environment variables in the yaml for complex applications with dependencies between containers.
Networks
We can mess with them with docker network
e.g:
PS C:\Users\Administrator> docker network ls
NETWORK ID NAME DRIVER SCOPE
8cbd7933a480 nat nat local
a12ad0a25fcc none null local
We can pass a --net
parameter with docker run
to connect to specific networks if needed.
Troubleshooting tool for Microsoft Server Docker hosts
Invoke-WebRequest https://aka.ms/Debug-ContainerHost.ps1 -UseBasicParsing | Invoke-Expression