Skip to content

Initialize a Windows container with an entrypoint script

A popular Docker article describes a pattern to initialize stateful container data at runtime. The example uses a Shell script to run the initialization and then pass control to the container’s main command. We can use the same pattern to initialize a Docker Windows container.

My example

In keeping with the original example, we’ll initialize data into a database container. This pattern will work for any container though. As we’re using Windows containers, I’ll use the SQL Server (Express) image.

As a side note, it’s not as easy as it should be to initialize a SQL Server container. I’ve followed Tometchy’s excellent Initialize MS SQL in Docker container – create database at startup article. My changes are:

  1. I’m using Windows containers
  2. To demonstrate a point, I want to initialize the database and then run the regular start command

How to initialize a Windows container

First, create a Powershell script that runs the initialization code and then passes control back to a long running process:

$cmd = $args

######################
# Start initialization
######################
Write-Host "Starting SQL Server for initialization"
start-service MSSQL`$SQLEXPRESS

if($sa_password -ne "_")
{
    Write-Verbose "Changing SA login credentials"
    $sqlcmd = "ALTER LOGIN sa with password='$($env:sa_password)';ALTER LOGIN sa ENABLE;"
    & sqlcmd -Q $sqlcmd
}

Write-Host "Running initialization script"
sqlcmd -S localhost -U sa -P $env:sa_password -d master -i c:\init.d\create-database.sql

Write-Host "SQL Server initialized. Stopping..."
stop-service MSSQL`$SQLEXPRESS
####################
# End initialization
####################


Write-Host "Running command: $($cmd)"
Invoke-Expression -Command "$cmd"
# or...
# cmd.exe /c "$cmd"

What’s happening here is:

  • Line 1: Capture arguments to this script’s invocation. We expect this to be the command we want to run after initialization
  • Line 3-23: Initialization code. In this case we start SQL Server, set an sa password so we can login to it, run the create-database.sql and then stop SQL Server. You can populate this section with any initialization code you need.
  • Line 27: Invoke the script argument as a Powershell command. I’ve shown the equivalent for cmd.exe in line 29.

To execute this code on container startup, simply set the script as the ENTRYPOINT and the original command as the CMD. Here’s what it looks like as Docker Compose:

version: '3'
services:
  sqlserver:
    image: microsoft/mssql-server-windows-express:latest
    environment:
      ACCEPT_EULA: Y
      sa_password: "C;2nXv#w"
    ports:
    - "1433:1433"
    volumes:
    - ./init.d:C:/init.d
    entrypoint: "powershell -File C:\\\\init.d\\\\run-initialization.ps1"
    command: ".\\\\start -sa_password $$env:sa_password -ACCEPT_EULA $$env:ACCEPT_EULA -attach_dbs \\\"$$env:attach_dbs\\\" -Verbose"

Note that the command here is the default CMD of the microsoft/mssql-server-windows-express image. Just watch the escaping of $ and \ characters here.

When this container starts, its command is the ENTRYPOINT with the CMD as command line arguments to it. That is:

powershell -File C:\init.d\run-initialization.ps1 .\start -sa_password $env:sa_password -ACCEPT_EULA $env:ACCEPT_EULA -attach_dbs \"$env:attach_dbs\" -Verbose

What actually happens is run-initialization.ps1 does the database initialization work and then invokes everything afterwards as a new Powershell command. That is, it starts the database.

Try it!

Pull the example code from GitHub. I ran it on my Windows 10 (1903) laptop. It should also work in Windows Server 2019.

Published inDockerHow To

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *