{"id":70946,"date":"2017-05-10T16:19:38","date_gmt":"2017-05-10T16:19:38","guid":{"rendered":"https:\/\/www.simple-talk.com\/?p=70946"},"modified":"2021-04-27T13:55:25","modified_gmt":"2021-04-27T13:55:25","slug":"working-windows-containers-docker-stride","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/devops\/containers-and-virtualization\/working-windows-containers-docker-stride\/","title":{"rendered":"Working with Windows Containers and Docker: Into your Stride"},"content":{"rendered":"<ul>\n<li><a href=\"https:\/\/www.simple-talk.com\/sysadmin\/virtualization\/working-windows-containers-docker-basics\/\">First Part \u2013 The basics<\/a>: the basic principles of how container virtualization is implemented in Windows Server 2016 operating system.<\/li>\n<li><a href=\"https:\/\/www.simple-talk.com\/sysadmin\/virtualization\/working-windows-containers-docker-running\/\">Second part \u2013 Up and Running<\/a>: creating and managing Windows Server Containers using Docker.<\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/virtualization\/working-windows-containers-docker-stride\/\">Third part \u2013 Into your Stride<\/a> Working with Windows Containers and Docker<\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/containerization\/working-windows-containers-docker-save-data\/\">Fourth part<\/a> -- Save the Container Data<\/li>\n<\/ul>\n\n<p>In this article I\u2019ll be explaining some of the differences between Windows containers and Docker. To allow us to do more with Windows Containers and Docker, I\u2019ll need to explain a couple of new techniques such as using <strong>Docker-Compose<\/strong> to build a multi-container application, and using <strong>Image2Docker<\/strong> to port existing Windows application workloads from virtual machines to Docker images. I\u2019ll then go on to explain and demonstrate Hyper-V Isolation because it affects whether you can run a Hyper-V container on Windows Server.<\/p>\n<h2>Linux Containers on Windows: Bridging the Gap<\/h2>\n<p>Before going further with this article, I must demonstrate that if I try to run a Linux Container on my Windows Container Host, the attempt will fail because the Windows and Linux kernels are fundamentally different. We can&#8217;t currently run Linux-based containers on a Windows container host:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; docker pull wordpress\r\n  Using default tag: latest\r\n  latest: Pulling from library\/wordpress\r\n  image operating system \"linux\" cannot be used on this platform<\/pre>\n<p>This problem is being solved, and developers will soon be able to run Linux containers natively on Windows Server using the Hyper-V container isolation technology. Microsoft announced this fact during <a href=\"https:\/\/2017.dockercon.com\/\">DockerCon 2017<\/a> conference, taking place in Austin, Texas. When this is released, it will remove the need for separate infrastructures and development tools for the two operating systems. At the same DockerCon event, The Docker team announced LinuxKit, a secure and portable Linux subsystem for the container movement. LinuxKit will provide the tooling that will allow us to build custom Linux subsystems that include just the components that are required by the runtime platform. The project to enable this new capability was officially launched at the event. Docker will be working with Microsoft to integrate the LinuxKit subsystem with Hyper-V isolation.<\/p>\n<h2>Docker-Compose<\/h2>\n<p>Although Docker provides us with a container platform that allows simple and fast deployment, the process of setting up a new environment can be time-consuming, especially if you have more than one service to deploy. <strong>Docker-Compose<\/strong> simplifies the installation process to a single deployment command. <strong>Docker-Compose <\/strong>is a tool that greatly reduces the time and effort required to define and run multi-container Docker applications. With <strong>Docker-Compose<\/strong>, you use a special <strong>docker-compose.yml<\/strong> file to configure your application&#8217;s services. Then, just by using a single command, you can use data in the file to create and start all the services from your configuration.<\/p>\n<p>There are two steps to Using <strong>Docker-Compose<\/strong>:<\/p>\n<ul>\n<li>Define the services that make up your app in <strong>docker-compose.yml<\/strong> to be run together in an isolated environment<\/li>\n<li>Run <strong>docker-compose<\/strong> to run your entire app<\/li>\n<\/ul>\n<p>You must install the <strong>Docker-Compose<\/strong> executable using this command:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; Invoke-WebRequest https:\/\/dl.bintray.com\/docker-compose\/master\/docker-compose-Windows-x86_64.exe -UseBasicParsing -OutFile $env:ProgramFiles\\docker\\docker-compose.exe<\/pre>\n<p>If you already have a <strong>Docker-Compose.yml<\/strong> file, then you just have to run the following:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; docker-compose -f docker-compose.yml up<\/pre>\n<p>That\u2019s it. Your App is deployed!<\/p>\n<h3><strong>What&#8217;s happening here?<\/strong><\/h3>\n<p>When I run the <strong>Docker-Compose<\/strong> command, Docker will build a Windows container from the <strong>Docker-Compose.yml<\/strong> file. Instead of using one or more dockerfile(s), here I can deploy, for example, an entire application based on a web server and a database. Below is an example of a <strong>Docker-Compose.yml<\/strong> file example, written in YAML:<\/p>\n<pre class=\"theme:vs2012 lang:yaml decode:true \">version: '3'\r\n  services:\r\n    db:\r\n      image: microsoft\/mssql-server-windows-express\r\n      environment:\r\n        sa_password: \"Password\"\r\n      ports:\r\n        - \"1433:1433\" \r\n    web:\r\n      image: getcmd\/MyIIS\r\n      environment:\r\n        - \"Data:DefaultConnection:ConnectionString=Server=db,1433;Database=MyIISWebSite;User Id=sa;Password=Password;MultipleActiveResultSets=True\"\r\n      depends_on:\r\n        - \"db\"\r\n      ports:\r\n        - \"5000:5000\"\r\n  networks:\r\n    default:\r\n      external:\r\n        name: nat<\/pre>\n<p>The \u201cServices:\u201d section will define two services: \u201cdb\u201d and \u201cweb\u201d. The \u201cdb\u201d service is a Microsoft SQL Express image from Microsoft. This service includes some parameters:<\/p>\n<ul>\n<li>The password for the SA account is set to \u201cPassword1\u201d<\/li>\n<li>Port 1433 on the host is mapped to the exposed port 1433 in the container<\/li>\n<\/ul>\n<p>Next, the second service named \u201cWeb\u201d is built from my custom repository and especially from my custom IIS image which contains a custom website. Then we use an environment variable which defines where the database is, and how to connect to it. Finally, port 5000 is mapped to the exposed port 5000 in the container. The two services are added to an existing network, named <strong>nat<\/strong>.<\/p>\n<p>Docker Compose is a particularly good way of managing multi-containers that contain databases and web frontends.<\/p>\n<h2>Image2Docker<\/h2>\n<p>It is difficult to migrate apps out of Virtual Machines, especially distributed apps with multiple components. <strong>Image2Docker<\/strong> may be the simplest way of getting your older applications working on newer operating systems.<\/p>\n<h3>What is Image2Docker?<\/h3>\n<p><strong>Image2Docker <\/strong>is a PowerShell module that ports existing Windows application workloads from virtual machines to Docker images. It supports multiple application types, but the initial focus is on IIS. You can use <strong>Image2Docker<\/strong> to extract ASP.NET websites from a VM, so you can then run them in a Docker container with no application changes. You will need Windows Server 2016 or Windows 10 in order to use <strong>Image2Docker<\/strong>.<\/p>\n<h3>How does it work?<\/h3>\n<p><strong>Image2Docker<\/strong> first inspects the artifacts in a Windows Server 2003, 2008, 2012 or 2016 VM image &#8211; in WIM, VHD or VHDX format. It then extracts either an entire VM or specific artifacts from a VHD file. Next, it will generate a Dockerfile which you can build into a Docker image. This PowerShell module requires PowerShell 5.0, or later.<\/p>\n<p>I will now describe the steps that are needed to extract IIS artifacts. In the screenshot below, I deployed a Windows Server 2016 Virtual Machine with the IIS role installed named \u201cIIS01\u201d. This VM has two IIS websites:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"821\" height=\"249\" class=\"wp-image-70947\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2017\/05\/word-image.png\" \/><\/p>\n<p>First, install the <strong>Image2Docker<\/strong> PowerShell module on your container host:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; Install-Module Image2Docker\r\n  Untrusted repository\r\n  You are installing the modules from an untrusted repository. If you trust this repository, change its\r\n  InstallationPolicy value by running the Set-PSRepository cmdlet. Are you sure you want to install the modules from\r\n  'PSGallery'?\r\n  [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is \"N\"): Y<\/pre>\n<p>Next, you can use the <strong>ConvertTo-DockerFile<\/strong> cmdlet. This cmdlet will scan your source image (e.g. VHDX or WIM file) to determine the artifact. <strong>Image2Docker<\/strong> currently supports discovery of the following artifacts:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; Get-WindowsArtifact\r\n  AddRemovePrograms\r\n  AllWindowsFeatures\r\n  Apache\r\n  DHCPServer\r\n  DNSServer\r\n  IIS\r\n  MSMQ\r\n  SQLServer<\/pre>\n<p>To scan an image, you just need to call the <strong>ConvertTo-Dockerfile<\/strong> cmdlet and specify the <strong>-ImagePath <\/strong>parameter which contains the VHDX file. The output folder will contain the generated dockerfile. Before scanning your image, you must power-off the virtual machine.<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; Import-Module Image2Docker\r\n  PS &gt; ConvertTo-Dockerfile -ImagePath \"C:\\Hyper-V\\IIS01\\Virtual Hard Disks\\IISV01.vhdx\" -OutputPath \"C:\\Containers\" -Artifact IIS -Verbose\r\n  VERBOSE: Reading image file: C:\\Hyper-V\\IIS01\\Virtual Hard Disks\\IIS01.vhdx\r\n  VERBOSE: Image file appears to be a valid WIM or VHDX file.\r\n  VERBOSE: Image file C:\\Hyper-V\\IIS01\\Virtual Hard Disks\\IIS01.vhdx contains 1 images\r\n  VERBOSE: This image appears to be a valid Virtual Hard Drive (VHDX) file.\r\n  VERBOSE: Image type is: VHDX\r\n  VERBOSE: User didn't specify a mount path. Using:\r\n  C:\\Users\\Nicolas\\AppData\\Local\\Temp\\94decd22-a9aa-45d7-9402-a309c2fa39b0-mount\r\n  VERBOSE: Finished mounting image C:\\Hyper-V\\IIS01\\Virtual Hard Disks\\IIS01.vhdx at mount point\r\n  C:\\Users\\Nicolas\\AppData\\Local\\Temp\\94decd22-a9aa-45d7-9402-a309c2fa39b0-mount\r\n  VERBOSE: Finished mounting image to: C:\\Users\\Nicolas\\AppData\\Local\\Temp\\94decd22-a9aa-45d7-9402-a309c2fa39b0-mount\r\n  VERBOSE: Starting conversion process\r\n  VERBOSE: Started discovering IIS artifact\r\n  VERBOSE: Checking IIS ApplicationHost config for Windows Version: 10.0\r\n  VERBOSE: Target Image Version 10.0.14393.0\r\n  VERBOSE: IIS service is present on the system\r\n  VERBOSE: ASP.NET is NOT present on the system\r\n  VERBOSE: .NET 3.5 is NOT present on the system\r\n  VERBOSE: Finished discovering IIS artifact\r\n  VERBOSE: Generating Dockerfile based on discovered artifacts in\r\n  :C:\\Users\\Nicolas\\AppData\\Local\\Temp\\94decd22-a9aa-45d7-9402-a309c2fa39b0-mount\r\n  VERBOSE: Generating result for IIS component\r\n  VERBOSE: Copying IIS configuration files\r\n  VERBOSE: Writing instruction to create site Default Web Site\r\n  VERBOSE: Processing source directory: C:\\inetpub\\wwwroot\r\n  VERBOSE: Writing instruction to expose port for site Default Web Site\r\n  VERBOSE: Writing instruction to create site GET-CMD\r\n  VERBOSE: Processing source directory: C:\\GET-CMD\r\n  VERBOSE: Writing instruction to expose port for site GET-CMD\r\n  VERBOSE: Finished generating the Dockerfile\r\n  VERBOSE: Finished dismounting the Windows image from\r\n  C:\\Users\\Nicolas\\AppData\\Local\\Temp\\94decd22-a9aa-45d7-9402-a309c2fa39b0-mount<\/pre>\n<p>You can also extract a single website from an IIS virtual machine using the <strong>\u2013ArtifactParam<\/strong> parameter followed by the IIS website name:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; ConvertTo-Dockerfile -ImagePath \"C:\\Hyper-V\\IIS01\\Virtual Hard Disks\\IIS01.vhdx\" -OutputPath \"C:\\Containers\" -Artifact IIS -ArtifactParam \"GET-CMD\" \u2013Verbose<\/pre>\n<p>Now, you can go to the output folder, and you\u2019ll notice that a <strong>Dockerfile<\/strong> has been created.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1232\" height=\"811\" class=\"wp-image-70948\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2017\/05\/word-image-1.png\" \/><\/p>\n<p>If you only have a VMDK file, you can use the Microsoft Virtual Machine Converter Tool to convert VMDK images to VHD images.<\/p>\n<h2>Hyper-V Isolation<\/h2>\n<p>When you are running on Windows 10, you can only work with Hyper-V containers, but when you are running on Windows Server 2016, you can choose between Hyper-V and Windows Server containers. By default, when you use the\u00a0<strong>docker run<\/strong>\u00a0command, it will start a Windows Server container, but you can specify that you want to run a Hyper-V container by using the &#8212;<strong>isolation=hyperv <\/strong>parameter.<\/p>\n<p>Before running a Hyper-V container, you must install the Hyper-V role on your container host:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; Install-WindowsFeature -Name Hyper-V<\/pre>\n<p>When running the previous command, you will probably get the following error message if your container host is a virtual machine:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">Hyper-V cannot be installed: The processor does not have required virtualization capabilities<\/pre>\n<p>It means that Nested Virtualization is not enabled on the system. Nested Virtualization allows you to run a Hypervisor inside a Virtual Machine running on a Hypervisor. To enable Nested Virtualization in Hyper-V, you must first shutdown the Container Host Virtual Machine and then run the following PowerShell command:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; Set-VMProcessor -VMName \"VMName\" -ExposeVirtualizationExtensions $true<\/pre>\n<p>This feature is currently Intel-only: Intel VT-x is required. Once the Hyper-V role is installed, you can run your first Hyper-V container using the following script on your container host:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; docker run --rm -it --name MyNanoHYPV --isolation=hyperv microsoft\/nanoserver:latest<\/pre>\n<p>In this example, I deploy a Hyper-V container named \u201c<strong>MyNanoHYPV<\/strong>\u201d with the &#8212;<strong>isolation=hyperv <\/strong>parameter which is based on the Nano Server image from Microsoft.<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">Microsoft Windows [Version 10.0.14393]\r\n  (c) 2016 Microsoft Corporation. All rights reserved.\r\n  C:\\&gt;ipconfig\r\n  Windows IP Configuration\r\n  Ethernet adapter Ethernet:\r\n     Connection-specific DNS Suffix  . :\r\n     Link-local IPv6 Address . . . . . : fe80::2890:b928:39d6:c8a%4\r\n     IPv4 Address. . . . . . . . . . . : 172.21.158.25\r\n     Subnet Mask . . . . . . . . . . . : 255.255.240.0\r\n     Default Gateway . . . . . . . . . : 172.21.144.1\r\n  C:\\&gt;hostname\r\n  b97558fd884a<\/pre>\n<p>As you can see, the Hyper-V container boots in seconds; much faster than a virtual machine. To confirm that you are running a Hyper-V container, you can run a very simple check. Open the PowerShell console, and use the <strong>Get-Process<\/strong> cmdlet to list the process named \u201cVMWP\u201d which corresponds to the Hyper-V process:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; Get-Process -Name vmwp\r\n  Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName\r\n  -------  ------    -----      -----     ------     --  -- -----------\r\n     3386      18    38796      20048       4.39   3632   0 vmwp\r\n      235      14    35888      16128       2.63   5224   0 vmwp<\/pre>\n<p>We can see from this result that there are two processes running on the container host. Now, just type the \u201cexit\u201d command inside your Hyper-V container and rerun the previous command:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS C:\\Users\\Administrator&gt; Get-Process -Name vmwp\r\n  Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName\r\n  -------  ------    -----      -----     ------     --  -- -----------\r\n      235      14    35888      16128       2.63   5224   0 vmwp\r\n  PS C:\\Users\\Administrator&gt;<\/pre>\n<p>There is only one process. Why? Hyper-V container is like a virtual machine in some ways but different in others. When you run your Hyper-V container, Windows will create what seems to be a VM but it\u2019s not actually a virtual machine, it\u2019s a Hyper-V container! Of course, you can\u2019t see this VM in the Hyper-V console manager. The only thing that you can see is the process. The use of a Hyper-V container provides a kernel-mode isolation instead of user-mode isolation.<\/p>\n<p>Ok, now let\u2019s examine another example to understand the difference between Windows Server containers and Hyper-V containers. Run the following command:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; docker run -d --name NanoWithoutHYPV microsoft\/nanoserver:latest ping localhost \u2013t<\/pre>\n<p>This command deploys a Windows Server container based on the Nano Server image. We run a permanent ping inside the container. Now, use the <strong>Docker Top<\/strong> command to display the list of the process running inside this container:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; docker top NanoWithoutHYPV\r\n  Name                PID                 CPU                 Private Working Set\r\n  smss.exe            5384                00:00:00.140        208.9kB\r\n  csrss.exe           1920                00:00:00.437        356.4kB\r\n  wininit.exe         3320                00:00:00.031        651.3kB\r\n  services.exe        5780                00:00:00.203        1.487MB\r\n  lsass.exe           5752                00:00:00.234        1.95MB\r\n  svchost.exe         2800                00:00:00.062        1.241MB\r\n  svchost.exe         2856                00:00:00.031        1.323MB\r\n  svchost.exe         5852                00:00:00.125        2.179MB\r\n  svchost.exe         5800                00:00:00.000        1.434MB\r\n  svchost.exe         4544                00:00:00.140        3.752MB\r\n  svchost.exe         4412                00:00:00.156        1.942MB\r\n  svchost.exe         4844                00:00:00.062        1.47MB\r\n  svchost.exe         5876                00:00:00.328        4.039MB\r\n  svchost.exe         3016                00:00:00.109        2.327MB\r\n  CExecSvc.exe        3136                00:00:00.000        737.3kB\r\n  PING.EXE            3912                00:00:00.000        536.6kB\r\n  PS C:\\Users\\Administrator&gt; get-process *PING*\r\n  Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName\r\n  -------  ------    -----      -----     ------     --  -- -----------\r\n       62       5      720       3480       0.00   3912   3 PING<\/pre>\n<p>We can see that the last process, called \u201cPING.EXE\u201d, corresponds to the ping command inside the container. But, running the <strong>Get-Process<\/strong> cmdlet on the container host, notice that the same process exists with the same PID! It means that our Windows Server container uses the Kernel resources from my container host. OK, now stop this container with the <strong>Docker Stop<\/strong> command and do the same thing by appending the &#8212;<strong>isolation=hyperv <\/strong>parameter:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; docker run -d --name NanoWithHYPV --isolation=hyperv microsoft\/nanoserver:latest ping localhost \u2013t<\/pre>\n<p>And run the <strong>Docker Top<\/strong> command:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; docker top NanoWithHYPV\r\n  Name                PID                 CPU                 Private Working Set\r\n  smss.exe            828                 00:00:00.312        213kB\r\n  csrss.exe           848                 00:00:00.703        356.4kB\r\n  wininit.exe         888                 00:00:00.140        618.5kB\r\n  services.exe        900                 00:00:00.453        1.384MB\r\n  lsass.exe           916                 00:00:00.406        1.933MB\r\n  svchost.exe         1008                00:00:00.109        1.237MB\r\n  svchost.exe         216                 00:00:00.125        1.245MB\r\n  svchost.exe         444                 00:00:00.187        1.184MB\r\n  svchost.exe         724                 00:00:00.062        1.073MB\r\n  svchost.exe         984                 00:00:00.375        3.895MB\r\n  svchost.exe         712                 00:00:00.265        1.88MB\r\n  svchost.exe         1028                00:00:00.078        1.528MB\r\n  svchost.exe         1056                00:00:00.296        3.441MB\r\n  svchost.exe         1168                00:00:00.390        2.273MB\r\n  CExecSvc.exe        1188                00:00:00.031        737.3kB\r\n  PING.EXE            1396                00:00:00.046        532.5kB\r\n  PS C:\\Users\\Administrator&gt; get-process *PING*\r\n  get-process : Cannot find a process with the name \"ping\". Verify the process name and call the cmdlet again.\r\n  At line:1 char:1\r\n  + get-process -Name ping\r\n  + ~~~~~~~~~~~~~~~~~~~~~~\r\n      + CategoryInfo          : ObjectNotFound: (ping:String) [Get-Process], ProcessCommandException\r\n      + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand<\/pre>\n<p>PowerShell error! No PING process exists on the container host. It means that due to the Hyper-V isolation and especially the kernel mode isolation, the kernel resources are not shared between the container host and the Hyper-V containers.<\/p>\n<p>For those of you who are getting the following error:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS C:\\Users\\Administrator&gt; docker run --rm -it --name nanohyperv --isolation=hyperv microsoft\/nanoserver:latest\r\n  C:\\Program Files\\Docker\\docker.exe: Error response from daemon: container 2f83bfc2bbbbed5a0425a0219a7a747c971a1eeb032ce11b76149f17b397f17b en\r\n  countered an error during CreateContainer: failure in a Windows system call: No hypervisor is present on this system. (0xc0351000) <\/pre>\n<p>It means that Hyper-V role is not installed on your system, so you can\u2019t run Hyper-V containers. If you have some trouble using a specific container, you can use the <strong>Docker Logs<\/strong> command to troubleshoot. The <strong>Docker logs<\/strong> command shows information logged by a running container. The information that is logged and the format of the log depends almost entirely on the container\u2019s endpoint command:<\/p>\n<pre class=\"theme:powershell-output lang:ps decode:true\">PS &gt; docker logs NanoWithHYPV<\/pre>\n<h2>Conclusion<\/h2>\n<p>In this part, we discussed about Docker Compose. To build a multi-container application, Docker has developed <strong>Docker-Compose<\/strong> which makes it easier to configure and run applications made up of multiple containers. <strong>Docker-Compose<\/strong> starts all the required containers with a single command.<\/p>\n<p>Next, we used <strong>Image2Docker<\/strong> that allows you to take a virtualized web server in a Hyper-V VM and extract a Docker image for each website in the Virtual Machine. It looks at the disk for known artifacts, compiles a list of all the artifacts installed on the VM and generates a Dockerfile to package the artifacts.<\/p>\n<p>Finally, we described the Hyper-V container concept. Hyper-V containers provide a kernel mode isolation instead of user mode isolation. Hyper-V containers use an automatically generated Hyper-V VM where the container instances run.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So far, in this series, Nicolas has shown how to  get simple container instances up and running with just some basic background information. Now we need to understand the differences between Linux  containers, Windows Server containers and Hyper-V containers.  We can then define, create and run multi-container Docker applications, and port existing Windows Container VMs to Docker.&hellip;<\/p>\n","protected":false},"author":158223,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143513],"tags":[95506,48325],"coauthors":[6804],"class_list":["post-70946","post","type-post","status-publish","format-standard","hentry","category-containers-and-virtualization","tag-automate","tag-windows_containers"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/70946","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/158223"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=70946"}],"version-history":[{"count":9,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/70946\/revisions"}],"predecessor-version":[{"id":90089,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/70946\/revisions\/90089"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=70946"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=70946"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=70946"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=70946"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}