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)

requirements.txt

Flask==2.3.0

❌ 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

Tasks

1. Troubleshoot the Build

Run:

docker build -t broken-app .

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

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"]

Target: < 150MB image size βœ…

4. Security Hardening

# Run as non-root
USER 1001

Run with a read-only filesystem:

docker run --read-only --tmpfs /tmp myapp:latest

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

2. Write Data Inside the Container

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

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

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

5. Verify Persistence

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

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

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

Tasks

1. Run the Stack

docker compose up

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

3. Fix depends_on with a Condition

web:
  depends_on:
    postgres:
      condition: service_healthy

Now your web service won’t start until Postgres passes its healthcheck. βœ…

4. Move Secrets to .env

.env

POSTGRES_PASSWORD=secret

docker-compose.yml

environment:
  - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}

5. Keep Secrets Out of Git

.gitignore

.env

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

2. Install Trivy

brew install aquasecurity/trivy/trivy

Or on Linux:

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

3. Scan the Image

trivy image nginx:1.21.0

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

Or go even lighter:

FROM nginx:alpine

5. Rescan

trivy image nginx:1.25-bookworm

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
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 βœ…

Monitor resource usage live:

docker stats

4. Export the Image

docker save -o myapp.tar myapp:latest

5. Simulate an Offline Machine

docker rmi myapp:latest

6. Restore the Image

docker load -i myapp.tar

7. Run Without Internet

docker run myapp:latest

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.