DEV Community

Cover image for 5 Docker Scenarios Every Developer Should Practice (With Fixes & Best Practices)
MysticMc
MysticMc

Posted on

5 Docker Scenarios Every Developer Should Practice (With Fixes & Best Practices)

So you know the basics of Docker — docker run, docker build, maybe some docker compose up. But do you know what happens when things break?

This guide walks you through 5 real-world Docker scenarios that will sharpen your skills around debugging, security, storage, and production-readiness.


Scenario 1: The Broken Build 🔨

Goal

Fix a broken Dockerfile, then optimize it to be 10x smaller and production-ready.

Setup

app.py

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello from Docker!"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
Enter fullscreen mode Exit fullscreen mode

requirements.txt

Flask==2.3.0
Enter fullscreen mode Exit fullscreen mode

❌ The Broken Dockerfile

FROM ubuntu:latest

RUN apt-get update
RUN apt-get install python3

COPY . /opt/app
RUN pip install -r requirements.txt

USER root

CMD python /opt/app/app.py
Enter fullscreen mode Exit fullscreen mode

Tasks

1. Troubleshoot the Build

Run:

docker build -t broken-app .
Enter fullscreen mode Exit fullscreen mode

There are at least 3 issues hiding in that Dockerfile:

  • pip is never installed
  • apt-get install is missing the -y flag (hangs waiting for input)
  • COPY happens before dependency install — busting the cache on every change

2. Fix Layer Caching

Copy requirements.txt first, install deps, then copy the rest of the app. This way, changing app.py won't trigger a full pip install on every build.

COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . /opt/app
Enter fullscreen mode Exit fullscreen mode

3. Optimize the Image

Switch from ubuntu:latest to a slim base:

FROM python:3.12-slim

WORKDIR /opt/app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000
CMD ["python", "app.py"]
Enter fullscreen mode Exit fullscreen mode

Target: < 150MB image size ✅

4. Security Hardening

# Run as non-root
USER 1001
Enter fullscreen mode Exit fullscreen mode

Run with a read-only filesystem:

docker run --read-only --tmpfs /tmp myapp:latest
Enter fullscreen mode Exit fullscreen mode

Scenario 2: The Ghost Data 👻

Goal

Understand Docker's storage lifecycle and how to make data actually persist.

Tasks

1. Run an Ephemeral Container

docker run -d --name web-test -p 8080:80 nginx
Enter fullscreen mode Exit fullscreen mode

2. Write Data Inside the Container

docker exec -it web-test bash
echo "hello" > /usr/share/nginx/html/test.txt
Enter fullscreen mode Exit fullscreen mode

Visit http://localhost:8080/test.txt — it's there!

3. Destroy & Recreate

docker stop web-test
docker rm web-test
docker run -d --name web-test2 -p 8080:80 nginx
Enter fullscreen mode Exit fullscreen mode

The file is gone. Why?

Because the container filesystem is ephemeral — it only lives as long as the container does.

4. Named Volume Persistence

docker volume create web-data

docker run -d \
  --name web-test \
  -p 8080:80 \
  -v web-data:/usr/share/nginx/html \
  nginx
Enter fullscreen mode Exit fullscreen mode

5. Verify Persistence

docker exec -it web-test bash
echo "persistent data" > /usr/share/nginx/html/test.txt
Enter fullscreen mode Exit fullscreen mode

Stop and remove the container, then start a new one with the same volume — your file will still be there. 🎉

6. Cleanup

docker system prune -f
Enter fullscreen mode Exit fullscreen mode

Note: system prune removes stopped containers, dangling images, and unused networks — but not named volumes unless you add --volumes.


Scenario 3: The Flaky Database Connection 🐘

Goal

Fix service startup dependency issues in Docker Compose.

The Broken docker-compose.yml

version: '3'

services:
  web:
    build: .
    ports:
      - "5000:5000"
    environment:
      - DB_HOST=postgres
    depends_on:
      - postgres

  postgres:
    image: postgres:15
    environment:
      - POSTGRES_PASSWORD=secret
Enter fullscreen mode Exit fullscreen mode

Tasks

1. Run the Stack

docker compose up
Enter fullscreen mode Exit fullscreen mode

The problem: depends_on only waits for the container to start, not for Postgres to be ready to accept connections. Your web app crashes on startup.

2. Add a Healthcheck to Postgres

postgres:
  image: postgres:15
  environment:
    - POSTGRES_PASSWORD=secret
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U postgres"]
    interval: 5s
    timeout: 5s
    retries: 10
Enter fullscreen mode Exit fullscreen mode

3. Fix depends_on with a Condition

web:
  depends_on:
    postgres:
      condition: service_healthy
Enter fullscreen mode Exit fullscreen mode

Now your web service won't start until Postgres passes its healthcheck. ✅

4. Move Secrets to .env

.env

POSTGRES_PASSWORD=secret
Enter fullscreen mode Exit fullscreen mode

docker-compose.yml

environment:
  - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
Enter fullscreen mode Exit fullscreen mode

5. Keep Secrets Out of Git

.gitignore

.env
Enter fullscreen mode Exit fullscreen mode

Never commit .env files. Ever.


Scenario 4: The Evil Image Scanner 🔍

Goal

Find and fix vulnerabilities hiding in your Docker images.

Tasks

1. Build a Vulnerable Image

FROM nginx:1.21.0
Enter fullscreen mode Exit fullscreen mode

2. Install Trivy

brew install aquasecurity/trivy/trivy
Enter fullscreen mode Exit fullscreen mode

Or on Linux:

curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
Enter fullscreen mode Exit fullscreen mode

3. Scan the Image

trivy image nginx:1.21.0
Enter fullscreen mode Exit fullscreen mode

You'll see a wall of HIGH and CRITICAL CVEs. This is what ships to production when nobody checks.

4. Fix the Base Image

FROM nginx:1.25-bookworm
Enter fullscreen mode Exit fullscreen mode

Or go even lighter:

FROM nginx:alpine
Enter fullscreen mode Exit fullscreen mode

5. Rescan

trivy image nginx:1.25-bookworm
Enter fullscreen mode Exit fullscreen mode

Expected: 0 CRITICAL vulnerabilities ✅

Make image scanning part of your CI/CD pipeline — not an afterthought.


Scenario 5: The Limited Resource Box 📦

Goal

Run containers safely under strict resource constraints and enable offline portability.

Tasks

1. Build the Optimized Image

Use the hardened image from Scenario 1.

2. Run with Resource Limits

docker run -d \
  --memory=256m \
  --cpus=0.5 \
  --read-only \
  --tmpfs /tmp \
  myapp:latest
Enter fullscreen mode Exit fullscreen mode
Flag What it does
--memory=256m Hard cap on RAM usage
--cpus=0.5 Limits to half a CPU core
--read-only Prevents filesystem writes
--tmpfs /tmp Mounts writable in-memory temp dir

3. Verify the Restrictions

docker exec -it <container_id> bash
touch /etc/test
# Permission denied ✅
Enter fullscreen mode Exit fullscreen mode

Monitor resource usage live:

docker stats
Enter fullscreen mode Exit fullscreen mode

4. Export the Image

docker save -o myapp.tar myapp:latest
Enter fullscreen mode Exit fullscreen mode

5. Simulate an Offline Machine

docker rmi myapp:latest
Enter fullscreen mode Exit fullscreen mode

6. Restore the Image

docker load -i myapp.tar
Enter fullscreen mode Exit fullscreen mode

7. Run Without Internet

docker run myapp:latest
Enter fullscreen mode Exit fullscreen mode

Works fully offline. 🚀 Great for air-gapped environments, demos, or CI runners without registry access.


What You've Learned 🎓

After completing all five scenarios, you now have hands-on experience with:

  • Dockerfile debugging & optimization — fixing real build errors and shrinking image sizes
  • Layer caching strategies — speeding up builds without reinstalling dependencies
  • Volume persistence — understanding ephemeral vs. persistent storage
  • Compose healthchecks — preventing race conditions between services
  • Image vulnerability scanning — catching CVEs before they reach production
  • Runtime security hardening — non-root users, read-only filesystems, resource limits
  • Offline container portability — shipping containers without a registry

Want more? Drop a comment and I can turn this into a full GitHub repo with solutions, or expand each scenario into its own deep-dive post.


Enter fullscreen mode Exit fullscreen mode

Top comments (0)