Why I Started Using This Tool
If you've ever heard a colleague say "it works on my machine" you already know the problem. When I started working on embedded C code, my test suite ran perfectly locally but failed the moment a teammate cloned the repo. Different versions of GCC, different system libraries, missing dependencies. It was a mess and i will need to jump in to troubleshoot.
I needed a way to guarantee that everyone on the team was compiling and testing in exactly the same environment. That's when I started using Docker to run my C test suite, and I haven't looked back since.
What It Does
Docker lets you package a complete build environment, compiler, libraries, tools into a lightweight, portable container. Instead of installing GCC, make, and your testing framework directly on your machine (and hoping everyone else's setup matches), you define the environment once in a file called a Dockerfile, and Docker handles the rest.
Think of it like a separate, lightweight computer living inside your computer, except it starts in seconds, is free to create and throw away, and behaves identically on every machine it runs on.
Important: Docker is designed for CLI-based workflows. It does not support GUI applications โ but for compiling and testing C code, the command line is all you need.
- Consistency โ your test suite runs in the same environment every time, on every machine
- Isolation โ no conflicts with your local toolchain or system libraries
- Reproducibility โ perfect for CI/CD pipelines and onboarding new team members
- Easy reset โ delete a container and spin up a fresh one in seconds
My Honest Pros & Cons
โ What I Love
- Zero environment conflicts โ no more "works on my machine" debugging sessions
- Great for embedded C code โ you can target a specific compiler version that matches your embedded toolchain
- CI/CD ready โ the same Docker setup you use locally can run in GitHub Actions or any other pipeline with no changes
- Free and open source โ Docker Desktop is free for personal and small-team use
โ What Could Be Better
- Initial learning curve โ Docker introduces new concepts (images, containers, volumes) that take a little time to understand
- Not for GUI tools โ if your testing workflow relies on a graphical IDE or debugger UI, Docker won't help there directly
Prerequisites
Before getting started, make sure you have the following:
- Docker Desktop installed on your computer. Download it at https://www.docker.com/products/docker-desktop
- VS Code with the Docker extension installed
- Basic familiarity with Makefiles โ you don't need to be an expert, but you should understand what
makedoes
Key Docker Concepts
Before jumping into the steps, here are three concepts you'll use constantly:
Docker Image A Docker image is a snapshot of a complete environment โ it includes the operating system, installed tools, and any configuration you define. Think of it as the blueprint. You build it once from a Dockerfile.
Docker Container A container is a running instance of an image. You can spin up as many containers as you like from the same image, and they're completely free to create and use. When you're done, just delete it. Nothing is left behind on your actual machine.
Docker Volume A volume is how you connect your local files to the container. Without a volume, the container is isolated and can't see your C source files. With a volume mount, your local project folder appears inside the container โ so you can edit files in VS Code and compile them inside Docker without copying anything manually.
Step-by-Step Setup Guide
1. Write Your Dockerfile
Create a file named Dockerfile in the root of your project. This file defines your build environment.
Here's a minimal example for C development with make and the cmocka unit testing library:
dockerfile
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
gcc \
make \
libcmocka-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /project
This tells Docker to:
- Start from a clean Ubuntu 22.04 base
- Install GCC, Make, and the cmocka testing library
- Set
/projectas the default working directory inside the container
2. Build the Docker Image
Open a terminal in your project root and run:
bash
docker build -t c-test-env .
This reads your Dockerfile and builds an image named c-test-env. You only need to do this once (or whenever you change the Dockerfile).
3. Launch a Container with a Volume Mount
Now run a container from your image, mounting your local project folder into it:
bash
docker run -it --rm -v $(pwd):/project c-test-env
Here's what each flag does:
| Flag | Meaning |
|---|---|
-it |
Interactive mode โ gives you a terminal inside the container |
--rm |
Automatically removes the container when you exit |
-v $(pwd):/project |
Mounts your current local directory into /project inside the container |
You'll land inside the container's terminal, with your C source files visible at /project.
For the full list of
docker runoptions, see the official documentation: Running containers โ Docker Docs
Running Your Test Suite
Once inside the container, navigate to your project (you should already be in /project if you used the Dockerfile above) and run your Makefile targets:
Clean previous build artifacts:
bash
make clean
This removes any previously compiled object files and binaries, ensuring a fresh build.
Build the project:
bash
make build
This compiles your C source files and test files using GCC.
Run the tests:
bash
make test
This executes your compiled test binary and prints the results to the terminal โ pass/fail for each test case.
A typical session looks like this:
bash
$ docker run -it --rm -v $(pwd):/project c-test-env
root@a1b2c3d4:/project# make clean
rm -f build/*
root@a1b2c3d4:/project# make build
gcc -o build/test_runner src/module.c tests/test_module.c -lcmocka
root@a1b2c3d4:/project# make test
./build/test_runner
[==========] Running 4 test(s).
[ PASSED ] 4 test(s).
Pricing: Is It Worth It?
Docker Desktop is free for personal use, open-source projects, and small teams (fewer than 250 employees and under $10M in revenue). For larger commercial teams, paid plans start at a few dollars per user per month.
For the workflow in this post, running C tests locally, the free tier covers everything you need.
My take: For embedded C developers, Docker is essentially free infrastructure that saves hours of environment debugging. It's one of the best value tools in the ecosystem.
Final Verdict
If you're writing C code, especially for embedded systems, and you want your tests to run reliably on every machine without fighting toolchain differences, Docker is the answer. The setup takes about 15 minutes the first time, and from that point on, your test environment is locked, portable, and reproducible.
Who should use this: C and embedded software developers who share code across teams, want to add CI/CD pipelines, or have ever lost time debugging environment issues instead of actual bugs.
Who can skip it: Solo developers working on a single machine who never need to share their build environment, though even then, the reproducibility benefits are worth the small setup cost.