Using Docker on Apple Silicon

Before getting into the details

Docker is not natively compatible with macOS, so Hyperkit is used to run an alpine virtual image. The workflow described in this guide is similar goals to Docker Desktop on Mac (note that several features such as bridge network, volume wouldn't work with this way.)

Install docker client binary

Install Docker Engine from binaries
Instructions for installing Docker as a binary. Mostly meant for hackers who want to try out Docker on a variety of environments.

Launch Ubuntu Linux (ARM64) VM and Dockerd

First of all, I assume you are working on ~/Downloads directory and have the following files downloaded:

Then run the following commands in terminal:

-- Terminal 1
$ mv ubuntu-20.04-server-cloudimg-arm64-vmlinuz-generic vmlinux.gz
$ gunzip vmlinux.gz
$ rm vmlinux.gz
$ mv ubuntu-20.04-server-cloudimg-arm64-initrd-generic initrd
$ tar zxvf ubuntu-20.04-server-cloudimg-arm64.tar.gz
$ mv focal-server-cloudimg-arm64.img disk.img
$ git clone https://github.com/evansm7/vftool.git
$ cd vftool && xcodebuild
$ cp ./build/Release/vftool vftoolcli

# Expand the disk image size because its default size is 2GB.
$ DYLD_LIBRARY_PATH=~/Downloads/qemu-img-x86_64 ~/Downloads/qemu-img-x86_64/qemu-img resize disk.img +60G
$ ./vftoolcli -k vmlinuz -i initrd -d disk.iso -m 4096  -a "console=hvc0"
...
# You can see /dev/ttysXXX here.

-- Terminal 2
$ screen /dev/ttysXXX

So you can see initramfs prompt in Terminal 2, and then:

mkdir /mnt
mount /dev/vda /mnt
chroot /mnt
touch /etc/cloud/cloud-init.disabled
echo 'root:root' | chpasswd
ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa
ssh-keygen -f /etc/ssh/ssh_host_dsa_key -N '' -t dsa
ssh-keygen -f /etc/ssh/ssh_host_ed25519_key -N '' -t ed25519
cat <<EOF > /etc/netplan/01-dhcp.yaml 
network:
    renderer: networkd
    ethernets:
        enp0s1:
            dhcp4: true
    version: 2
EOF
exit
umount /dev/vda

Now press CTRL + C to terminate the VM, and run the following command to start it again with the disk mounted to /dev/vda:

$ ./vftoolcli -k vmlinuz -i initrd -d focal-desktop-arm64.iso -m 4096  -a "console=hvc0 root=/dev/vda"

After that get into TTY using screen command:

Ubuntu 20.04.1 LTS ubuntu hvc0

ubuntu login: root
Password: root
Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-54-generic aarch64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon Nov 30 08:59:18 UTC 2020

  System load:  0.08              Processes:               100
  Usage of /:   95.8% of 1.23GB   Users logged in:         0
  Memory usage: 4%                IPv4 address for enp0s1: 192.168.64.7
  Swap usage:   0%

  => / is using 95.8% of 1.23GB


0 updates can be installed immediately.
0 of these updates are security updates.


Last login: Wed Apr  1 17:24:06 UTC 2020 on hvc0

$ resize2fs /dev/vda
$ passwd
$ apt update
$ apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common -y
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
$ add-apt-repository \
   "deb [arch=arm64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
$ apt-get update
$ apt-get install docker-ce docker-ce-cli containerd.io -y
$ sh -c "cat <<EOF > /etc/docker/daemon.json
{
    \"hosts\": [\"tcp://0.0.0.0:2375\", \"unix:///var/run/docker.sock\"],
    \"storage-driver\": \"vfs\"
}
EOF"
$ sed -i 's/ -H fd:\/\///g' /lib/systemd/system/docker.service
$ systemctl daemon-reload
$ systemctl restart docker
$ docker run hello-world
# Check if docker works.
$ apt install openssh-server net-tools -y
$ ip a | grep 192.168
    inet 192.168.64.2/24 brd 192.168.64.255 scope global dynamic noprefixroute enp0s1
# Check the IP address here.

Now you can execute docker on your mac by:

$ DOCKER_HOST=192.168.64.xxx docker run hello-world

If this works well, you can use docker after registering the environment variable using export DOCKER_HOST=192.168.64.xx (note that you have to run vftool and check ip address again after rebooting your Mac.)