Isaac.

Docker: An Introduction

Docker is a platform that enables developers to automate the deployment, scaling, and management of applications using containerization. Containers are lightweight, portable, and self-sufficient units that package an application and its dependencies together, allowing it to run consistently across different environments.

By EMEPublished: December 6, 2024
dockercontainersdevops

Docker: An Introduction

Docker has revolutionized how developers build, ship, and run applications. In this guide, we'll explore the fundamentals of Docker and containerization.

What is Docker?

Docker is a containerization platform that packages your application and its dependencies into a standardized unit called a container. Think of it as a lightweight virtual machine that runs on any system.

Key Benefits:

  • Consistency: Your app runs the same everywhere
  • Isolation: Apps don't interfere with each other
  • Efficiency: Containers are lightweight and fast
  • Portability: Ship your app anywhere

Core Concepts

Images

A Docker image is a blueprint or template for creating containers. It contains:

  • Application code
  • Runtime environment
  • System libraries
  • Configuration files
  • Environment variables

Images are built from a Dockerfile and can be stored in registries like Docker Hub.

Containers

A container is a running instance of an image. It's:

  • Isolated from the host system
  • Lightweight (megabytes vs. gigabytes for VMs)
  • Ephemeral (created and destroyed as needed)
  • Consistent across environments

Registries

Docker registries store and distribute images:

  • Docker Hub: Public registry (official images)
  • Private registries: Company-hosted registries
  • Cloud registries: AWS ECR, Azure ACR, Google GCR

Your First Dockerfile

Here's a simple example for a Node.js application:

# Use official Node.js image as base
FROM node:18-alpine

# Set working directory
WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy application code
COPY . .

# Expose port
EXPOSE 3000

# Start application
CMD ["npm", "start"]

Dockerfile Instructions

| Instruction | Purpose | |-----------|---------| | FROM | Base image to build upon | | WORKDIR | Set working directory in container | | COPY | Copy files from host to container | | RUN | Execute command during build | | EXPOSE | Document which ports the app uses | | ENV | Set environment variables | | CMD | Default command when container starts | | ENTRYPOINT | Configurable container entry point |

Building and Running

Build an Image

# Basic build
docker build -t my-app:1.0 .

# Build with build arguments
docker build --build-arg ENV=production -t my-app:1.0 .

# Build from a specific Dockerfile
docker build -f Dockerfile.prod -t my-app:1.0 .

Run a Container

# Basic run
docker run my-app:1.0

# Run with port mapping
docker run -p 3000:3000 my-app:1.0

# Run in background
docker run -d -p 3000:3000 my-app:1.0

# Run with environment variables
docker run -e NODE_ENV=production -p 3000:3000 my-app:1.0

# Run with volume mount
docker run -v /host/path:/container/path -p 3000:3000 my-app:1.0

# Run interactively
docker run -it -p 3000:3000 my-app:1.0

Common Docker Commands

Image Commands

# List images
docker images

# Pull image from registry
docker pull node:18

# Remove image
docker rmi image-name:tag

# Tag image
docker tag source-image:tag destination-image:tag

# Push image to registry
docker push username/image-name:tag

# Inspect image
docker inspect image-name:tag

Container Commands

# List running containers
docker ps

# List all containers (including stopped)
docker ps -a

# Stop container
docker stop container-id

# Start container
docker start container-id

# Remove container
docker rm container-id

# View logs
docker logs container-id

# Execute command in running container
docker exec -it container-id bash

# Copy files from container
docker cp container-id:/path/to/file ./local/path

.dockerignore

Similar to .gitignore, the .dockerignore file excludes files from the Docker build context:

node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.DS_Store
dist
build
coverage

This reduces the build context size and speeds up builds.

Best Practices

1. Use Specific Base Image Tags

Bad:

FROM node

Good:

FROM node:18-alpine

2. Minimize Layer Count

Bad:

RUN apt-get update
RUN apt-get install -y git
RUN apt-get install -y curl

Good:

RUN apt-get update && apt-get install -y git curl

3. Use .dockerignore

Exclude unnecessary files to reduce build context and improve security.

4. Order Instructions by Frequency of Change

FROM node:18-alpine
WORKDIR /app

# Copy only package files (changes less frequently)
COPY package*.json ./
RUN npm install

# Copy application code (changes more frequently)
COPY . .

EXPOSE 3000
CMD ["npm", "start"]

This leverages Docker's layer caching for faster rebuilds.

5. Run as Non-Root User

# Create and use a non-root user
RUN useradd -m appuser
USER appuser

6. Keep Images Small

  • Use alpine or slim base images
  • Multi-stage builds for applications
  • Remove build tools in production images

7. Avoid Using Latest Tag

# Specify versions explicitly
FROM node:18.16.1-alpine

Multi-Stage Builds

Multi-stage builds reduce final image size by building in one stage and running in another:

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

# Runtime stage
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package*.json ./
EXPOSE 3000
CMD ["node", "dist/index.js"]

Docker Compose (Quick Introduction)

Docker Compose runs multiple containers as a service. Here's a simple example:

version: '3.8'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgres://user:password@db:5432/myapp
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Run with:

docker-compose up

Troubleshooting

Container Exits Immediately

Check logs:

docker logs container-id

Permission Denied

Run as non-root user or use sudo:

docker run -u appuser image-name

Out of Disk Space

Clean up unused images and containers:

docker system prune
docker system prune -a  # Also remove unused images

Next Steps

  1. Install Docker: docker.com/products/docker-desktop
  2. Practice: Create Dockerfiles for your applications
  3. Learn Docker Compose: Orchestrate multi-container applications
  4. Explore Registries: Push images to Docker Hub or private registries
  5. Study Production Deployment: Kubernetes, Docker Swarm, cloud platforms

Resources

Conclusion

Docker simplifies application packaging and deployment. Master containerization to:

  • Deploy consistently across environments
  • Simplify development workflows
  • Scale applications efficiently
  • Improve collaboration between teams

Start small, build containers for your projects, and gradually expand your Docker knowledge!