Only registred users can make comments

Running Docker on macOS Without Docker Desktop - updated with Kubernetes installation

colima install with docker

I’ve been using Docker Desktop on my Mac for a while, but I always noticed that it caused my computer to start very slowly, so I decided to look for an alternative.

If you’re using macOS and want to run the Docker runtime without relying on Docker Desktop, it’s still possible. However, since macOS lacks native support for Linux technologies like cgroups and namespaces (which Docker relies on), you’ll need a virtualization layer to run containers. On Linux, Docker can run natively using the kernel’s built-in support for these features, but on macOS, this isn’t possible due to differences in the operating system.

Fortunately, tools like Colima can help with this by providing a lightweight, Linux-based virtual machine optimized for running containers.

What is Colima?

Colima (short for “Containers on Lima”) is an open-source tool that provides a Linux virtual machine on macOS, specifically optimized for running container workloads. It uses Lima, which is a lightweight VM manager, to create a Linux environment on your Mac. Colima is designed to be an alternative to Docker Desktop, with several advantages:

  • Colima is optimized to be efficient in terms of resource usage (CPU, memory).
  • It supports container technologies like Docker and Kubernetes, leveraging the underlying Linux VM.
  • Provides support for Docker and Kubernetes, with features like automatic volume mounting and network port forwarding.
  • Colima allows for easy configuration of CPU, memory, and disk resources, making it a great option for developers.

Installations

In this example, we're going to use Docker runtime.

Install Colima:

brew install colima

Install Docker client (required for Docker runtime):

brew install docker

Start Colina with Docker Runtime:

colima start --runtime docker

Set the Docker Host variable:

export DOCKER_HOST="unix://$HOME/.colima/docker.sock"

Let's test it:

 docker run hello-world

Output:

Hello from Docker!

Start Colima with Custom Preferences

You can also start Colima with your own preferences. Since I have Apple Sillicon processor, I've the following parameters:

colima start \
--profile devoriales-1 \
--activate \
--arch aarch64 \
--cpu 4 \
--disk 15 \
--memory 4 \
--mount ${HOME}:w \
--mount-inotify \
--ssh-agent \
--vm-type vz \
--vz-rosetta \
--verbose

A bit of explanation:

  • --profile devoriales-1; Specifies the profile name for this Colima instance. 
  • --activate; Automatically activates Docker and Kubernetes contexts after Colima starts, so they are ready to use without additional configuration.
  • --arch aarch64; Defines the architecture as ARM64 (aarch64), which is optimized for Apple Silicon (M1/M2/M3/M4). Use this for native compatibility with ARM-based binaries.
  • --cpu 4; Allocates 4 CPU cores to the virtual machine.
  • --disk 15; Allocates 15 GB of disk space for the virtual machine. This space is used to store images, containers, and other data inside Colima.
  • --memory 4; Allocates 4 GB of RAM to the virtual machine. Make sure to adjust this based on your system’s total memory and other running processes.
  • --mount ${HOME}:w;Mounts your home directory (${HOME}) into the virtual machine with write permissions. This allows the VM to access files from your local environment.
  • --mount-inotify; Enables inotify support for file watchers, which is critical for tools like webpack or nodemon that monitor file changes.
  • --ssh-agent; Shares your host’s SSH agent with the virtual machine, allowing the VM to use your SSH keys without having to copy them into the VM.
  • --vm-type vz; Specifies the use of Apple’s Virtualization Framework (vz), which is optimized for performance on Apple Silicon compared to qemu.
  • --vz-rosetta; Enables Rosetta 2 emulation, allowing x86_64 binaries to run within the virtual machine when ARM-native binaries are unavailable.
  • --verbose; Enables detailed logging during Colima startup, which is useful for debugging or understanding the startup process.

Add a second profile

Assume that we want to have a second Kubernetes cluster running. With Colima we can do that by creating a second profile. We can easily create it as we did with devoriales-1:

colima start \
--profile devoriales-2 \
--activate \
--arch aarch64 \
--cpu 2 \
--disk 15 \
--memory 4 \
--mount ${HOME}:w \
--mount-inotify \
--ssh-agent \
--vm-type vz \
--vz-rosetta \
--verbose

Check the Status

To confirm you’re connected to the correct Colima profile, use:

colima status --profile "${COLIMA_VM}"

Output example:

INFO[0000] colima [profile=devoriales-1] is running using macOS Virtualization.Framework
INFO[0000] arch: aarch64
INFO[0000] runtime: docker
INFO[0000] mountType: virtiofs
INFO[0000] socket: unix:///Users/userx/.colima/devoriales-1/docker.sock
➜  ~

❗Please note the path to the docker socket, which points to the profile being used.

Switch the profiles

# Stop the current profile (optional)
colima stop --profile devoriales-1

# Set up the environment for the new profile
export COLIMA_VM="devoriales-2"
export DOCKER_HOST="unix://${HOME}/.colima/${COLIMA_VM}/docker.sock"

# Start the new profile
colima start --profile "${COLIMA_VM}"

Configure Colima to Start Automatically

To start Colima automatically, you can add a configuration script to your shell profile. This script will set up the necessary environment variables and automatically start the Colima virtual machine (VM) if it’s not already running.

In my case, I've added the following to my shell profile file, like ~/.zshrc:

# Colima configuration
export COLIMA_VM="devoriales-1"
export COLIMA_VM_SOCKET="${HOME}/.colima/${COLIMA_VM}/docker.sock"
export DOCKER_HOST="unix://${COLIMA_VM_SOCKET}"

if ! colima status --profile "${COLIMA_VM}" | grep -q 'Running'; then
  colima start --profile "${COLIMA_VM}"
  echo "Colima profile '${COLIMA_VM}' started"
fi

You can extend this script and start all your profiles if you wish.

Delete a profile and corresponding VM

You can delete a profile and corresponding VM:

colima stop --profile devoriales-1
colima delete --profile devoriales-1

Install Kubernetes on Top of Colima

When setting up Kubernetes on Colima, you have two main options:

1. Use the Built-In Kubernetes Cluster Provided by Colima

This is a straightforward approach, as Colima comes with a built-in option to enable Kubernetes with minimal setup.

Kubernetes Installation provided by Colima

You can simply run the following command to install kubernetes:

colima start --with-kubernetes

2. Install a Custom Kubernetes Distribution, such as k3d

k3d offers greater flexibility and advanced configuration options, such as creating multi-node clusters or customizing cluster networking. This makes it an excellent choice for users who need a more tailored Kubernetes environment.

Personally, I prefer using k3d, as it allows for more control over the cluster setup and configuration, making it ideal for experimenting with multi-node setups or specific Kubernetes use cases.

Install k3d

brew install k3d

Now we can install a cluster:

k3d cluster create devoriales-cluster \
  --agents 2 \
  --servers 1 \
  -p "8080:80@loadbalancer" \
  -p "8443:443@loadbalancer"

What This Does:

  • Creates a Kubernetes cluster named devoriales-cluster.
  • 1 server node (control-plane node).
  • 2 agent nodes (worker nodes).
  • Port 8080 for HTTP traffic (mapped to Kubernetes load balancer port 80).
  • Port 8443 for HTTPS traffic (mapped to Kubernetes load balancer port 443).

❗k3ds installs Traefik ingress controller by default.

Once the cluster is created, verify that it is running:

k3d cluster list

We get something like:

NAME                 SERVERS   AGENTS   LOADBALANCER
devoriales-cluster   1/1       2/2      true

Expose the application

Since we have mapped the 8080 to 80 and 8443 to 443 in k3d cluster, we can easily create an ingress rule and expose the application to our local macOS.

Here is an example of running NGINX:

# create namespace
apiVersion: v1
kind: Namespace
metadata:
  name: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx
  namespace: nginx
  annotations:
    ingress.kubernetes.io/ssl-redirect: "false"
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx
            port:
              number: 80
    host: devoriales-nginx.local

---
# add nginx deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.19.6
        ports:
        - containerPort: 80
---
# add nginx service
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: nginx
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Update the /etc/hosts file:

# k3d
127.0.0.1 devoriales-nginx.local

Verify the access from your local machine:

 curl -k http://devoriales-nginx.local:8080/

We should get a following result:

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Great!

You can find more information about the Colima project here

 

Comments