Running Vagrant using podman as a provider on MacOS M1
VirtualBox, a staple of Vagrant’s default provisioning mechanism, doesn’t support ARM and has zero plans to. Docker has excellent support, but may not be the right tool (because of licensing, etc).
Podman is compatible alternative to Docker, can be aliased to the ‘docker’ command, and doesn’t come with the baggage of Docker. It uses qemu, and has excellent support for ARM.
system setup
This is what you need to do to prepare your system:
- get vagrant installed
- get podman installed
- alias podman to docker (for muscle memory and scripts that rely on ‘docker’ specifically)
Vagrant’s docker plugin does have special code for handling some podman-specific output, but it does require that the output of ‘docker –version’ includes the word ‘podman’ in it. It also checks to make sure that ‘docker’ is a command on the PATH, the process for which might not resolve the alias properly. Using a symlink instead of an alias will pass the PATH check, but will fail the ‘docker –version’ check.
In that case, a simple fix is to put this script somewhere on your PATH as
docker
:
#!/bin/bash
podman "$@"
init podman
Init your podman machine for vagrant usage:
$ podman machine init vagrant
$ podman machine start vagrant
note: podman can only have one running machine at a time, but creating a named machine for vagrant, specifically, allows you to start/stop it as you need, and keep all the vagrant specific contextual stuff separate, assuming that you want to.
create a Dockerfile that is equivalent to a vagrant box
Next you need a Dockerfile
for vagrant to use as it’s target:
#
# NOTE: this is primarily derived from the Dockerfile found in this article:
# https://dev.to/taybenlor/running-vagrant-on-an-m1-apple-silicon-using-docker-3fh4
#
FROM amazonlinux:2
RUN yum -y install systemd systemd-libs initscripts
RUN yum -y update; yum clean all; \
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
RUN yum -y install openssh-server openssh-clients sudo
RUN sed -i -e 's/\(UsePAM \)yes/\1 no/' /etc/ssh/sshd_config
RUN ssh-keygen -A
RUN useradd --create-home -s /bin/bash vagrant
RUN echo -n 'vagrant:vagrant' | chpasswd
RUN echo 'vagrant ALL = NOPASSWD: ALL' > /etc/sudoers.d/vagrant
RUN chmod 440 /etc/sudoers.d/vagrant
RUN mkdir -p /home/vagrant/.ssh
RUN chmod 700 /home/vagrant/.ssh
# this is the insecure vagrant ssh (pub) key published here: https://github.com/hashicorp/vagrant/tree/main/keys
RUN echo "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key" > /home/vagrant/.ssh/authorized_keys
RUN chmod 600 /home/vagrant/.ssh/authorized_keys
RUN chown -R vagrant:vagrant /home/vagrant/.ssh
RUN sed -i -e 's/Defaults.*requiretty/#&/' /etc/sudoers
RUN systemctl enable sshd.service
RUN mkdir /var/run/sshd
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
create a Vagrantfile for your project
And you need a Vagrantfile
for vagrant to use:
Vagrant.configure("2") do |config|
# for a "normal" provider, like VirtualBox, using a vm
config.vm.box = "ubuntu/bionic64"
# for the docker/podman provider, specifically
config.vm.provider "docker" do |d, override|
# need to tell vagrant not to try and manage a box of any kind
override.vm.box = nil
override.ssh.insert_key = true
d.build_dir = "."
d.dockerfile = "Dockerfile.vagrant"
d.has_ssh = true
d.privileged = true
# need to tell podman to forward the ssh port
override.vm.network "forwarded_port", guest: 22, host: 2222
end
# open up to the folder that should be mounted to a folder on the podman
# machine, which might be itself mapped to a volume on the local host system
# depending on your podman machine configuration
config.ssh.extra_args = ["-t", "cd /vagrant; bash --login"]
# for an app running in the vagrant controlled container
#config.vm.network "forwarded_port", guest: 8000, host: 8000
config.vm.provision "shell", inline: <<-SHELL
# fun init stuff here
SHELL
end
run vagrant
Finally, assuming all went well, you can run a vagrant config using docker to emulate a VM, like so:
$ vagrant up --provider=docker
$ vagrant ssh