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.
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
#!/bin/bash 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
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