Replacing docker with podman on macOS (and Linux)
There are many reasons why you might want to replace docker, especially on macOS. One of the more recent controversies with docker has been related to this feature:
...ignoring Docker updates is a paid feature now?? pic.twitter.com/ZxKW3b9LQM
— Brendan Dolan-Gavitt (@moyix) May 1, 2021
Docker has been one of the larger influencers in the container world, helping to standardize the (OCI Image Format Specification). By easily allowing the necessary dependencies to live alongside the application code, the “works on my machine” problem is less of a problem.
For many developers, containers have become synonymous with terms like docker, and the Dockerfile
being a file that contains the instructions on how to build an image. Docker has certainly made it very convenient to build and run containers, but it is not the only solution for doing so.
What are containers?
A container is a standard unit of software that packages up all application dependencies within it. Multiple containers can be run on a host machine all sharing the same kernel as the host. In Linux, namespaces help provide an isolated view of the system: including networking, PIDs, UIDs, and mounts. There is an in-depth video that discusses what containers are made from, and near the end there is a demonstration about how to build your own containers on the command line.
Benefits of podman
One of the most interesting features of podman is that it is daemonless. There isn’t a process running on your system managing your containers. In contrast, the docker client is reliant upon the docker daemon (often running as root) to be able to build and run containers.
Podman is rootless by default. It is now possible to run the docker daemon rootless as well, but it’s still not the default behaviour.
Installing podman
Installing podman on macOS is more involved than installing on Linux, because the podman-machine must run Linux inside a virtual machine. Nevertheless, let’s move forward by installing podman with brew:
brew install podman
We must now initialize the podman machine:
podman machine init
podman machine start
Let’s try to pull an image*:
$ podman pull alpine
Trying to pull docker.io/library/alpine:latest...
Getting image source signatures
Copying blob sha256:a0d0a0d46f8b52473982a3c466318f479767577551a53ffc9074c9fa7035982e
Copying config sha256:14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab
Writing manifest to image destination
Storing signatures
14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab
*Note: If you’re having an issue with pulling containers, you may need to remove ~/.docker
. Rather than removing it entirely, you can simply rename it: mv ~/.docker ~/.docker-backup
. (~/.docker/config.json
can cause issues with podman.)
and then exec into the container:
$ podman run -p 8080 --rm -ti alpine
Error: error preparing container 99ace1ef8a78118e178372d91fd182e8166c399fbebe0f676af59fbf32ce205b for attach: error configuring network namespace for container 99ace1ef8a78118e178372d91fd182e8166c399fbebe0f676af59fbf32ce205b: error adding pod unruffled_bohr_unruffled_bohr to CNI network "podman": unexpected end of JSON input
What does this error mean? A bit of googling lead to this github issue.
Until the fix is released, a workaround is to just specify a port (even when it’s not needed):
podman run -p 8080 --rm -ti alpine
If you’re reading this from the future, there is a good chance specifying a port won’t be needed.
Aliasing docker with podman
Force of habit (or other scripts) may have you calling docker
. To workaround this:
alias docker=podman
podman-compose
You may be wondering: what about docker-compose? Well, there happens to be a drop-in replacement for it: podman-compose.
pip3 install --user podman-compose
alias docker-compose=podman-compose
Now let’s create a docker-compose.yml
file to test:
cat << EOF >> docker-compose.yml
version: '2'
services:
hello_world:
image: ubuntu
command: [/bin/echo, 'Hello world']
EOF
Now run:
$ docker-compose up
podman pod create --name=davegallant.github.io --share net
40d61dc6e95216c07d2b21cea6dcb30205bfcaf1260501fe652f05bddf7e595e
0
podman create --name=davegallant.github.io_hello_world_1 --pod=davegallant.github.io -l io.podman.compose.config-hash=123 -l io.podman.compose.project=davegallant.github.io -l io.podman.compose.version=0.0.1 -l com.docker.compose.container-number=1 -l com.docker.compose.service=hello_world --add-host hello_world:127.0.0.1 --add-host davegallant.github.io_hello_world_1:127.0.0.1 ubuntu /bin/echo Hello world
Resolved "ubuntu" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull docker.io/library/ubuntu:latest...
Getting image source signatures
Copying blob sha256:f3ef4ff62e0da0ef761ec1c8a578f3035bef51043e53ae1b13a20b3e03726d17
Copying blob sha256:f3ef4ff62e0da0ef761ec1c8a578f3035bef51043e53ae1b13a20b3e03726d17
Copying config sha256:597ce1600cf4ac5f449b66e75e840657bb53864434d6bd82f00b172544c32ee2
Writing manifest to image destination
Storing signatures
1a68b2fed3fdf2037b7aef16d770f22929eec1d799219ce30541df7876918576
0
podman start -a davegallant.github.io_hello_world_1
Hello world
This should more or less provide the same results you would come to expect with docker.
Summary
Installing podman on macOS was not seamless, but it was manageable well within 30 minutes of time. I would recommend podman to anyone who is tired of experiencing forced docker updates, and who wants to use a more modern technology for managing containers.
One thing to note is that there isn’t a graphical user interface for podman, but there is an open issue considering one. If you rely heavily on Docker Desktop’s UI, you may not be as interested in using podman just yet.
I had been experimenting with podman on Linux before writing this, but after listening to this podcast episode, I was inspired to try podman on macOS, and then write about my experience here.