• Trying Docker for Windows and Linux

    I’ve been spending a bit of time trying out Docker over the past few days, with the goal of making builds more reliable and repeatable.

    Docker Desktop for Windows has the ability to run in Windows mode and Linux mode. Usually that means you can only run containers of one OS at at a time.

    However, if you run configure Docker to enable ‘Experimental’ mode, then you can actually run both platforms simultaneously.

    Interestingly, when you’re in this mode and you set ‘Windows’ as the default container platform, you don’t see an extra virtual machine listed in HyperV.

    Here’s Docker running with Linux containers: Hyper-V Manager showing Docker virtual machine

    And here’s Docker with Windows containers: Hyper-V Manager showing Docker machine not running Notice the VM may be there, but it is not running, even when I’m actually building a Linux container when that screenshot was taken.

    So with experimental mode on, how can Docker be also running Linux containers in Windows mode?

    Currently it uses something called LCOW - Linux Containers on Windows.

    I know Docker also has preview support for WSL2. I think the plan is that once that ships (presumably with Windows 10 20H1) then Docker will be able to leverage that for Linux execution.

    So in theory, if you need to spin up Linux and Windows containers, then this is the technology that will make that happen.

    There’s still a few rough edges - probably why it’s all behind ‘preview’ or ‘experimental’ flags.

    I hit one issue where trying to spin up a Node Linux container which has a step to run yarn resulted in some weird internal error:

    Step 14/22 : RUN yarn
    ---> Running in eb14f055a9aa
    container eb14f055a9aaa23db5f35493feec9009b775c6688e3c488b26c6880517bdd9f1 encountered an error during CreateProcess: failure in a Windows system call: Unspecified error (0x80004005)
    [Event Detail: failed to run runc create/exec call for container eb14f055a9aaa23db5f35493feec9009b775c6688e3c488b26c6880517bdd9f1: exit status 1 Stack Trace:
    github.com/Microsoft/opengcs/service/gcs/runtime/runc.(*container).startProcess
    /go/src/github.com/Microsoft/opengcs/service/gcs/runtime/runc/runc.go:580
    github.com/Microsoft/opengcs/service/gcs/runtime/runc.(*runcRuntime).runCreateCommand
    /go/src/github.com/Microsoft/opengcs/service/gcs/runtime/runc/runc.go:471
    github.com/Microsoft/opengcs/service/gcs/runtime/runc.(*runcRuntime).CreateContainer
    

    No idea what’s going on there other than maybe I’ve managed to hit some issue where some API isn’t implemented?

    It’s strange, as a different container (based on a different Linux distribution) didn’t have that problem.

    So it has potential, but it’s obviously a work in progress.

  • PowerShell ErrorAction

    Many PowerShell cmdlets have a common parameter ErrorAction, that can be set to one of Continue, Ignore, Inquire, SilentlyContinue, Stop or Suspend

    I’ve never really understood what the different between Ignore and SilentlyContinue was until today. I’d ran the following code:

    Get-Service 'NonExistantService' -ErrorAction SilentlyContinue
    

    and then happened to look in the $Error automatic variable and noticed the following:

    Get-Service : Cannot find any service with service name 'NonExistantService'.
    At line:1 char:1
    + Get-Service 'NonExistantService' -ErrorAction SilentlyContinue
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (NonExistantService:String) [Get-Service], ServiceCommandException
    + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand
    
    

    Whereas the following does not get added to $Error

    Get-Service 'NonExistantService' -ErrorAction Ignore
    

    That’s the difference! Ignore was added in PowerShell 3.0, and quoting the documentation page “Unlike SilentlyContinue, Ignore doesn’t add the error message to the $Error automatic variable.”

    So Ignore is probably a better option for most cases where ignoring the error is fine.

  • PowerShell require minimum version

    I have some PowerShell scripts that had a dependency on using at least PowerShell 4.0. I’d added #Require -Version 4.0 to the top of the script, but was surprised the other day when this script ran on a machine with only PowerShell 2.0 and it didn’t complain. Well it did complain about other things (related to trying to run on the older version), but it didn’t throw up an error about the wrong version immediately like I’d expected.

    Double-checking the documentation for About_Requires, I realised I’d made a minor (but significant) typo.

    #Requires -Version 4.0
    

    Yeah - a missing ‘s’. Without that, it’s just a commented line rather than a directive, so it was having no effect.

    As it happens, this script also needs to be run as an Administrator, and whilst browsing same the documentation discovered there’s also a Requires prerequisite for that too!

    #Requires -RunAsAdministrator
    

    Trying to run the script non-elevated results in the following error:

    .\Script.ps1 : The script 'Script.ps1' cannot be run because it contains a "#requires" statement for running as Administrator. The current PowerShell session is not running as Administrator. Start PowerShell by using the Run as Administrator option, and then try running the script again.