Using Docker and Docker-Compose on macOS with Multipass

      No Comments on Using Docker and Docker-Compose on macOS with Multipass

In the light of recent news that
Docker Desktop for Windows and macOS is no longer free, efforts have been put in to search for a replacement.

Docker Desktop?

Docker Desktop used to be Docker Toolbox, which is based on VirtualBox. Docker Desktop is able to utilize Hyperkit on macOS which makes the performance much better compared to Type II hypervisor.

In my mind a good in-place replacement should be:

  • Runs single Dockerfile
  • Supports volume mounting and port forwarding
  • Runs docker-compose.yml
  • Easy to setup
  • Supports Windows and macOS(Docker Engine on Linux remains open-sourced)
  • Works with built-in debugger for common IDEs(IntelliJ & VSCode)
  • Works with IDE’s built-in support that’s based on Docker socket
  • Supports ARM Mac

Common replacements proposed includes:

  • Podman: a Redhat-backed solution that runs on OCI. Spins up a Podman-flavored VM. Very limited support for Docker-Compose. Probably requires reworking Dockerfile. Volume mounting is painful. Cannot be used with IDE’s built-in support.
  • Microk8s & k3s: Kubenetes. Won’t work with Docker-Compose.

Multipass

This is where Multipass comes to shine:

  • Utilized Hyperkit, Hyper-V, and Virtualbox for best performance
  • Handles volume mounting nicely
  • Easy to setup
  • Networking is easy
  • Volume mounting is simple – at least when using Hyperkit
  • Native ARM support

Downsides include:

  • Ubuntu. Not even Debian. Bad news for CentOS lovers.
  • Overlapping function with Vagrant. Can’t deny that.

The actual setup

Steps based on macOS Catalina, 10.15.7.

Install Multipass

Download installer
here. You DO NOT need to set driver as VirtualBox – leave it as is and Hyperkit will be used as default!

You can try running brew install multipass.

Make sure that you give multipassd Full Disk Access – otherwise mounting will fail!

Create and setup your instance

I am calling my instance as
fakedocker.

Note the default disk size is merely 5GiB – not enough for setting up Docker. To give it a bit more space:

multipass launch fakedocker -d 20G

Use -c to add more CPU cores, -m to add more RAM. Documentation

One-liner with cloud-init

You may want to change Docker-Compose’s version to the latest.

Save this file as cloud-init.yaml, and run:

multipass launch fakedocker -d 20G --cloud-init cloud-init.yaml

If having any problem, run multipass shell fakedocker to SSH into the VM. Logs are located at /var/log/cloud-init.log.

Manually set up your instance

Create VM

Use multipass launch fakedocker -d 20G to create the instance.

Run multipass shell fakedocker to get into the instance.

Setup Docker and other stuff

Follow this guide to install Docker: https://docs.docker.com/engine/install/ubuntu/

Also this post-install guide to setup groups: https://docs.docker.com/engine/install/linux-postinstall/

For installing Docker-Compose: https://docs.docker.com/compose/install/

Run sudo apt-get install -y avahi-daemon libnss-mdns to install Avahi to enable Bonjour so you can access the box by fakedocer.local. This will comes in handy in the following setup.

Edit Docker’s Systemd config to expose both port and Unix socket: TCP is for remote debugger on your local machine, the socket is for running Docker command locally:

Create a folder at /lib/systemd/system/docker.service.d/ add a file overwrite.conf with the following content:

then

to make sure that docker command works on the VM.

Mounting local folder

Run multipass mount ~ fakedocker to attach your home directory to the new VM. This will make sure that you don’t need to calculate where you are mounting.

Quick sanity test

On fakedocker VM,

  • Run docker pscommand: Docker should be able to run. You may need to log out and re-login for group change to take effect.
  • Run nc -zv 127.0.0.1 2375to make sure that Docker Engine is taking traffic from TCP.
  • Run ls /User/<your_username>to make sure that volume attaching is successful: use catto read a file, and write something random to make sure that the attached volume is readable and writable.

On your local machine:

  • do a nc -zv fakedocker.local 2375to make sure that your local debugger can communicate with the Docker instance on fakedocker.

Now you’ve got a nice environment where you can use
docker
and
docker-compose
as if you are on your local machine.

Setting up Docker on Mac

Run export DOCKER_HOST="tcp://fakedocker.local:2375" or put it in your ~/.zshrc to make the VM your default Docker host.

Follow https://docs.docker.com/engine/install/binaries/ to setup docker command locally, and https://github.com/docker/compose/releases to setup docker-compose.

Setting up remote debugger

I am using PyCharm with Docker-Compose with attached volume in docker-compose.yml as an example:

Create a new Docker machine

PyCharm should be able to connect to this instance.

Setup a new Interpreter

Make sure that you do Path mappings as shown: otherwise, debugger won’t be able to run.

Setup debug config

Listen to 0.0.0.0 – otherwise, you won’t be able to visit the web service.

That should be it! Trigger debugging – if you are listening to port 8000, go to http://fakedocker.local:8000 to visit your site. Setup port forwarding in docker-compose.yml if you want to expose more services, like your database.

Common problems

Multipass VM stuck at “Starting”/ Multipass is stuck on any command

Run
sudo pkill multipassd
and redo your last step. multipassd is a daemon that checks VM: killing this process does not change the state of VM. (So what’s the point of making it a daemon?)

Multipass VM is botched

Run multipass delete <name_of_vm> && multipass purge to completely remove the VM. 

Multipass VM cannot read mounted folder on computer reboot

Reattach the volume:
multipass unmount ~ fakedocker && multipass mount ~ fakedocker.

Cannot connect to remote Docker

Make sure that you’ve edited Docker’s startup command to include TCP listening on
0.0.0.0.

Need to debug issues when using cloud-init

Logs are located at /var/log/cloud-init.log.

docker command on VM won’t run

  • Make sure that Docker’s startup command also listens on Unix socket.
  • That socket file needs to be 666.

IDE cannot connect to debugger: cannot find debugger file(especially Pycharm)

Mount your project home to
/opt/project.

Reference

https://github.com/canonical/multipass/issues/913

https://youtrack.jetbrains.com/issue/PY-33489

https://serverfault.com/questions/843296/how-do-i-expose-the-docker-api-over-tcp

https://docs.docker.com/engine/install/ubuntu/

https://docs.docker.com/engine/install/linux-postinstall/

https://docs.docker.com/compose/install/

https://github.com/canonical/multipass/issues/1839

https://github.com/canonical/multipass/issues/1389

https://docs.docker.com/engine/install/binaries/

https://cloudinit.readthedocs.io/en/latest/topics/examples.html

https://cloudinit.readthedocs.io/en/latest/topics/boot.html

https://unix.stackexchange.com/questions/542343/docker-service-how-to-edit-systemd-service-file

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.