</>StackKit
</>StackKit

Developer tutorials & guides

Docker whale logo with containers
Docker

Docker for Developers: Getting Started in 2025

Learn Docker from scratch — containers, images, Dockerfile, docker-compose, and how to containerize a real Node.js application step by step.

M
Marcus Lee
April 20, 202510 min read
#docker#containers#devops#nodejs

What Is Docker and Why Should You Care?

Docker is a platform that packages your application and all its dependencies into a container — a lightweight, portable, self-sufficient unit. The famous promise: "it works on my machine" becomes "it works everywhere."

Before Docker, deploying apps meant wrestling with environment differences between development, staging, and production. With Docker, you ship the environment alongside the app.


Core Concepts

Image — A read-only blueprint. Like a class in OOP. Container — A running instance of an image. Like an object. Dockerfile — A script of instructions to build an image. Registry — A storage hub for images (Docker Hub, GitHub Container Registry).


Installing Docker

Download Docker Desktop from docker.com for macOS or Windows. On Linux:

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

Verify:

docker --version
docker run hello-world

Your First Dockerfile

Let's containerize a simple Node.js Express app.

app.js:

const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello from Docker!'));
app.listen(3000);

Dockerfile:

# Base image
FROM node:20-alpine

# Set working directory inside container
WORKDIR /app

# Copy package files first (layer caching)
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production

# Copy rest of the app
COPY . .

# Expose port
EXPOSE 3000

# Run the app
CMD ["node", "app.js"]

Build and run:

docker build -t my-node-app .
docker run -p 3000:3000 my-node-app

Visit http://localhost:3000 — your app is running in a container.


Essential Docker Commands

docker images              # list images
docker ps                  # running containers
docker ps -a               # all containers (including stopped)
docker stop <id>           # stop a container
docker rm <id>             # remove container
docker rmi <image>         # remove image
docker logs <id>           # view container logs
docker exec -it <id> sh    # shell into running container

Docker Compose — Multi-Container Apps

Most real apps need multiple services: a web server, a database, a cache. docker-compose orchestrates them together.

docker-compose.yml:

version: '3.9'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/myapp
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    volumes:
      - pg_data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: myapp

volumes:
  pg_data:
docker compose up -d      # start all services in background
docker compose logs -f    # tail logs from all services
docker compose down       # stop and remove containers

.dockerignore

Always add a .dockerignore to prevent bloating your image:

node_modules
.git
.env
*.log

Multi-Stage Builds (Production Best Practice)

Reduce image size dramatically by only including what's needed in the final image:

# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]

Conclusion

Docker is one of those tools that changes how you think about software. Once you containerize your first real app, you'll never want to go back to manual environment setup. Start with the Dockerfile, graduate to docker-compose, and you'll cover 90% of what most developers need day-to-day.

#docker#containers#devops#nodejs