Daniel's Tech Blog

Cloud Computing, Cloud Native & Kubernetes

Running Podman on macOS with Multipass

Several months ago, I worked on a little side project during my spare time but instead of writing a blog post I set it aside till today.

Since the announcement that Docker made yesterday on what has changed in the Docker Subscription Service Agreement my side project got my attention again.

-> https://www.docker.com/blog/updating-product-subscriptions/

For most of us nothing will change as Docker for Desktop stays free for personal use. But for companies which have been using Docker for Desktop for free and not using Docker Hub as their primary container registry things have changed since yesterday.

Looking at alternatives for Docker for Desktop, Podman will be definitely the container engine that gets most of the attention right now.

-> https://podman.io/

In today’s blog post I walk you through how to run Podman on macOS with Multipass as an alternative for Docker for Desktop. This was my little side project I worked on several months ago.

Let us start with the prerequisites for it. You need two tools installed on your Mac. The Podman client and Multipass. Both tools can be installed easily via brew.

I have written an install script which installs both tools via brew in the first step.

#!/bin/bash

PODMAN_MODE=$1

# Install podman client & multipass
brew install podman multipass

# Symlink as otherwise `az acr login` does not work.
ln -s /usr/local/bin/podman /usr/local/bin/docker || true

# Podman setup
SSH_PUB_KEY=$(cat ~/.ssh/id_rsa.pub)
echo '
ssh_authorized_keys:
  - '${SSH_PUB_KEY}'' >> user-data

./create.sh $PODMAN_MODE

Instead of only using docker as an alias for podman, as recommended in most articles throughout the web, I am creating a symlink too. The symlink is a hard requirement when you are working with the Azure Container Registry and using the command az acr login. The command checks for the docker binary executable and fails if it cannot find it on the system. So, the docker alias will not work in that case but the symlink does.

Next step is your SSH public key which is added to the end of the user-data file.

users:
  - default

write_files:
  - path: /home/ubuntu/setup-podman.sh
    content: |
      #!/bin/bash

      # Set correct permission on own home folder
      sudo chown ubuntu:ubuntu .
      chmod 755 .

      # Install podman
      . /etc/os-release
      echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
      curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key | sudo apt-key add -
      sudo apt update
      sudo apt install podman fuse-overlayfs -y
      sudo cp /home/ubuntu/.ssh/authorized_keys /root/.ssh/authorized_keys
      sudo systemctl --system enable --now podman.socket
      systemctl --user enable --now podman.socket
      sudo loginctl enable-linger $USER
      sudo systemctl enable --now ssh.service
    permissions: "0755"

runcmd:
  - sudo cp /etc/skel/.bashrc /home/ubuntu/.bashrc
  - sudo cp /etc/skel/.bash_logout /home/ubuntu/.bash_logout
  - sudo cp /etc/skel/.profile /home/ubuntu/.profile

The user-data file is a cloud-init file which configures our Ubuntu VM we spin up with Multipass on our Mac.

As seen above a setup script for installing Podman in the Ubuntu VM is placed in the user’s home folder. Podman gets configured to be accessible in root and rootless mode. Depending on the parameter you provide when running the install.sh script you interact in root or rootless mode with Podman.

> ./install.sh root
> ./install.sh rootless

Last step is running the create.sh script.

#!/bin/bash

PODMAN_MODE=$1

INSTANCE_NAME="podman"
multipass set client.primary-name=$INSTANCE_NAME

multipass launch -c 4 -m 8G -d 32G -n $INSTANCE_NAME --cloud-init user-data 20.04
multipass exec $INSTANCE_NAME -- /home/ubuntu/setup-podman.sh

IP=$(multipass info $INSTANCE_NAME | grep IPv4: | cut -d ':' -f2 | tr -ds ' ' '')
if [ "$PODMAN_MODE" == "root" ]; then
  podman system connection add $INSTANCE_NAME --identity ~/.ssh/id_rsa  ssh://root@${IP}/run/podman/podman.sock
else
  podman system connection add $INSTANCE_NAME --identity ~/.ssh/id_rsa  ssh://ubuntu@${IP}/run/user/1000/podman/podman.sock
fi

# List of volume mounts that Docker for Desktop also mounts per default.
multipass mount /Users $INSTANCE_NAME
multipass mount /Volumes $INSTANCE_NAME
multipass mount /private $INSTANCE_NAME
multipass mount /tmp $INSTANCE_NAME
multipass mount /var/folders $INSTANCE_NAME

multipass list
echo "#######################"
podman system connection list

The script launches a new Multipass Ubuntu 20.04 instance with 4 cores, 8 GB memory and 32 GB disk configured. Podman then gets installed by executing the setup script. Afterwards a system connection is added for Podman which enables us using the Podman client from our Mac to interact with the Podman server in the Multipass instance.

Finally, several folders are mounted into the Multipass instance and Podman is ready. The volume mounts are the exact default mounts Docker for Desktop uses. In the end you only need the /Users mount point.

“By default the /Users, /Volume, /private, /tmp and /var/folders directory are shared.”
https://docs.docker.com/desktop/mac/#resources

When we run now podman version or docker version we get the version information about the Podman client and server.

Terminal - Running podman version and docker version

Let us start a simple Hello World container application. As I am interacting with Podman in root mode I can bind the container to the privileged port 80.

> docker run -d -p 80:80 mcr.microsoft.com/azuredocs/aci-helloworld:latest

> docker ps
CONTAINER ID  IMAGE                                              COMMAND               CREATED         STATUS             PORTS               NAMES
c0aca4d57e9a  mcr.microsoft.com/azuredocs/aci-helloworld:latest  /bin/sh -c node /...  16 seconds ago  Up 16 seconds ago  0.0.0.0:80->80/tcp  exciting_colden

Opening a browser and accessing the Multipass instance via its IP address we see the Hello World application.

Browser - Hello World application

As always, you find the scripts on my GitHub repository.

-> https://github.com/neumanndaniel/scripts/tree/main/Bash/Podman

I also added two more scripts. One for switching between root and rootless mode and the other one to reset the Multipass instance.

WordPress Cookie Notice by Real Cookie Banner