The practical Docker reference — containers, images, volumes, networking, docker-compose, and debugging commands you'll actually use every day.
Docker is now a prerequisite for professional development. Whether you're running local databases, packaging apps for deployment, or working with microservices, these are the commands you'll reach for daily.
# Pull an image
docker pull node:20-alpine
docker pull postgres:16
# List local images
docker images
docker image ls
# Build an image
docker build -t myapp:1.0 . # from Dockerfile in current dir
docker build -t myapp:1.0 -f docker/Dockerfile . # from specific file
docker build --no-cache -t myapp . # ignore build cache
# Remove images
docker rmi myapp:1.0
docker image prune # remove dangling (untagged) images
docker image prune -a # remove ALL unused images
# Push to registry
docker tag myapp:1.0 username/myapp:1.0
docker push username/myapp:1.0
# Run a container
docker run node:20-alpine # run and exit
docker run -d nginx # detached (background)
docker run -it ubuntu bash # interactive terminal
docker run --rm alpine echo hello # remove when done
docker run -p 3000:3000 myapp # map host:container port
docker run -p 127.0.0.1:3000:3000 myapp # bind to localhost only
docker run -e NODE_ENV=production myapp # env variable
docker run --env-file .env myapp # env from file
docker run -v $(pwd):/app -w /app node:20 npm test # mount volume
docker run --name mycontainer myapp # custom name
# List containers
docker ps # running
docker ps -a # all (including stopped)
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
# Start/stop/restart
docker start mycontainer
docker stop mycontainer # graceful (SIGTERM, then SIGKILL after 10s)
docker kill mycontainer # immediate (SIGKILL)
docker restart mycontainer
# Remove
docker rm mycontainer
docker rm -f mycontainer # force remove running container
docker container prune # remove all stopped containers
# Execute commands inside a running container
docker exec -it mycontainer bash
docker exec -it mycontainer sh # if no bash
docker exec mycontainer ls /app
# View logs
docker logs mycontainer
docker logs -f mycontainer # follow (tail)
docker logs --tail 100 mycontainer # last 100 lines
docker logs --since 1h mycontainer # since 1 hour ago
# Inspect container
docker inspect mycontainer
docker inspect mycontainer | jq '.[0].NetworkSettings.IPAddress'
# Resource usage
docker stats # live stats for all containers
docker stats mycontainer
docker top mycontainer # processes inside
# Copy files
docker cp mycontainer:/app/config.json ./config.json
docker cp ./local.txt mycontainer:/app/
# Named volumes (persisted, managed by Docker)
docker volume create pgdata
docker run -v pgdata:/var/lib/postgresql/data postgres:16
# Bind mounts (host directory → container)
docker run -v /host/path:/container/path myapp
docker run -v $(pwd):/app myapp # current directory
# Volume management
docker volume ls
docker volume inspect pgdata
docker volume rm pgdata
docker volume prune # remove unused volumes
# docker-compose.yml
version: '3.9'
services:
app:
build: .
ports:
- '3000:3000'
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/mydb
depends_on:
db:
condition: service_healthy
volumes:
- .:/app
- /app/node_modules # prevent overwriting node_modules
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: password
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 5s
timeout: 5s
retries: 5
volumes:
pgdata:
docker compose up -d # start all services in background
docker compose down # stop and remove containers
docker compose down -v # also remove volumes
docker compose logs -f app # follow logs for 'app' service
docker compose exec app bash # shell into 'app' service
docker compose ps # status of all services
docker compose build --no-cache # rebuild images
docker compose pull # pull latest images
# Nuclear option — remove everything
docker system prune -a --volumes
# More surgical
docker container prune # stopped containers
docker image prune -a # unused images
docker volume prune # unused volumes
docker network prune # unused networks
# Check disk usage
docker system df
# Use specific version tags, not 'latest'
FROM node:20.11-alpine
# Set working directory
WORKDIR /app
# Copy dependency files first (better layer caching)
COPY package.json package-lock.json ./
RUN npm ci --only=production
# Then copy source (changes frequently → later layer)
COPY . .
# Run as non-root user
RUN adduser -D appuser
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]