Last weekend I posted about Docker Desktop Alternatives for macOS, and it looks like I missed one as the week before Podman release version v3.3.0 which introduced support for macOS by allowing you to launch a Podman managed virtual machine.
So, What is Podman?
Podman is a daemonless container engine for developing, managing, and running OCI Containers on your Linux System. Containers can either be run as root or in rootless mode.
As it has been built to run and manage OCI compliant container images it means that any images want to run built using any other Container engine, like Docker or containerd (which was covered in last weeks post using Lima) will also “just” work with Podman - to the point where the Podman developers are confident enough to claim that you add
alias docker=podman on your machine as running Podman is nearly indistinguishable from running Docker.
Let’s put that to the test.
As I am running macOS installing Podman using Homebrew is just a simple command:
brew install podman
Using Podman Machine
podman client binaries are installed there isn’t much you can do with it other than connect to remote instances of Podman, this is because macOS is not able to natively run containers so we need to download a Linux image to run a virtual machine, to do this simply run the following command:
podman machine init
As you can see from the following output this downloads a custom Fedora image based on CoreOS:
Downloading VM image: fedora-coreos-34.20210904.1.0-qemu.x86_64.qcow2.xz: done Extracting compressed file
Now that we have a copy of the image and the virtual machine has been created, we can now start the virtual machine by running:
podman machine start
This gives the following output, as you can see, there is a warning - but this release is hot off the press so we can forgive that:
INFO waiting for clients... INFO listening tcp://0.0.0.0:7777 Waiting for VM ... INFO new connection from to /var/folders/q8/dplpdx9n7lz1r3m282_vcz440000gn/T/podman/qemu_podman-machine-default.sock qemu-system-x86_64: warning: host doesn't support requested feature: CPUID.80000001H:ECX.svm [bit 2]
Once the virtual machine is up and running you can run the following command to open a shell to it:
podman machine ssh
Now we have a shell on the machine lets look at the operating system information:
Connecting to vm podman-machine-default. To close connection, use `~.` or `exit` Warning: Permanently added '[localhost]:50983' (ECDSA) to the list of known hosts. Fedora CoreOS 34.20210904.1.0 Tracker: https://github.com/coreos/fedora-coreos-tracker Discuss: https://discussion.fedoraproject.org/c/server/coreos/ [[email protected] ~]$ cat /etc/*release Fedora release 34 (Thirty Four) NAME=Fedora VERSION="34.20210904.1.0 (CoreOS)" ID=fedora VERSION_ID=34 VERSION_CODENAME="" PLATFORM_ID="platform:f34" PRETTY_NAME="Fedora CoreOS 34.20210904.1.0" ANSI_COLOR="0;38;2;60;110;180" LOGO=fedora-logo-icon CPE_NAME="cpe:/o:fedoraproject:fedora:34" HOME_URL="https://getfedora.org/coreos/" DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora-coreos/" SUPPORT_URL="https://github.com/coreos/fedora-coreos-tracker/" BUG_REPORT_URL="https://github.com/coreos/fedora-coreos-tracker/" REDHAT_BUGZILLA_PRODUCT="Fedora" REDHAT_BUGZILLA_PRODUCT_VERSION=34 REDHAT_SUPPORT_PRODUCT="Fedora" REDHAT_SUPPORT_PRODUCT_VERSION=34 PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy" VARIANT="CoreOS" VARIANT_ID=coreos OSTREE_VERSION='34.20210904.1.0' DEFAULT_HOSTNAME=localhost Fedora release 34 (Thirty Four) Fedora release 34 (Thirty Four) [[email protected] ~]$ exit logout Connection to localhost closed.
While you can open a shell to the machine it is not needed to run so let’s run some containers using the
podman client on our Mac.
So now we have everything up and running let’s re-run the same command we used when testing Lima in the last post.
First up is the
podman equivalent of running
docker container run hello-world, as we have already stated that you can simply replace Docker with Podman it will be no surprise that the command is:
podman container run hello-world
As expected, this connects straight do the Docker Hub , pulls and then runs the image:
Resolved "hello-world" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf) Trying to pull docker.io/library/hello-world:latest... Getting image source signatures Copying blob sha256:b8dfde127a2919ff59ad3fd4a0776de178a555a76fff77a506e128aea3ed41e3 Copying blob sha256:b8dfde127a2919ff59ad3fd4a0776de178a555a76fff77a506e128aea3ed41e3 Copying config sha256:d1165f2212346b2bab48cb01c1e39ee8ad1be46b87873d9ca7a4e434980a7726 Writing manifest to image destination Storing signatures Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/
So far, so good.
Building and running an Image
Next, lets take the Dockerfile we built last time and try building it using Podman, as a reminder the Dockerfile looks like the following:
FROM alpine:latest LABEL maintainer="Russ McKendrick <[email protected]>" LABEL description="This example Dockerfile installs NGINX." RUN apk add --update nginx && \ rm -rf /var/cache/apk/* && \ mkdir -p /tmp/nginx/ COPY files/nginx.conf /etc/nginx/nginx.conf COPY files/default.conf /etc/nginx/conf.d/default.conf ADD files/html.tar.gz /usr/share/nginx/ EXPOSE 80/tcp ENTRYPOINT ["nginx"] CMD ["-g", "daemon off;"]
To build the image you will need to checkout this repo and run the build command from the folder containing the
Dockerfile. The command to build and tag the image is no different to the one which we would use in Docker:
podman image build --tag local:podman-example .
The output of the build is below:
STEP 1/10: FROM alpine:latest Resolved "alpine" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf) Trying to pull docker.io/library/alpine:latest... Getting image source signatures Copying blob sha256:a0d0a0d46f8b52473982a3c466318f479767577551a53ffc9074c9fa7035982e Copying blob sha256:a0d0a0d46f8b52473982a3c466318f479767577551a53ffc9074c9fa7035982e Copying config sha256:14119a10abf4669e8cdbdff324a9f9605d99697215a0d21c360fe8dfa8471bab Writing manifest to image destination Storing signatures STEP 2/10: LABEL maintainer="Russ McKendrick <[email protected]>" --> 9e7e28e77e9 STEP 3/10: LABEL description="This example Dockerfile installs NGINX." --> aa67eedf7b2 STEP 4/10: RUN apk add --update nginx && rm -rf /var/cache/apk/* && mkdir -p /tmp/nginx/ fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz (1/2) Installing pcre (8.44-r0) (2/2) Installing nginx (1.20.1-r3) Executing nginx-1.20.1-r3.pre-install Executing nginx-1.20.1-r3.post-install Executing busybox-1.33.1-r3.trigger OK: 7 MiB in 16 packages --> 6a61a4653e9 STEP 5/10: COPY files/nginx.conf /etc/nginx/nginx.conf --> f3a1faa6b75 STEP 6/10: COPY files/default.conf /etc/nginx/conf.d/default.conf --> 4a57c732f37 STEP 7/10: ADD files/html.tar.gz /usr/share/nginx/ --> 2180b8083f4 STEP 8/10: EXPOSE 80/tcp --> fe304c0d38d STEP 9/10: ENTRYPOINT ["nginx"] --> 4dda02ea2b7 STEP 10/10: CMD ["-g", "daemon off;"] COMMIT local:podman-example --> 88a4d1cbc6d Successfully tagged localhost/local:podman-example 88a4d1cbc6dcf92cd4662da990e80125ad062c0ac99551e38c0a2e8eee9231f9
Once built you can use the following command to run the image:
podman container run -d --name podman-example -p 8080:80 --network bridge local:podman-example
Once running, open a browser and goto http://localhost:8080/ and you should be greeted by:
Now the keen eyed amongst you may have noticed that the command to launch the container is a little slightly different than want we used in the last post, at the time of writing –network bridge is needed to map port 8080 from the virtual machine to 127.0.0.1 on the mac. The next release which is due in the next fortnight should resolve this.
Update 10/10/2021 the update has been release and it works as expected, so you can remove the –network bridge from the command.
From as you can see from the terminals below, other commands you would just run in Docker to manage your containers just work:
podman image ls REPOSITORY TAG IMAGE ID CREATED SIZE localhost/local podman-example 52add0470325 15 minutes ago 7.57 MB docker.io/library/alpine latest 14119a10abf4 2 weeks ago 5.87 MB docker.io/library/hello-world latest d1165f221234 6 months ago 20.4 kB
podman container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 79e3825f608e docker.io/library/hello-world:latest /hello 37 minutes ago Exited (0) 37 minutes ago lucid_chandrasekhar 8fd9aaa8febe localhost/local:podman-example -g daemon off; 9 seconds ago Up 9 seconds ago 0.0.0.0:8080->80/tcp podman-example
podman container stop podman-example ERRO accept tcp [::]:8080: use of closed network connection podman-example
podman container rm podman-example
podman container prune WARNING! This will remove all non running containers. Are you sure you want to continue? [y/N] y 79e3825f608e5f4a0ce8dd03849ecb55d5ff03eeff063a52c9e053bcde0460fc
podman image prune WARNING! This will remove all dangling images. Are you sure you want to continue? [y/N] y
Tidying up Podman
Once you have finished having a play with Podman you will need to stop the virtual machine, as you may have already guessed, to do this run the following command:
podman machine stop
Once stopped, you can start it back up again - order to remove the Virtual Machine altogether run:
podman machine rm
This will give the following prompt:
This will delete the virtual machine and everything on it, please make sure you really to do this before agreeing.
The following files will be deleted: /Users/russ.mckendrick/.ssh/podman-machine-default /Users/russ.mckendrick/.ssh/podman-machine-default.pub /Users/russ.mckendrick/.config/containers/podman/machine/qemu/podman-machine-default.ign /Users/russ.mckendrick/.local/share/containers/podman/machine/qemu/podman-machine-default_fedora-coreos-34.20210904.1.0-qemu.x86_64.qcow2 /Users/russ.mckendrick/.config/containers/podman/machine/qemu/podman-machine-default.json Are you sure you want to continue? [y/N]
Once you have delete the virtual machine you will need to run
podman machine init to recreate it again.
Bonus Desktop App
While currently there is not an official native Desktop app for Podman on macOS, Victor Gama has coded and released one which can be downloaded from heyvito/podman-macos , the screens below show the application in action …
… at the time of writing of writing the application is less than a week or so old so I recommend keeping an eye on the repo for updates.
Podman has long been used on Linux machines, and the developers (RedHat) have been working on the macOS integration long before Docker announced their changes to the licensing model for Docker Desktop.
There are however some bugs, like the one mentioned, and also some functionality which needs to be in place - the biggest of which is the at the time of writing there is no native way to mount the filesystem from the host (macOS) into the virtual machine (Podman) which could be a deal breaker from some developers as this could block them from easily developing locally. However, the good thing is the Podman developers know all of this and are working hard to add the functionality on top of their already solid base.