2.8k
Connect
  • GitHub
  • Mastodon
  • Twitter
  • Slack
  • Linkedin

Blog

No Runtime Required: Get Containers on macOS and Windows with Colima and Flox

Steve Swoyer | 13 December 2024
No Runtime Required: Get Containers on macOS and Windows with Colima and Flox

Fun Package Fridays is a series where we ask members of the Flox team to share fun and perhaps not-so-well-known tools and utilities you can find in the Flox Catalog, powered by Nix. Today's edition comes from Steve Swoyer, our staff writer and resident Nix abecedarian.

12 days from today, many of us expect to be inundated with plenty of packages.

So think of this week’s edition of Fun Package Friday(R)(TM) as kicking off the 12 Days of Christmas.

For this Friday, December 13th (!) we’re serving up a timely apotropaic talisman in the form of a neat, useful, powerful package that promises to revolutionize your workflow.

And with this as prelude, we give you...Colima, a lightweight Linux VM pre-configured for running containers on macOS, Linux, and Windows with WSL2.

Short for “Containers on Lima,” Colima is built on Lima, a CNCF-sponsored project for running Linux VMs on macOS. It ships pre-configured with Docker Engine by default, but it can also be set up to run just containerd. Colima is an especially attractive option for running containers on macOS, integrating quite nicely with macOS’ Apple Hypervisor Framework.

Colima = containers made simple

Flox does this thing where we point out stuff you can do with us that you can’t do with containers.

But the reverse of this shtik is also true. Flox, Nix, and containers are all gifts to the world. They let you do different kinds of things differently. Need to run software in a hermetically isolated context but with direct access to local hardware? Containers are great for that! (On Linux, at least.) Need a way to package up a runtime environment into a portable build artifact for deployment to a managed K8s service or a serverless environment like AWS Lambda? Containers are great for this, too!

But not everyone wants to install a resource-intensive container runtime, especially on desktop platforms like macOS and Windows.

If you find yourself nodding along thinking “Yep. I’m one of those people,” Colima is all you need.

Getting It

Let’s first install Flox. If you don’t already have Flox on your system, we’ve made it pretty easy to download, install, and play along at home.

Next, let’s grab Flox’s pre-built Colima example environment. This is shockingly simple:

flox activate -s -r flox/colima

This creates a local copy of the remote Flox environment colima, activates it (with the -r switch, for “remote”), starts the colima service (with the -s switch, for “services”), and puts you in a Flox subshell. When you type exit to quit (or press CTRL + D), this environment disappears and Colima shuts down.

✅ You are now using the environment 'flox/colima (remote)'.
To stop using this environment, type 'exit'
 
                                                     
  ╔═══════════════════════════════════════════════╗  
  ║                                               ║  
  ║    Colima may take a few moments to start.    ║  
  ║                                               ║  
  ║    Once it starts, try it with:               ║  
  ║      docker run hello-world                   ║  
  ║                                               ║  
  ╚═══════════════════════════════════════════════╝

Because Colima needs to spin up a Linux VM with Docker Engine, we do need to give it a moment, even after we see this message. (Moves fingers over keyboard for 30 seconds.) Okay. That should do it.

Note: If you want to bootstrap this yourself, you need to run flox install colima to install it manually.

You’d then need to define a service so Flox knows to start and manage Colima. Just open up the manifest.toml file that lives in .flox/env/ inside your project directory. Look for the [services] section, and add the following:

[services]
colima.command = "colima start"
colima.is-daemon = true
colima.shutdown.command = "colima stop"

Save and exit, then start your local Flox Colima environment using the -s switch:

flox activate -s

You won’t see the welcome message I showed above because you haven’t created logic to display it. 😄

Using it

Let’s suppose I’m containerizing DuckDB because I want to build a Flask-based app that exposes RESTful endpoints for users to interact with it. I’m using an Amazon Linux base image, because that’s what my (hypothetical) org runs in both its AWS Elastic Container Service and Elastic Kubernetes Service deployments.

First, I need to pull my container image from the AWS Elastic Container Registry. But let’s assume I’ve already done that. The next step is building my custom container image using the Dockerfile I’ve created.

Colima spins up a lightweight Linux VM that's configured by default to use Docker Engine. This means I’ve also got to install a Docker client so I can interact with it. My Flox colima example environment already includes this:

flox list
 
colima: colima (0.7.6)
docker: docker-client (docker-27.3.1)
gum: gum (0.14.5)

(Note: If you’re playing along at home and bootstrapping from scratch, just run flox install docker-client.)

Now that I’ve got my Docker client, let’s build my container:

flox [aws-1pass colima] daedalus@askesis:~/dev/colima$ docker build -t duckdb-task-api .
[+] Building 9.3s (10/10) FINISHED                                                                                                                                               docker:colima
 => [internal] load build definition from Dockerfile                                                                                                                                      0.0s
 => => transferring dockerfile: 489B                                                                                                                                                      0.0s
 => [internal] load metadata for public.ecr.aws/amazonlinux/amazonlinux:latest                                                                                                            0.0s
 => [internal] load .dockerignore                                                                                                                                                         0.0s
 => => transferring context: 2B                                                                                                                                                           0.0s
 => [1/5] FROM public.ecr.aws/amazonlinux/amazonlinux:latest                                                                                                                              0.0s
 => [internal] load build context                                                                                                                                                         0.0s
 => => transferring context: 1.83kB                                                                                                                                                       0.0s
 => [2/5] RUN yum update -y &&     yum install -y python3 python3-pip &&     yum clean all                                                                                                6.1s
 => [3/5] RUN pip3 install flask duckdb                                                                                                                                                   2.7s
 => [4/5] WORKDIR /app                                                                                                                                                                    0.0s 
 => [5/5] COPY crud.py .                                                                                                                                                                  0.0s 
 => exporting to image                                                                                                                                                                    0.2s 
 => => exporting layers                                                                                                                                                                   0.2s 
 => => writing image sha256:0f68c78630a25d7cbb5edada7a288ec454e0a6ad2818d8930377516d19341626                                                                                              0.0s 
 => => naming to docker.io/library/duckdb-task-api

Alll right. Now I’m ready to fire up and run my container in Colima:

docker run -p 5000:5000 duckdb-task-api
 * Serving Flask app 'crud'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
* Running on http://172.17.0.2:5000

Success! A quick double-check confirms that my container is, in fact, running:

docker ps
CONTAINER ID   IMAGE             COMMAND             CREATED          STATUS          PORTS                                       NAMES
3545e6e5247d   duckdb-task-api   "python3 crud.py"   52 minutes ago   Up 52 minutes   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   sharp_montalcini

It’s one thing to start a container, another to confirm it’s running, and still another to interact with it.

So let’s interact with. Let’s see if it behaves like a RESTful service running in a container should.

curl http://localhost:5000/
Welcome to the DuckDB Trivial Task Management API (TTMA) v0.0.0.314159!

So it’s up, it’s running, and it’s accessible. But can I do the stuff I expect to able to do with it?

curl -X POST -H "Content-Type: application/json" \
-d '{"title": "Cured Global Warming"}' http://localhost:5000/tasks
{"message":"Task created"}
 
curl http://localhost:5000/tasks
[[1,"Cured Global Warming",false],[2,"Cured Global Warming",false]]

Even though I can't change that task's status to true, I’m going to go ahead and call this a successful q.e.d.!

This has been Fun Package Friday(R)(TM)

So that’s Colima. It gives you a simple, lighter-weight VM for running containers on macOS and Windows with WSL. (Colima runs just fine on Linux, too—witness this walk-through!—albeit with one caveat: instead of running natively, your containers run inside a VM.)

Colima is full-stop amazing on its own. But Flox makes it even, um, amazing-er, giving you an easy way to create and share a portable Colima environment for running containers … anywhere. Don’t believe me? Go ahead and flox activate -s -r flox/colima on your system and take it for a spin.

Happy hacking!

Thanks to both Rok Garbas and Ross Turk for building this Colima environment! Collectively, Rok and Ross are Flox’s skunkworks platform engineering team. I’d be verklempt without ‘em!