Skip to content

Rootless Podman on an Apple M3 Pro

Published: at 05:00 PM

My journey

Late last year I treated myself to a much-overdue upgrade of my personal laptop. After close to ten years of outstanding service, my 2014 Macbook Air had finally earned its honorable discharge. I replaced it with an Apple M3 Pro.

As part of the uplift I resolved to change the development setup for my numerous side projects. In the past I used to juggle various versions of ghc, node, Python, etc. etc., in my user environment, which unsurprisingly ended up being thoroughly contaminated with myriad seemingly random environment variables meant to configure all of these tools.

On the new machine, I wanted to do things differently and try out containerized development. I had experimented with Docker before, but my old machine had really struggled trying to keep up. In any case, Podman with its rootless feature had started to sound a lot more appealing.

The following describes my path to containerized bliss.

Installing podman

Installing podman via homebrew was straightforward.

$ brew install podman

Following the installation instructions, I then tried

$ podman machine init
$ podman machine start

Unfortunately, this is where the problems began, as the second command got stuck permanently at

Starting machine "podman-machine-default"
Waiting for VM ...

Switching to Apple Hypervisor

A quick search led me to the conclusion that because I have an Apple Silicon-based Mac, I needed to switch to the applehv driver and use vfkit instead of qemu (cp. this Github issue).

Consequently, I modified $HOME/.config/containers/containers.conf

[machine]
  provider = "applehv"

and installed vfkit, again via homebrew.

$ brew tap cfergeau/crc
$ brew install vfkit

The reward was a running VM, finally!

Permission denied

As a next step I tried mounting a directory inside of a simple container (ubi9 from Redhat)

$ podman run -d --rm -v ${HOME}/project:/workspaces/project ubi9 sleep 100

Unfortunately, trying to list the contents of the mounted directory resulted in ‘Permission denied’:

$ podman exec -t $(podman container ls -q) ls -l /workspaces/project
ls: cannot open directory '/workspaces/project': Permission denied

Apparently, this issue occurs due to the rootless nature of the VM.

User namespaces, etc.

By default, the user issuing the ‘podman run’ command is mapped to ‘root’ inside of the container. There are various ways of remapping uid/gid between host and container via the —userns option (see this page for a good summary), and while I did end up using one of the variants (details below), none of the suggestions addressed the ‘permission denied’ problem.

The Troubleshooting page mentions relabelling file objects in the shared volumes by adding either of the two suffixes :z or :Z to the volume mount as a potential solution, but doing so actually modifies the attributes of the files on the host system, which is a side effect that I wanted to avoid by switching to containers in the first place.

Ultimately, at least in my specific situation, only the alternative recommendation to disable SELinux security worked satisfactorily:

$ podman run --security-opt label=disable ...

Enter VSCode

With all these preliminaries out of the way, I could finally progress to leveraging DevContainers in VS Code.

After installing the extension and configuring it to use podman instead of the default docker command,

podman_command_in_vscode

I translated all of my findings above into the following setup inside the main project directory:

# .devcontainer/devcontainer.json
{
    "build": {
        "dockerfile": "../Dockerfile"
    },
    "containerUser": "node",
    "runArgs": [
        "--userns=keep-id:uid=<xxx>,gid=<yyy>",
        "--security-opt", "label=disable"
    ],
    "containerEnv": {
        "HOME": "/home/node"
    },
    "mounts": [
        "source=astro_node_modules,target=${containerWorkspaceFolder}/myblog/node_modules,type=volume"
    ],
    "postCreateCommand": "sudo chown -R node myblog/node_modules"
}

You’ll have noticed an additional mount of a named volume called ‘astro_node_modules’ and associated postCreateCommand. I created this volume specifically for this project - my blog, based on the Astro framework - to store node modules required by Astro following advice gleaned from the Improve Disk Performance section of the VS Code DevContainer site.

$ podman create volume astro_node_modules

The main container user is ‘node’ with in-container home directory ‘/home/node’ and its uid/gid are mapped to my regular user/group on the M3 host. In addition, I reference a Dockerfile which resides in the project’s home directory.

The End

Happy to report that all worked out well in the end, and I enjoy working with this setup.