DevOps Lesson 4: Docker
Docker packages your app and ALL its dependencies into a container. “Works on my machine” becomes “works everywhere.” The most important DevOps skill.
Key Concepts
// Image: blueprint (like a class)
// Container: running instance (like an object)
// Dockerfile: recipe for building an image
// Registry: storage for images (Docker Hub, ECR, GCR)
Dockerfile
# Dockerfile
FROM node:20-alpine # base image
WORKDIR /app # set working directory
COPY package*.json ./ # copy package files
RUN npm install # install dependencies
COPY . . # copy source code
RUN npm run build # build app
EXPOSE 3000 # document the port
CMD ["node", "dist/app.js"] # start command
Docker Commands
# Build image
docker build -t myapp:1.0 .
# Run container
docker run -p 3000:3000 myapp:1.0
docker run -d --name myapp -p 3000:3000 myapp:1.0 # detached
# Manage containers
docker ps # list running
docker ps -a # list all (including stopped)
docker logs myapp # view logs
docker exec -it myapp sh # shell into running container
docker stop myapp
docker rm myapp
# Images
docker images
docker rmi myapp:1.0
docker pull nginx:latest
docker push myapp:1.0 # push to registry
Multi-stage Build
# Smaller production image
FROM node:20 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
# Final stage: only runtime
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/app.js"]
# Result: 200MB instead of 1GB!
🏋️ Practice Task
Dockerize your Node.js API from the Node.js course. Write a Dockerfile. Build the image. Run it. Verify /api/tasks works at localhost:3000. Use multi-stage build to minimize image size. Check: docker images to see the size difference.
💡 Hint: docker build -t tasks-api . && docker run -p 3000:3000 tasks-api. Then curl http://localhost:3000/api/tasks