To understand the relationship between Docker Run and Docker Compose, and compare their syntax and use cases.
Example:
docker run -d \
--name my-nginx \
-p 8080:80 \
-v ./html:/usr/share/nginx/html \
-e NGINX_HOST=localhost \
--restart unless-stopped \
nginx:alpine
docker-compose.yml to define services, networks, and volumes in a single file.docker compose up -d) runs everything.Equivalent Compose File:
version: '3.8'
services:
nginx:
image: nginx:alpine
container_name: my-nginx
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
environment:
NGINX_HOST: localhost
restart: unless-stopped
| Docker Run | Docker Compose |
|---|---|
-p |
ports |
-v |
volumes |
-e |
environment |
--name |
container_name |
--network |
networks |
--restart |
restart |
--memory |
deploy.resources.limits.memory |
--cpus |
deploy.resources.limits.cpus |
docker compose up --scale web=3)docker run -d --name lab-nginx -p 8081:80 -v $(pwd)/html:/usr/share/nginx/html nginx:alpine
curl http://localhost:8081

docker-compose.yml
version: '3.8'
services:
nginx:
image: nginx:alpine
container_name: lab-nginx
ports:
- "8081:80"
volumes:
- ./html:/usr/share/nginx/html
docker compose up -d
docker compose ps

docker network create wp-net
docker run -d --name mysql --network wp-net -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=wordpress mysql:5.7
docker run -d --name wordpress --network wp-net -p 8082:80 -e WORDPRESS_DB_HOST=mysql -e WORDPRESS_DB_PASSWORD=secret wordpress:latest

(Note: The equivalent steps in Compose are demonstrated in Experiment 6B below).
Converting manual docker run commands and configurations into declarative docker-compose.yml configurations:
Given Run Command:
docker run -d --name webapp -p 5000:5000 -e APP_ENV=production -e DEBUG=false --restart unless-stopped node:18-alpine
Converted Compose File:
version: '3.8'
services:
webapp:
image: node:18-alpine
container_name: webapp
ports:
- "5000:5000"
environment:
APP_ENV: production
DEBUG: false
restart: unless-stopped
Compose clearly organizes dependencies, limits, and custom named networks natively without extra CLI scaffolding. (See lab theory notes for full limit syntax using deploy:).
We can combine custom image building with Compose orchestration.
app.js
const http = require('http');
http.createServer((req, res) => {
res.end("Docker Compose Build Lab");
}).listen(3000);
Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY app.js .
EXPOSE 3000
CMD ["node", "app.js"]
docker-compose.yml
version: '3.8'
services:
nodeapp:
build:
context: .
dockerfile: Dockerfile
container_name: custom-node-app
ports:
- "3000:3000"
docker compose up --build -d
curl http://localhost:3000

Using a single Compose file completely replaces the manual networking and container execution from Task 2.
docker-compose.yml
version: '3.9'
services:
db:
image: mysql:5.7
container_name: wordpress_db
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: wordpress
MYSQL_USER: wpuser
MYSQL_PASSWORD: wppass
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:latest
container_name: wordpress_app
depends_on:
- db
ports:
- "8080:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: wppass
WORDPRESS_DB_NAME: wordpress
volumes:
- wp_data:/var/www/html
volumes:
db_data:
wp_data:
docker compose up -d
docker ps

docker compose up --scale wordpress=3

Important Learning Outcome: The scaling intentionally throws an error because standard Docker Compose is limited here. Since
container_name: wordpress_appandports: "8080:80"are hardcoded in the file, Compose cannot launch 3 replicas that all want the identical name and host port. This demonstrates the exact scenario where Docker Swarm (which handles dynamic naming and load balances identical ports) becomes necessary for production!
| Feature | Compose | Swarm |
|---|---|---|
| Scope | Single host | Multi-node |
| Scaling | Manual / Limited by port bindings | Built-in |
| Load balancing | No | Yes |
| Self-healing | No | Yes |
docker run flags.| Previous | Home | Next |
|---|---|---|
| ← Lab 5 | Main README | — |