Objective
Walk through the canonical “new deploy is broken, roll back” path.
Tasks
Task 1: Bring up a known-good version
mkdir -p ~/rollback-lab && cd ~/rollback-lab
cat > compose.yml <<'EOF'
services:
web:
image: myorg/web:1.0.0
ports: ["8080:80"]
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost"]
interval: 5s
retries: 3
EOF
# Use a real image as the "good" baseline
sed -i 's/myorg\/web:1.0.0/nginx:1.27/' compose.yml
docker compose up -d
sleep 5
curl -s http://localhost:8080 | head -1
# <!DOCTYPE html>...
docker compose ps
Task 2: Deploy a broken image
sed -i 's/nginx:1.27/myorg/web:does-not-exist/' compose.yml
docker compose up -d
sleep 5
docker compose ps
# web myorg/web:does-not-exist ... Exit 1
docker compose logs web
# Error response from daemon: pull access denied ... or no such image
Task 3: Detect via health
The container is in Exit 1. A monitoring system would alert
here. For the lab, observe the state directly:
docker inspect $(docker compose ps -q web) --format '{{.State.Status}} {{.State.ExitCode}}'
Task 4: Roll back
sed -i 's/myorg\/web:does-not-exist/nginx:1.27/' compose.yml
docker compose up -d
sleep 5
docker compose ps
curl -s http://localhost:8080 | head -1
Task 5: Verify the previous image is the running one
docker compose ps --format json | jq -r '.[].Image'
# nginx:1.27
Cleanup
docker compose down