Swift on Windows — Part 2 (Docker Container)

Shalini
VMware 360
Published in
6 min readJan 20, 2023

This tutorial will help you run Swift inside of Windows Docker Container.

Docker on Windows

One of the challenges when setting up Swift on Windows native is the requirement to install underlying dependencies on all machines with agents installed to run CI/CD.

Docker provides an easier solution to this problem and handles the entire installation in a single click.

Prerequisite

  1. Install Docker Desktop

Download Docker Desktop on a Windows machine by downloading its executable from Docker’s official page. Follow below steps to install it.

  1. Double-click Docker Desktop Installer.exe to run the installer.
  2. When prompted, ensure the Use WSL 2 instead of Hyper-V option on the Configuration page is selected or not depending on your choice of backend.
  3. Follow the instructions on the installation wizard to authorize the installer and proceed with the installation.
  4. When the installation is successful, click Close to complete the installation process.
  5. If your admin account is different from your user account, you must add the user to the docker-users group. Run Computer Management as an administrator and navigate to Local Users and Groups > Groups > docker-users. Right-click to add the user to the group. Log out and log back in for the changes to take effect.

2. Start Docker Desktop

Docker Desktop does not start automatically after installation. To start Docker Desktop:

  1. Search for Docker, and select Docker Desktop in the search results.
Docker Desktop in Windows machine

2. Select Accept to continue. Docker Desktop starts after you accept the terms.

3. Switch Container — This is an important step

  1. Once Docker Desktop has been set up and started successfully, close it.
  2. Right click the Docker icon in the Windows tray, and select Switch to Windows containers.
Switching between Windows/Linux Container

3. To use the command line to switch between containers, then run

& $Env:ProgramFiles\Docker\Docker\DockerCli.exe -SwitchDaemon.

DockerFile

Once the above prerequisites have been met, you can run any Windows- based container on the machine. Swift image can be pulled directly from Docker Hub using following command:

docker pull swift

If you have a custom requirement such as cloning a git repository, which requires ssh-key setup, you need an image that configures ssh-key for a container. To do so, you can copy contents from below attached Dockerfile, paste it in a text file, name it as Dockerfile(case-sensitive)and add or remove steps based on your requirement before creating a container out of it.

# escape=`

FROM mcr.microsoft.com/windows/servercore:ltsc2022 AS windows

LABEL maintainer="Swift Infrastructure <swift-infrastructure@forums.swift.org>"
LABEL description="Docker Container for the Swift programming language"

ARG GIT=https://github.com/git-for-windows/git/releases/download/v2.35.1.windows.2/Git-2.35.1.2-64-bit.exe
ARG INSTALLER=https://download.swift.org/swift-5.7-release/windows10/swift-5.7-RELEASE/swift-5.7-RELEASE-windows10.exe
ARG PYTHON=https://www.python.org/ftp/python/3.10.4/python-3.10.4-amd64.exe

# restore the default Windows shell for correct batch processing
SHELL ["cmd", "/S", "/C"]

# Install Visual Studio Build Tools
RUN `
curl -SLo vs_buildtools.exe https://aka.ms/vs/17/release/vs_buildtools.exe `
&& (start /w vs_buildtools.exe --quiet --wait --norestart --nocache `
--add Microsoft.VisualStudio.Component.Windows11SDK.22000 `
--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
|| IF "%EXITCODE%"=="3010" EXIT 0) `
&& del /q vs_buildtools.exe

# Install Swift toolchain.
RUN `
curl -SLo installer.exe %INSTALLER% `
&& (start /w installer.exe -q) `
&& del /q installer.exe

# Install Git.
# See: git-[version]-[bit].exe /SAVEINF=git.inf and /?
RUN `
curl -SLo git.exe %GIT% `
&& (start /w git.exe /SP- /VERYSILENT /SUPPRESSMSGBOXES /NOCANCEL /NORESTART /CLOSEAPPLICATIONS /FORCECLOSEAPPLICATIONS /NOICONS /COMPONENTS="gitlfs" /EditorOption=VIM /PathOption=Cmd /SSHOption=OpenSSH /CURLOption=WinSSL /UseCredentialManager=Enabled /PerformanceTweaksFSCache=Enabled /EnableSymlinks=Enabled /EnableFSMonitor=Enabled ) `
&& del /q git.exe

# Create an user and configure GIT ssh-key
RUN powershell -Command `
net user /add ensemble; `
net localgroup Administrators ensemble /add;
USER ensemble
RUN powershell -Command `
mkdir C:\Users\ensemble\.ssh;
RUN powershell -Command `
mkdir C:\Users\ensemble\swift;

COPY .\id_ed25519 C:\Users\ensemble\.ssh\id_rsa

RUN powershell -Command `
# Make sure you're running as an Administrator `
Set-Service ssh-agent -StartupType Automatic; `
Start-Service ssh-agent; `
Get-Service ssh-agent;

RUN ssh-add C:\Users\ensemble\.ssh\id_rsa

# Install Python.
# See: https://docs.python.org/3.10/using/windows.html
# FIXME: it appears that `PYTHONHOME` and `PYTHONPATH` are unset
RUN `
curl -SLo python.exe %PYTHON% `
&& (start /w python.exe /quiet InstallAllUsers=1 AssociateFiles=0 PrependPath=1 Shortcuts=0 Include_doc=0 Include_debug=0 Include_dev=0 Include_exe=0 Include_launcher=0 InstallLauncherAllUsers=0 Include_lib=1 Include_pip=0 Include_symbols=0 Include_tcltk=0 Include_test=0 Include_tools=0 ) `
&& del /q python.exe

# Default to powershell
# FIXME: we need to grant ContainerUser the SeCreateSymbolicLinkPrivilege
# privilege so that it can create symbolic links.
# USER ContainerUser
CMD ["powershell.exe", "-nologo", "-ExecutionPolicy", "Bypass"]
Suggested versions of Visual Studio, Python and Git in above Dockerfile
have been refered from Swift Official Documentation(link attached below).
Please check correct version on Swift's official documentation
and update Dockerfile accordingly.

The docker image created from the above Dockerfile does following:

Pulls base image as for Windows OS

Downloads Git installer

Downloads Swift 5.7 installer

Downloads Python 3.10 installer

Sets terminal to Windows cmd

Installs Visual Studio and required tools

Installs Swift Toolchain from downloaded swift installer

Installs Git from downloaded git installer

Adds an user ensemble and add it to Administrator group

Configures SSH key to access our stash repositories by copying ssh key from local machine(where docker is running) to docker container

Starts ssh-agent on the container

Installs Python from downloaded pyhton installer

Sets terminal to PowerShell in container

Docker Image

To create an image out of the above Dockerfile :

  • Save it with name Dockerfile on the machine or agent where container has to be created
  • This docker file has a step that copies id_rsa from native machine to container. Before you build an image out of this Dockerfile, you need to copy id-rsa from machine’s .ssh folder to the folder where Dockerfile is saved.
  • Run following command to create a container from same path using PowerShell or cmd in admin mode where Dockerfile has been saved.

docker build -t <my_image_name> .

It takes some time when building the first time because it pulls all base images and the terminal (Powershell or cmd) looks like this:

Building Docker Image from Dockerfile

Docker Container

Once an image has been created using above DockerFile:

  • Click Run button corresponding to Docker image from Docker Desktop
Run Docker Image
Container Properties

Once the container is up and running, you can run swift --version command inside container to check if container has Swift installed.

In order to run container from same image via Powershell or Command prompt, run following command using admin mode

docker run — interactive — tty — name <container_name> <image_name> cmd.exe

Customizing Container

If you made changes inside the container which can not be added to Dockerfile:

For example: When I tried to clone a repository hosted on our corporate VPN, even though we had added ssh-key to the container, it asked to add permanently add stash to list of known hosts. After entring `Yes` to the prompt, the repository was cloned.
This particular step can not be defined in the image and has to be done inside container.
We can commit this change into a new image, so that when a container is created using this image, it retains this change.
Custom Changes in Container

To commit container changes into a new image, run following command in Powershell or Command Prompt using admin mode.

docker commit <container-id> <new-docker-image-name>

The image and container created as a result of above command will have all changes done in the previous container.

Further, you can push this image to the internal corporate docker hub or to the public docker hub so that others can use the same to create Swift-enabled containers on windows.

Happy Swifting on Windows native and container!!

--

--