
5 Docker Projects That Will Actually Make You Better at Docker in 2026
Jonas ScholzMost people learn Docker by copying a Dockerfile, running docker compose up, and hoping the build stays green.
That is fine for day one. But if you want Docker to stop feeling like magic, you need projects that force you to touch the parts people usually skip: layers, image size, build cache, networking, security, and deployment.
As a Docker Captain and co-founder of Sliplane, I have seen the same pattern again and again: developers can run containers, but they get stuck when something is slow, insecure, too large, or weird in production.
These five projects are meant to fix that.
1. Shrink a real Docker image until it hurts
Pick an app you already know. A Next.js app, a FastAPI API, a Rails app, a Go service, anything.
Your goal: make the production image as small as possible without breaking the app.
Start with the boring version:
FROM node:24-bookworm
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
CMD ["npm", "start"]
Then improve it:
- Use a multi-stage build
- Copy only the build output into the final image
- Remove dev dependencies
- Compare Debian slim, Alpine, distroless, and scratch where they make sense
- Check what changed with
docker history - Inspect the filesystem with a tool like
dive
You will learn why images become huge, why COPY . . can be expensive, how build cache works, and why "smallest possible" is not always the same as "best for production".
Current note for 2026: do not blindly switch everything to Alpine. Smaller is nice, but native modules, libc differences, debugging, and security update flow matter too.
2. Build one image for AMD64 and ARM64
In 2026, multi-arch is not optional anymore. Your laptop might be ARM64. Your server might be AMD64. Your CI runner might be different again.
Take a small web app and make one image that works on both common architectures.
Try this flow:
IMAGE="ttl.sh/docker-skill-lab-$(date +%s):1h"
docker buildx create --use
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t "$IMAGE" \
--push \
.
docker buildx imagetools inspect "$IMAGE"
Then pull and run the image on a different architecture than the one you built it on.
You will learn:
- What
buildxactually does - Why emulation can be slow
- Which dependencies ship native binaries
- Why official base images usually support multiple architectures
- Why "works on my machine" often means "works on my CPU"
Bonus round: build the same app with GitHub Actions and compare local vs CI build speed.
3. Break and fix a Docker Compose network
Docker networking feels simple until it does not.
Create a Compose app with three services:
webapipostgres
Then intentionally break it.
Examples:
services:
web:
image: nginx:1.29
ports:
- "8080:80"
api:
build: ./api
environment:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/app
postgres:
image: postgres:18
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: app
The bug is subtle if you are new to Docker: localhost inside the api container points to the api container itself, not to Postgres. The service name should be the hostname:
postgres://postgres:postgres@postgres:5432/app
Now keep going:
- Remove a port and see what is still reachable between containers
- Add a custom network
- Run
docker network inspect - Add a healthcheck for Postgres
- Make the API wait for the database properly
This project will save you hours later. Networking bugs are where Docker stops feeling cute.
4. Run untrusted code and try to lock it down
Imagine your app lets users upload code and run it in a container. Sounds useful. Also terrifying.
Build a tiny runner service that executes a submitted script in a container. Then try to make it safer.
Things to test:
- Run as a non-root user
- Drop Linux capabilities
- Make the filesystem read-only
- Limit CPU and memory
- Disable privilege escalation
- Use a temporary working directory
- Avoid mounting the Docker socket
Example flags to explore:
docker run --rm \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges \
--memory=256m \
--cpus=0.5 \
--tmpfs /tmp:rw,noexec,nosuid,size=16m \
--user=1000:1000 \
alpine:3.22 \
sh -c 'id && touch /tmp/test'
Then try to break your own setup.
This teaches a painful but important lesson: Docker is a container runtime, not a complete sandbox for hostile code. You can reduce risk, but serious untrusted-code execution needs stronger isolation and a real threat model.
5. Ship one container from laptop to production
The final project is simple: deploy something real.
Not a toy container that prints "hello world". A small app with:
- A production Dockerfile
- A healthcheck
- Environment variables
- Logs to stdout
- A persistent volume if needed
- A database connection if needed
- A clear update path
Build it locally:
docker build -t my-app:2026 .
docker run --rm -p 3000:3000 my-app:2026
Then deploy the same app somewhere outside your laptop. Use a VPS with Docker Compose, Kubernetes if you are practicing clusters, or Sliplane if you want the Docker deploy without server maintenance.
This project connects all the others. You will find out whether your image is too large, whether your config is hardcoded, whether your logs are useful, whether your app shuts down cleanly, and whether your "production" command actually works.
Bonus project: Skip the Docker CLI for one build
Docker is the friendly frontend. Underneath it are BuildKit, containerd, runc, OCI images, registries, and a lot of specs.
For one afternoon, skip the usual path:
- Build with
buildctl - Inspect an OCI image layout
- Push to a registry without
docker push - Read the image manifest
- Compare the digest locally and remotely
You do not need this every day. But once you see the layers underneath Docker, debugging gets much easier.
Conclusion
If you finish these projects, Docker will feel less like a black box.
You will understand why builds are slow, why images are large, why networking breaks, why security flags matter, and what changes when a container leaves your laptop.
That is the real skill. Not memorizing commands. Knowing what is happening when the command lies to you.
Want a more direct path from learning to shipping? Read how to use Docker Compose, then deploy a real container on Sliplane.