As you might have heard, at the end of January Docker started enforcing the license changes that were announced in August 2021.

Therefore, it was a good time to re-evaluate my setup (overall, I’ve been using Docker Desktop since I started learning about containers in 2017).

In this post, I’m going to document my setup, and how I’ve decided to replace Docker Desktop with minikube on my MacBook.


A Replacement for Docker Desktop

In my research, I’ve tried a few alternatives: from podman, to lima + nerdctl, and even Rancher Desktop.

Discussing their pros and cons is not really in scope for this post, nor do I want to swing you towards one or another. In my experience, though, they didn’t feel as “transparent in my day-to-day activities as Docker managed to be, as they all required some heavy tweaking to try to resemble the same functionalities offered by Docker for Desktop (emphasis on the “try”).

My main pain points?

  1. Exposing services to the host.
  2. Mounting local folders for development, with support for hot-reloading.
  3. Accessing (registry) credentials from the macOS Keychain.
  4. Reducing the performance impact on the host.

That’s why, in the end, I’ve decided to switch to minikube.

Although the main purpose of minikube is to allow people to set up a local Kubernetes cluster, it can also be used for traditional Docker workflows (e.g., pull, push, etc.).

It is also worth noting that, even though there are already some tutorials (e.g., 1, 2) describing how to replace Docker Desktop with minikube, it turned out I (like many others) still had issues while trying to mount volumes. After some troubleshooting, I’ve found a solution. The secret? Replace the Hyperkit driver with the Virtualbox one. Why? Because it has built-in host folder sharing.

All of this, without the load of a running Kubernetes cluster!

Next, I’ll describe my setup.


Installation

Uninstall Docker Desktop

If you previously had Docker Desktop installed, that’s what needs to be removed:

sudo rm -Rf /Applications/Docker.app
sudo rm -f /usr/local/bin/docker
sudo rm -f /usr/local/bin/docker-machine
sudo rm -f /usr/local/bin/docker-compose
sudo rm -f /usr/local/bin/docker-credential-desktop
sudo rm -f /usr/local/bin/docker-credential-ecr-login
sudo rm -f /usr/local/bin/docker-credential-osxkeychain
sudo rm -Rf ~/.docker
sudo rm -Rf ~/Library/Containers/com.docker.docker
sudo rm -Rf ~/Library/Application\ Support/Docker\ Desktop
sudo rm -Rf ~/Library/Group\ Containers/group.com.docker
sudo rm -f ~/Library/HTTPStorages/com.docker.docker.binarycookies
sudo rm -f /Library/PrivilegedHelperTools/com.docker.vmnetd
sudo rm -f /Library/LaunchDaemons/com.docker.vmnetd.plist
sudo rm -Rf ~/Library/Logs/Docker\ Desktop
sudo rm -Rf /usr/local/lib/docker
sudo rm -f ~/Library/Preferences/com.docker.docker.plist
sudo rm -Rf ~/Library/Saved\ Application\ State/com.electron.docker-frontend.savedState
sudo rm -f ~/Library/Preferences/com.electron.docker-frontend.plist

Install Virtualbox and minikube

Next, you’ll need both Virtualbox and minikube.

For Virtualbox, pre-compiled binaries are available on the official website. Then, you can use brew to install minikube, as well as some other command line utilities (like docker, and docker-compose):

# Install minikube
$ brew install minikube

# Install docker CLI
$ brew install docker

# Install docker-compose
$ brew install docker-compose

# Install docker-credential-helper
# (needed to retrieve ~/.docker/config.json credentials from the MacOS Keychain)
$ brew install docker-credential-helper

Start minikube

Once you have all the prerequisites, you can start minikube:

1
2
3
4
$ minikube start                 \
        --driver=virtualbox      \
        --memory 4000 --cpus 2   \
        --no-kubernetes
  • Line 2: specifies the driver (virtualbox) to be used.
  • Line 3: specifies the amount of memory and CPU to allocate to the virtual machine running in Virtualbox.
  • Line 4: the --no-kubernetes flag allows to use minikube only as a Docker Desktop replacement without starting Kubernetes itself.

On a first run, the output will look like the one below:

😄  minikube v1.25.1 on Darwin 12.1
    ▪ KUBECONFIG=~/.kube/config:~/Users/.kube/configs/
✨  Using the virtualbox driver based on user configuration
👍  Starting minikube without Kubernetes minikube in cluster minikube
🔥  Creating virtualbox VM (CPUs=2, Memory=4000MB, Disk=20000MB) ...
🏄  Done! minikube is ready without Kubernetes!
╭───────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                       │
│                       💡  Things to try without Kubernetes ...                        │
│                                                                                       │
│    - "minikube ssh" to SSH into minikube node.                                        │
│    - "minikube docker-env" to point your docker-cli to the docker inside minikube.    │
│    - "minikube image" to build images without docker.                                 │
│                                                                                       │
╰───────────────────────────────────────────────────────────────────────────────────────╯

If you open Virtualbox, you’ll be able to see a minikube virtual machine running:

minikube VM in Virtualbox
minikube VM in Virtualbox

Subscribe to CloudSecList

If you found this article interesting, you can join thousands of security professionals getting curated security-related news focused on the cloud native landscape by subscribing to CloudSecList.com.


Configuration

Environment Setup

The last thing needed is to configure your environment (shell) to use minikube’s Docker daemon:

$ eval $(minikube docker-env)

And that’s it! You won’t even have to make changes to your Dockerfiles or docker-compose files.

Addressing the pain points

Pain Point Solution Solved
Exposing services to the host
  • Services can be accessed via the IP address assigned to minikube (minikube ip to see it).
  • To make things simple, you could add an entry to your /etc/hosts file to map the minikube IP to a custom hostname:
    • echo "`minikube ip` docker" | sudo tee -a /etc/hosts > /dev/null
    • After this, you will be able to access exposed services at: http(s)://docker[:port]
Mounting local folders
  • Nothing to do, as the minikube Virtualbox driver has built-in host folder sharing, and the /Users folder is automatically mounted in the VM.
Accessing (registry) credentials from the macOS Keychain
  • If the first minikube start fails due to missing registry credentials, remove the ~/.docker/config.json file and login to the registries again.
  • docker-credential-helper will take care of the rest.
Reducing the performance impact on the host
  • The --no-kubernetes flag allows to use minikube only as a Docker Desktop replacement without starting Kubernetes itself.
  • If that's not enough, you can use the --memory and --cpus flags to fine tune resource consumption.

Automation

As a final touch, a couple of tweaks to automate some of the management of minikube.

First, I’ve added the following to my ~/.zshrc:

1
2
eval $(minikube docker-env)
alias minikubeup="minikube start --driver=virtualbox --memory 4000 --cpus 2 --no-kubernetes"
  • Line 1: first, the eval will ensure every new terminal will automatically point to the minikube’s Docker environment.
  • Line 2: in cases where I’ll have to restart minikube, the minikubeup alias will allow me to not having to remember the correct flags to use.

Lastly, I’ve added a custom plugin to XBar (a nice utility that allows to put the output from any script or program into your macOS Menu Bar). In this regard, I’ve customised the open source Minikube GUI plugin: I’ve stripped the components related to Kubernetes (not used in my setup), and added options to pause/resume the minikube’s Virtualbox VM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
# Adapted from: https://xbarapp.com/docs/plugins/Dev/Kubernetes/minikube.5s.sh.html

MINIKUBE_LOGO_COLOR='...'
MINIKUBE_LOGO_BW='...'

LANG="en_US.UTF-8"
PATH="/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
export LANG PATH

if [[ $(minikube status | grep host) =~ Running ]]; then
    echo "|image=$MINIKUBE_LOGO_COLOR"
else
    echo "|image=$MINIKUBE_LOGO_BW"
fi
echo ---

while read -r STATUS; do
    if [[ $STATUS =~ Running ]]; then
        echo "$STATUS | color=green"
        echo ---
        echo "IP: $(minikube ip) | color=black"
    else
        echo "$STATUS | color=red"
    fi
done < <(minikube status | grep host)

echo ---
echo "⭕️ Pause | terminal=true refresh=true shell=VBoxManage param1=controlvm param2=minikube param3=pause param4=&& param5=exit"
echo "♻️ Resume | terminal=true refresh=true shell=VBoxManage param1=controlvm param2=minikube param3=resume param4=&& param5=exit"
echo ---
  • Line 11-15: fetch the status of minikube and show the appropriate icon (coloured or black/white).
  • Line 22: if minikube is running, show the output of minikube ip.
  • Line 29-30: options to pause/resume the minikube’s Virtualbox VM with one click (by leveraging the VBoxManage command line utility).

You can find my adapted version on Github, and a few screenshots below:

Xbar - ON Xbar - OFF

Conclusions

In this post, I’ve documented my setup, and how I’ve decided to replace Docker Desktop with minikube on my MacBook.

I can say I’m satisfied with the result, as I was able to maintain a streamlined experience without neither having to change my workflows nor to extensively tweak minikube.

I hope you found this post useful and interesting, and I’m keen to get feedback on it! If you find the information shared was useful, if something is missing, or if you have ideas on how to improve it, please let me know on Twitter.