diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5471c72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +### gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + diff --git a/README.md b/README.md new file mode 100644 index 0000000..bd6c30e --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# Migrate from Docker Desktop to Multipass + +This document will guide you from your current installation of Docker Desktop for Mac to a setup which is not burdened by license fees. + +## Reasoning + +TODO + +## Let’s do this + +### Remove Docker Desktop for Mac + +**Warning**: prior to removing Docker Desktop for Mac, please make sure you back up all the important data you might be storing in your containers/volumes. + +1. Click the Docker icon in the macOS menu bar +2. Select the _Settings_ option +3. Click the button with a bug icon in the top right + ![Docker Desktop](images/dd-1.png) +4. Click the _Uninstall_ button and confirm the removal + ![Docker Desktop](images/dd-2.png) + ![Docker Desktop](images/dd-3.png) + ![Docker Desktop](images/dd-4.png) + - This will make sure that all files that were created by Docker Desktop (such as Docker images, Docker containers, and the Linux VM in which Docker Desktop operates itself) are properly removed + - This process might take 5-15 minutes, because Docker for Mac never cared about your time as a developer +5. If you installed Docker Desktop for Mac using Homebrew (specifically Homebrew Cask), also remove the last remaining artifacts of Docker Desktop by running either `brew uninstall --cask docker` or `brew uninstall --cask docker-edge` + +### Install Multipass + +1. In shell, run `brew install multipass` +2. You will be prompted for your password during the installation, so enter it when prompted +3. _Optional_: if you want to (or have to, due to crazy network configuration, as is the case for me) use VirtualBox as the hypervisor (instead of `Hypervisor.framework`), install VirtualBox now using the following command: `brew install virtualbox` + - You will likely be prompted to enable new kernel extension. You can do so by going to _System Preferences_ ⤳ _Security and Privacy_ ⤳ _Allow_, and restarting your Mac + - An indication that you cannot use `Hypervisor.framework` would be a sudden loss of Internet connection on your Mac while running the `init-instance.sh` command in the next step. If that happens to you, don’t panic, and restart your Mac. That should restore your network functionality. Run the `multipass delete --purge --all` command to start again from a clean state, and resume this tutorial from the third step, by using VirtualBox this time +4. Provision a virtual machine using Multipass: + - If using the default `Hypervisor.framework`, run `./init-instance.sh docker` + - If using VirtualBox, run `./init-instance.sh docker --virtualbox` diff --git a/images/dd-1.png b/images/dd-1.png new file mode 100644 index 0000000..d13c8e7 Binary files /dev/null and b/images/dd-1.png differ diff --git a/images/dd-2.png b/images/dd-2.png new file mode 100644 index 0000000..5d39d3c Binary files /dev/null and b/images/dd-2.png differ diff --git a/images/dd-3.png b/images/dd-3.png new file mode 100644 index 0000000..5c6aaf7 Binary files /dev/null and b/images/dd-3.png differ diff --git a/images/dd-4.png b/images/dd-4.png new file mode 100644 index 0000000..d511fca Binary files /dev/null and b/images/dd-4.png differ diff --git a/init-instance.sh b/init-instance.sh new file mode 100755 index 0000000..b96ee42 --- /dev/null +++ b/init-instance.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +set -e +set -o pipefail + +if [[ $# -eq 0 ]]; then + echo "Usage: $0 " + exit 1 +fi + +NAME=$1 +HYPERVISOR="hyperkit" + +if [[ $2 = "--virtualbox" ]]; then + HYPERVISOR="virtualbox" +fi + +# Configure Multipass to use the correct hypervisor +if [[ $HYPERVISOR = "virtualbox" ]]; then + sudo multipass set local.driver=virtualbox +fi + +# Spawn a new instance with a name given as first argument to the script +# If needed, can specify `focal` or other Ubuntu codename as last argument +# By default, Multipass will spawn a new instance with the latest stable Ubuntu, +# which is `focal` at the time of the script creation +echo "==> Creating a new VM, this might take a while…" +multipass launch --name "${NAME}" # focal + +# Transfer setup script to the new instance +echo "==> Installing Docker inside the VM…" +multipass transfer setup-instance.sh "${NAME}":/home/ubuntu/setup-instance.sh + +# Execute script +multipass exec "${NAME}" -- /bin/bash -x "/home/ubuntu/setup-instance.sh" + +# Enable passwordless SSH to the Multipass instance +# First, let’s create a new SSH key pair +if [ -f ~/.ssh/id_multipass_docker ]; then + echo "--> SSH key already exists, skipping and reusing ~/.ssh/id_multipass_docker…" +else + echo "==> Creating SSH key pair…" + ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_multipass_docker -N "" +fi + +# Add the key to list of authorized keys +echo "==> Setting up passwordless SSH…" +multipass transfer ~/.ssh/id_multipass_docker.pub "${NAME}":/home/ubuntu/.ssh/id_multipass_docker.pub +multipass exec "${NAME}" -- /bin/bash -c "cat /home/ubuntu/.ssh/id_multipass_docker.pub >> /home/ubuntu/.ssh/authorized_keys" + +# Find out IP address & connection method to the instance +IP_ADDRESS=$(multipass info docker | grep IPv4 | awk '{ print $2; }') +PORT=22 + +if [[ $HYPERVISOR = "virtualbox" ]]; then + IP_ADDRESS="localhost" + PORT=$(sudo VBoxManage showvminfo docker | grep -i nic | grep "name = ssh," | sed -rn 's/.*host port = ([[:digit:]]+).*/\1/p') +fi + +echo "--> VM detected at ${IP_ADDRESS}:${PORT}…" + +# Alter ~/.ssh/config +if grep "Host multipass" ~/.ssh/config > /dev/null; then + echo "--> Host multipass exists in SSH config, skipping ~/.ssh/config modification…" +else + echo "==> Modifying ~/.ssh/config…" + { + echo + echo "Host multipass" + echo " HostName ${IP_ADDRESS}" + echo " Port ${PORT}" + echo " User ubuntu" + echo " IdentityFile ~/.ssh/id_multipass_docker" + } >> ~/.ssh/config +fi + +if docker context ls | grep multipass > /dev/null; then + echo "--> Docker context multipass exists, skipping creation…" +else + echo "==> Creating Docker context…" + docker context create multipass --docker "host=ssh://multipass" +fi + +docker context use multipass + +echo "=> You should be good to go! Try running \`docker container run hello-world\` now!" diff --git a/install-software.sh b/install-software.sh new file mode 100755 index 0000000..1c94c05 --- /dev/null +++ b/install-software.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# set -e +set -o pipefail + +echo "Uninstalling Docker Desktop if installed…" +brew uninstall --cask --zap docker >/dev/null 2>&1 +brew uninstall --zap docker-completion >/dev/null 2>&1 + +echo "Installing Multipass…" +brew install multipass >/dev/null 2>&1 + +if [[ $1 = "--virtualbox" ]]; then + echo "Installing VirtualBox…" + brew install --cask virtualbox virtualbox-extension-pack >/dev/null 2>&1 +fi + +echo "Installing Docker CLI…" +brew install docker >/dev/null 2>&1 + +echo "Done!" diff --git a/setup-instance.sh b/setup-instance.sh new file mode 100644 index 0000000..fb13319 --- /dev/null +++ b/setup-instance.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +set -e +set -o pipefail + +# Update the system first +sudo apt update +sudo apt upgrade -y + +# Install prerequisites +sudo apt install -y \ + ca-certificates \ + curl \ + gnupg \ + lsb-release + +# Add Docker’s official GPG key +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg + +# Add Docker’s stable repository +# Note: If you want to add `nightly` or `test` repository, add the words +# `nightly` or `test` (or both) after the word `stable` in the commands below. +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + +# Update the `apt` package index +sudo apt update +sudo apt install -y docker-ce docker-ce-cli containerd.io + +# Create necessary groups if needed +getent group docker || sudo groupadd docker +sudo usermod -aG docker ubuntu + +# This should not be needed, but just to be sure, let’s start Docker on boot +sudo systemctl enable docker.service +sudo systemctl enable containerd.service