Replace Docker for Windows with Podman?

By Gerald Mücke | October 14, 2021

Replace Docker for Windows with Podman?

In the recent months - or years - an alternative implementation of the Open Container Inititive (OCI) - Podman - has gained traction, especially as large Linux distributors (RedHat, Suse) decided to drop Docker in favor of Podman. Not to mention, that podman is one of the container engines used by Kubernetes. But how is the situation on Windows?

In this article I want to shed some light on how to set-up Podman on Windows and discuss whether it’s ready to drop Docker on Windows as well.

Docker and Podman rely on kernel virtualization that is only available on Linux and therefore require both a Linux runtime - even on Windows. Earlier versions of Docker4Windows run on a virtual machine - first VirtualBox which was later replaced by a VM running on Hyper-V and now runs directly on Windows Subsystem for Linux (WSL). So either way, you require a VM or Linux to run docker or podman. While the Docker4Windows installation automates this setup for you, podman requires you to set it up yourself.

While there are already blogs or documentation how to set it up on Linux or WSL, none of these guides describe how to replace Docker4Windows which includes the CLI support to call docker from cmd line or powershell (or any other shell) directly from the Windows surface.

Setup

The setup is outlined as follows

  1. Start WSL distro (e.g.Ubuntu)
  2. Install Podman into WSL
  3. Install OpenSSH on WSL and generate keys
  4. Enable services to start automatically when WSL starts
  5. Install Podman into Windows

Start WSL distro

In a cmd line, start wsl by typing

wsl

which will spin up your default distro. You could list all your installed distros using

wsl --list

which may give you an output like

Windows-Subsystem for Linux-Distribution:
Ubuntu-20.04 (default)
docker-desktop
docker-desktop-data

As you can see, I have the Ubuntu distribution installed and set as default distro which gets spun up when starting wsl without any arguments. The Ubuntu distribution can be installed conveniently using the Windows store.

Install Podman into WSL

Now that we have WSL running, it’s time to install Podman. Neither Podman nor Docker run directly on the Windows surface but interact via command line clients with a process running on a (remote) Linux machine. On a local setup that is a process running inside the WSL. So let’s get started.

At first we’ll define some variables. You may add other values or copy these into a script

export NAME=xUbuntu
export VERSION_ID=20.04
export WINDOWS_HOME=/mnt/c/Users/<yourUserNameHere>

Now install Podman according to documentation

sudo sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/${NAME}_${VERSION_ID}/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"
wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/${NAME}_${VERSION_ID}/Release.key -O Release.key
sudo apt-key add - < Release.key
sudo apt-get update -qq
sudo apt-get -qq -y install podman
sudo mkdir -p /etc/containers
echo -e "[registries.search]\nregistries = ['docker.io', 'quay.io']" | sudo tee /etc/containers/registries.conf

In case you don’t want to run podman under your user but use a dedicated podman user you may add a podman user and group, but it’s not required as podman runs in user space

sudo groupadd podman -g 2000
sudo useradd podman -u 2000 -g 2000
#add your user to podman group
sudo usermod -a -G podman $USER

Now we take care of the process that accepts the clients command.

For reference, if you run on a distro that has Docker4Windows activated

ps aux | grep docker

you’ll get an output like

root        48  5.9  0.0 1686676 31016 pts/0   Ssl+ 00:26  73:21 /mnt/wsl/docker-desktop/docker-desktop-proxy --distro-name Ubuntu-20.04 --docker-desktop-root /mnt/wsl/docker-desktop
gmuecke    111  4.4  0.0 766040 42520 pts/1    Ssl+ 00:26  55:09 docker serve --address unix:///home/gmuecke/.docker/run/docker-cli-api.sock

The latter process is the service listening to calls from the docker client and does whatever the client requests. Podman requires a similar process running. We could start podman in a similar way manually by entering

podman system service --time=0 unix:///home/gerald/podman.sock

But as we want to spin this process automatically on startup we have to register it as a service. We create a service by adding the following script as /etc/init.d/podman (there is no systemd on WSL)

#!/bin/bash

#you may use uid 1000 which is your local user or uid 2000 which is the 
# previously created podman user
PODMAN_USER=2000
BASEPATH=/run/user/$PODMAN_USER/podman
PID_FILE=$BASEPATH/podman.pid
SOCK_FILE=$BASEPATH/podman.sock

start() {
  mkdir -p $BASEPATH
  podman system service --time=0 unix://$SOCK_FILE &
  echo "$!" > $PID_FILE
  echo "podman service started, pid is $(cat $PID_FILE)"

  counter=0
  until [[ -S "$SOCK_FILE" && "$counter" -lt 5 ]]
  do
    echo "waiting 1 second"
    sleep 1
    counter=$((counter+1))
  done

  chown -R podman:podman $BASEPATH
  chmod g+rw $SOCK_FILE
}

stop() {
  if [ -S "$SOCK_FILE" ]; then
    echo "socket found"
  fi
  if [ -f "$PID_FILE" ]; then
    echo "pid file found, pid is $(cat $PID_FILE)"
  fi

  if [[ -S "$SOCK_FILE" && -f "$PID_FILE" ]]; then

       kill $(cat $PID_FILE)
       rm -f $SOCK_FILE
       rm -f $PID_FILE
  else
       echo "no socket found, Podman service seems to be stopped"
  fi
}

status() {
  pid=$(cat $PID_FILE)
  if [[ -S "$SOCK_FILE" && -f "$PID_FILE" && $(ps -p $pid > /dev/null) -eq 0 ]]; then
    echo "podman is running (PID=$pid)"
  else
    echo "podman is not running"
  fi

}

case "$1" in
    start)
       start
       ;;
    stop)
       stop
       ;;
    restart)
       stop
       start
       ;;
    status)
       status
       ;;
    *)
       echo "Usage: $0 {start|stop|status|restart}"
esac

Don’t forget to set execution rights on the script:

sudo chmod a+x /etc/init.d/podman

Now start the podman service

sudo service podman start

Install OpenSSH on WSL and generate keys

Different to Docker, which allows TCP access on it’s daemon port, Podman requires SSH to remotely connect to a system running podman. So in order for being able to connect to WSL from Windows via SSH we have to install OpenSSH first.

sudo apt-get -qq -y install openssh-server
sudo service ssh start

We also have to generate a private/public key pair to perform authentication without username / password. Inside the WSL, run the commands:

export WINDOWS_HOME=/mnt/c/Users/Gerald/
ssh-keygen -b 2048 -t rsa -f $WINDOWS_HOME/.ssh/id_rsa_localhost -q -N ""
# also required for the local user
mkdir ~/.ssh
cat $WINDOWS_HOME/.ssh/id_rsa_localhost.pub >> ~/.ssh/authorized_keys

Enable services to start automatically when WSL starts

In order to start both podman and OpenSSH automatically when the WSL starts, we first have to add the service start operation to the sudoers list so that these services can be started without requiring a superuser password

sudo vi /etc/sudoers.d/01-services.conf

add the following entries:

%sudo   ALL(ALL) NOPASSWD: /usr/sbin/service ssh start
%sudo   ALL(ALL) NOPASSWD: /usr/sbin/service podman start

and create a script, that starts both service.

sudo vi /etc/wsl-init

and add the content

#!/bin/sh
echo booting
service ssh start
service podman start

and finally add execution permissions

sudo chmod +x /etc/wsl-init

After the script has been created, we create a new Scheduled Taks in Windows that is launched at boot and will start WSL (this is what Docker4Windows does for you)

  1. In Windows, open the Task Scheduler
  2. Create Basic Task (Wizard)
  3. Enter Name: WSL Init
    • click Next
  4. Select Run at login
    • click Next
  5. Choose Action:
    • Start a Program
    • Program: wsl
    • Arguments: -u root /etc/init-wsl
  6. Finish

Install Podman into Windows

After we’ve installed podman and allow ssh connections to WSL we can install the podman client on Windows.

Download the MSI Installer for podman from https://github.com/containers/podman/releases/tag/latest

After installation we have to configure a connection to our WSL service

set WSL_USER=<yourWslUserIDHere>
podman system connection add wsl --identity %USERPROFILE%\.ssh\id_rsa_localhost ssh://%WSL_USER%@localhost/run/user/2000/podman/podman.sock

Now test the configuration with

podman info

Conclusion

At the time of this writing, it is possible to replace Docker4Windows with Podman with some caveats. While Docker4Windows comes with an automated setup and a tight integration of the filesystem, Podman requires some manual steps for installation and probably also for staying up-to-date. The remote ssl connection “feels” a bit slower, but what’s more missing is the lack of filesystem mapping. When mounting volumes, you have to use the paths inside WSL. This is probably the feature with the most impact on developers.

At the time of writing, Docker4Windows requires a licence for businesses with more than 250 employees or more than 10M$ yearly revenue. The cost for small teams is 7$/person/month or 84$/person/year. What you get in return is an almost hassle-free installation, automated updates and a tight integration.

While Podman is feature-wise a complete replacement for Docker on Linux you’ll have to answer to yourself, whether 84$/person/year are more or less than it would take to install operate Podman. I have doubts - but development isn’t standing still and maybe in the future there’ll be a better installation experience and tighter integration. At the moment, I would stay with Docker4Windows.

References