HOW WE GOT THERE
The initial learning curve was steep, with the birth of PowerShell and the need to change my habit of relying on GUIs in order to get things really automated. I was pretty prone to dive into scripting since in the long term it meant less work for me, more for my servers.
Then it settled for a while. Learning Hyper-V was not difficult since I already had previous experience with VMware. And the cmdlets for managing those hypervisors are more or less the same (the consistency of Windows PowerShell is one of its primary assets).
During this period behind the curtains things were happening: Microsoft was trying to catch up with VMware and position their hypervisor in the ‘Leaders’ box of the Gartner quadrant. And at the same time Microsoft was building NanoServer, the thinnest OS they could provide on the road to containerization.
To make things even more complex to follow, Microsoft has also gone open source on some projects, like .NET Core or PowerShell, and is contributing to the Docker open source project. Whilst this has increased the quality of the product, thanks to the effort of hundreds of expert contributors, the risk for bugs to make it into the code has also increased. This is a common risk in the open source ecosystem. The most significative example? Just last week version 4.8 of the Linux kernel (which is marked as stable) has been released with the dangerous addition of a BUG_ON line which kills the kernel.
So, let’s now have a look at Microsoft Containers, how to use them and I will walk you through some of the technical problem you could encounter with this product. Since there are so many different instructions around, and releases are succeding pretty fast, it is difficult to know which one to use, so I’ll try to be as simple as possible.
The first step is go and get a Windows 2016 image. Once you have it, the upgrade process will be pretty easy. Personally I upgraded most of the systems in my labs, which were running Windows 2012 R2 or some Windows 2016 Technical Preview.
The process was painless, apart for a Hyper-V cluster that suffered a loss of its LBFO teaming and virtual switches caused by the Unaware Update burden I put on it…
INTRODUCING THE THING
INTRODUCING THE THING
Containers are all about operating system virtualization, so they are a different concept from virtual machines, which are all about hardware virtualization. Since containers work at a different level, they result significantly faster to setup and deploy. And you can pack a lot more containers than virtual machines on a single host.
Now Windows 2016 offers two Container models: Windows Containers and Hyper-V Containers. They differ in the fact that the isolation level is not the same: while the former shares the kernel with the host, the latter runs in a lightweight virtual machine (called partition) with a separated kernel.
Concerning Windows Containers, the process isolation mechanism is done by the Docker daemon, or service if you like, which allow them to reuse the host kernel through a sandbox. For this to happen, containerization primitives have been added to the Windows 2016 kernel (and to Windows 10 Anniversary Update), which is the reason why you won’t be able to run container on Windows 2012 R2. There is no tiny Linux virtual machine involved in this process, like you could read somewhere.
![]() |
Source: https://blog.docker.com/2015/08/tp-docker-engine-windows-server-2016/ |
docker run --isolation=hyperv microsoft/nanoserver
There is for sure a greater overhead when you setup a Hyper-V Container, and startup times are a bit longer, but each of these two types of Containers has its use.
Ok, let's make a step back and see all this from the beginning.
Ok, let's make a step back and see all this from the beginning.
The first step when setting up Containers on a vanilla Windows 2016 is to:
Install-WindowsFeature Containers
Success Restart Needed Exit Code Feature Result
------- -------------- --------- --------------
True Yes SuccessRest... {Containers}
WARNING: You must restart this server to finish the installation process.
Restart-Computer
This installs 10 new cmdlets:
(Get-Command).where{$_.Source -match 'Containers'} CommandType Name Version Source ----------- ---- ------- ------ Cmdlet Add-ContainerNetworkAdapter 1.0.0.0 Containers Cmdlet Add-ContainerNetworkAdapterStaticMapping 1.0.0.0 Containers Cmdlet Get-ContainerNetwork 1.0.0.0 Containers Cmdlet Get-ContainerNetworkAdapter 1.0.0.0 Containers Cmdlet Get-ContainerNetworkAdapterStaticMapping 1.0.0.0 Containers Cmdlet New-ContainerNetwork 1.0.0.0 Containers Cmdlet Remove-ContainerNetwork 1.0.0.0 Containers Cmdlet Remove-ContainerNetworkAdapter 1.0.0.0 Containers Cmdlet Remove-ContainerNetworkAdapterStaticMapping 1.0.0.0 Containers Cmdlet Set-ContainerNetworkAdapter 1.0.0.0 Containers
PROXY PROBLEMS
At this point the problems started for me. I spent a lot of time trying to understand the right procedure to follow (most of the tests I did were on Windows 2016 Evaluation build 14393.0).
At this point the problems started for me. I spent a lot of time trying to understand the right procedure to follow (most of the tests I did were on Windows 2016 Evaluation build 14393.0).
Being in an corporate environment, I had a hard time making the following to work:
Install-PackageProvider ContainerImage
… and eventually failed:
WARNING: MSG:UnableToDownload «https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409» «» WARNING: Unable to download the list of available providers. Check your internet connection. WARNING: Unable to download from URI 'https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409' to ''. Install-PackageProvider : No match was found for the specified search criteria for the provider 'ContainerImage'. The package provider requires 'PackageManagement' and 'Provider' tags. Please check if the specified package has the tags. At line:1 char:1 + Install-PackageProvider ContainerImage + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (Microsoft.Power...PackageProvider:InstallPackageProvider) [Install-PackageProvider], Exception + FullyQualifiedErrorId : NoMatchFoundForProvider,Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackageProvider
I tried a whole bunch of workarounds to make this cmdlet to work through a corporate proxy, and download the Nuget package provider. I went from the simple solution, which consists of using Netsh to configure the WinHTTP config after having defined a proxy in IE:
netsh winhttp import proxy source=ie
to using the Configure-Proxy function by fellow MVP Jeff Wouters:
function Configure-Proxy ($Proxy, $Port) { # Function that actually does the configuring of the proxy settings. Set-ItemProperty “HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings” -Name ProxyEnable -Value 1 Set-ItemProperty “HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings” -Name ProxyServer -Value $Proxy”:”$Port Set-ItemProperty “HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings” -Name ProxyOverride -Value “” } Configure-Proxy "10.x.x.x" 8080
…to using Install-Package provider with the –Proxy and –ProxyCredential parameters defined :
Install-PackageProvider ContainerImage -Force -proxy http://10.x.x.x:8080 -ProxyCredential $cred –Verbose
Nothing worked:
$Username = "proxyuser" $Password = ConvertTo-SecureString "proxyuserpw" -AsPlainText -Force $Cred = New-Object System.Management.Automation.PSCredential $Username, $Password Install-PackageProvider ContainerImage -Force -proxy http://10.x.x.x:8080 -ProxyCredential $cred -Verbose VERBOSE: Using the provider 'Bootstrap' for searching packages. VERBOSE: Finding the package 'Bootstrap::FindPackage' 'ContainerImage','','','''. WARNING: Unable to download from URI 'https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409' to ''. VERBOSE: Cannot download link 'https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409', retrying for '2' more times. VERBOSE: Cannot download link 'https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409', retrying for '1' more times. VERBOSE: Cannot download link 'https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409', retrying for '0' more times. WARNING: Unable to download the list of available providers. Check your internet connection. VERBOSE: Using the provider 'PowerShellGet' for searching packages. VERBOSE: The -Repository parameter was not specified. PowerShellGet will use all of the registered repositories. Install-PackageProvider : No match was found for the specified search criteria for the provider 'ContainerImage'. The package provider requires 'PackageManagement' and 'Provider' tags. Please check if the specified package has the tags. At line:1 char:1 + Install-PackageProvider ContainerImage -Force -proxy http://10.X.x. ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (Microsoft.Power...PackageProvider:InstallPackageProvider) [Install-PackageProvider], Exception + FullyQualifiedErrorId : NoMatchFoundForProvider,Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackageProvider
I even decided to deliberately ignore the SSL errors using the pieces of code found at Mono project:
add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
but the outcome stayed the same: failure.
To make a long story short, I finished manually downloading the module (version 0.6.4.0) on a computer with direct Internet access, and imported it on my corporate server in the right folder:
To me, it really felt like this cmdlet was never intended to use in enterprise…
Once I went through these tasks, I discovered that this ContainerImage module only had three cmdlets:
Get-Command -Module ContainerImage CommandType Name Version Source ----------- ---- ------- ------ Function Find-ContainerImage 0.6.4.0 ContainerImage Function Install-ContainerImage 0.6.4.0 ContainerImage Function Save-ContainerImage 0.6.4.0 ContainerImage
Since these cmdlets didn’t work either because of the corporate firewall, I ended up retrieving the Wim files straight from their web source and copying them on my Windows 2016 test bed.
The download links can be found here.
The content of this file, which basically containes the direct download links, is:
[ { "Name": "NanoServer", "Version": "10.0.14300.1016", "Description": "Container OS Image of Windows Server 2016 Technical Preview 5 : Nano Server Installation", "SasToken": "https://az887518.vo.msecnd.net/pshctcontainer/NanoServer-10-0-14300-1016.wim" }, { "Name": "WindowsServerCore", "Version": "10.0.14300.1000", "Description": "Container OS Image of Windows Server 2016 Technical Preview 5 : Windows Server Core Installation", "SasToken": "https://az887518.vo.msecnd.net/pshctcontainer/WindowsServerCore-10-0-14300-1000.wim" } ]
I populated a ContainerImages folder where I put the image files:
ls Directory: C:\ContainerImages Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 12/10/2016 13:45 178574823 NanoServer-10-0-14300-1016.wim -a---- 12/10/2016 14:37 2874089226 WindowsServerCore-10-0-14300-1000.wim
Then tried to install them offline:
Install-ContainerImage -.\NanoServer-10-0-14300-1016.wim WARNING: MSG:UnableToDownload «https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409» «» WARNING: Unable to download the list of available providers. Check your internet connection. PackageManagement\Save-Package : No match was found for the specified search criteria and package name '-.\NanoServer-10-0-14300-1016.wim'. Try Get-PackageSource to see all available registered package sources. At C:\Program Files\WindowsPowerShell\Modules\ContainerImage\0.6.4.0\ContainerImage.psm1:492 char:23 + ... $downloadOutput = PackageManagement\Save-Package @PSBoundParameters + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (Microsoft.Power...ets.SavePackage:SavePackage) [Save-Package], Exception + FullyQualifiedErrorId : NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManagement.Cmdlets.SavePackage The property 'Name' cannot be found on this object. Verify that the property exists. At C:\Program Files\WindowsPowerShell\Modules\ContainerImage\0.6.4.0\ContainerImage.psm1:494 char:5 + $Destination = GenerateFullPath -Location $Location ` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], PropertyNotFoundException + FullyQualifiedErrorId : PropertyNotFoundStrict Install-ContainerOSImage : The term 'Install-ContainerOSImage' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At C:\Program Files\WindowsPowerShell\Modules\ContainerImage\0.6.4.0\ContainerImage.psm1:502 char:5 + Install-ContainerOSImage -WimPath $Destination ` + ~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (Install-ContainerOSImage:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException Remove-Item : Cannot bind argument to parameter 'Path' because it is null. At C:\Program Files\WindowsPowerShell\Modules\ContainerImage\0.6.4.0\ContainerImage.psm1:512 char:8 + rm $Destination + ~~~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [Remove-Item], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.RemoveItemCommand
The key error here is :
The term 'Install-ContainerOSImage' is not recognized as the name of a cmdlet.
Something had changed from the different procedures I had tested in the past, and all lead me to think that the container cmdlets had been deprecated.
MOVING TO DOCKER
So, after reviewing the docs, I saw that Docker is the key required element in the process, as you can read on this article by Neil Peterson:
Hello a nice tutorial, thank you I'll certainly use it.
ReplyDeleteI do feel it's worth mentioning that your logic around bugs in open source software needs a little more reinforcing if you want to hold that opinion. Just because the bug discovery and replication process is in the open, does not make it logically any less or more prone to bugs than proprietary software -- the benefit is you are more aware of them.
Thanks again.