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.
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
- Install Docker: docker.com/products/docker-desktop
- Practice: Create Dockerfiles for your applications
- Learn Docker Compose: Orchestrate multi-container applications
- Explore Registries: Push images to Docker Hub or private registries
- 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!