Images
docker build -t name:tag .
docker build -t name:tag -f Dockerfile.prod .
docker pull image:tag
docker push image:tag
docker images
docker rmi image:tag
docker image prune -a # remove all unused images
Containers
docker run -d --name app -p 3000:3000 image:tag
docker run -it --rm image:tag sh # ephemeral interactive shell
docker ps # running containers
docker ps -a # all containers
docker stop app && docker rm app
docker logs app -f # follow logs
docker exec -it app sh # shell into running container
docker inspect app
Volumes
docker volume create mydata
docker run -v mydata:/data image
docker run -v $(pwd):/app image # bind mount current dir
docker volume ls
docker volume rm mydata
docker volume prune
Docker Compose
docker compose up -d
docker compose up -d --build # rebuild images
docker compose down
docker compose down -v # also remove volumes
docker compose logs -f service
docker compose exec service sh
docker compose ps
docker compose pull # pull latest images
Networks
docker network ls
docker network create mynet
docker run --network mynet image
docker network inspect mynet
Cleanup
docker system prune # remove stopped containers, dangling images
docker system prune -a --volumes # nuclear option: everything unused
docker container prune
docker image prune
docker volume prune
Useful Patterns
Multi-stage build skeleton
FROM node:24-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:24-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]
Compose with env file
services:
app:
build: .
env_file: .env
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules # anonymous volume to prevent host override
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata: