Docker for Developers: Containers, Images, and Compose

· 10 min read

Core Concepts

ConceptWhat It IsAnalogy
ImageRead-only template with app + dependenciesA class definition
ContainerRunning instance of an imageAn object (instance of class)
DockerfileInstructions to build an imageA recipe
VolumePersistent storage outside containerAn external hard drive
NetworkCommunication between containersA LAN
RegistryStorage for images (Docker Hub)npm/PyPI for containers

Dockerfile Best Practices

# Good Dockerfile example
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
RUN npm run build

FROM node:22-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
USER node
CMD ["node", "dist/server.js"]

Key practices:

Generate Dockerfiles with our Dockerfile Generator.

Essential Commands

# Build an image
docker build -t myapp:1.0 .

# Run a container
docker run -d -p 3000:3000 --name myapp myapp:1.0

# List running containers
docker ps

# View logs
docker logs -f myapp

# Execute command in running container
docker exec -it myapp sh

# Stop and remove
docker stop myapp && docker rm myapp

# Clean up unused resources
docker system prune -a

# List images with sizes
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

Docker Compose

Docker Compose defines multi-container applications in a single YAML file:

# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - '3000:3000'
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
    depends_on:
      - db
      - redis
    volumes:
      - ./src:/app/src  # Hot reload in development

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - '5432:5432'

  redis:
    image: redis:7-alpine
    ports:
      - '6379:6379'

volumes:
  pgdata:
# Start all services
docker compose up -d

# View logs
docker compose logs -f app

# Rebuild after code changes
docker compose up -d --build

# Stop everything
docker compose down

# Stop and remove volumes (reset data)
docker compose down -v

Generate compose files with our Docker Compose Generator.

Development Tips

TipWhy
Use volumes for source codeHot reload without rebuilding
Use .env filesKeep secrets out of docker-compose.yml
Use health checksEnsure services are ready before dependents start
Use named volumes for dataPersist database data across restarts
Use docker compose watchAuto-rebuild on file changes (Compose v2.22+)

Frequently Asked Questions

Docker vs virtual machines?

Containers share the host OS kernel and start in seconds. VMs include a full OS and take minutes to boot. Containers use less memory and disk. VMs provide stronger isolation.

When should I use Docker Compose vs Kubernetes?

Docker Compose for local development and simple deployments (single server). Kubernetes for production orchestration across multiple servers with auto-scaling, rolling updates, and self-healing.

How do I reduce Docker image size?

Use alpine base images, multi-stage builds, .dockerignore, and minimize layers. A Node.js app can go from 1GB to under 100MB with these techniques.

How do I debug a container?

Use docker exec -it container sh to get a shell. Use docker logs -f for output. Use docker inspect for configuration details.

Related Tools

Dockerfile Generator Docker Compose Nginx Config