Docker for Developers: A Practical Guide
Docker for Developers: A Practical Guide
Docker has become essential for modern development. It eliminates 'works on my machine' problems by packaging your application with all its dependencies into containers. This guide covers everything you need to get productive with Docker.
Core Concepts
Before diving in, let's understand the key concepts:
- Image: A read-only template containing instructions for creating a container. Think of it as a class.
- Container: A runnable instance of an image. Think of it as an object instantiated from the class.
- Dockerfile: A script of instructions to build an image. It defines your environment.
- Docker Compose: A tool for defining and running multi-container applications with a YAML file.
- Volume: Persistent storage that survives container restarts. Essential for databases.
- Network: Virtual networks that allow containers to communicate with each other.
Your First Dockerfile
A Dockerfile defines how to build your image. Here's a production-ready example for a Python web app:
# Use an official Python runtime as the base image
FROM python:3.12-slim
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
# Set work directory
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Create non-root user for security
RUN adduser --disabled-password --gecos '' appuser
USER appuser
# Expose port and define startup command
EXPOSE 8000
CMD ["gunicorn", "config.wsgi:application", "-b", "0.0.0.0:8000"]
Why these settings?
PYTHONUNBUFFERED=1 - Ensures Python output is sent straight to terminal (useful for logs)
--no-install-recommends - Minimizes image size by skipping optional packages
rm -rf /var/lib/apt/lists/* - Cleans up apt cache to reduce image size
Non-root user - Security best practice; never run containers as root in production
Docker Compose for Development
Docker Compose lets you define your entire stack in a single file. Here's a complete development setup with a web app, database, and cache:
# docker-compose.yml
services:
web:
build: .
ports:
- "8000:8000"
volumes:
- .:/app # Mount code for hot reload
- /app/.venv # Exclude virtualenv
environment:
- DEBUG=true
- DATABASE_URL=postgres://postgres:postgres@db:5432/app
- REDIS_URL=redis://redis:6379/0
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
command: python manage.py runserver 0.0.0.0:8000
db:
image: postgres:16
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=app
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
Essential Commands
These are the commands you'll use daily:
# Build and start all services
docker compose up --build
# Start in background (detached mode)
docker compose up -d
# View logs (follow mode)
docker compose logs -f web
# Run a command in a running container
docker compose exec web python manage.py migrate
docker compose exec web python manage.py shell
# Run a one-off command (creates new container)
docker compose run --rm web python manage.py test
# Stop all services
docker compose down
# Stop and remove volumes (WARNING: deletes data)
docker compose down -v
# Rebuild a specific service
docker compose build web
# View running containers
docker compose ps
Debugging Tips
# Get a shell inside a running container
docker compose exec web bash
# Inspect container details
docker inspect <container_id>
# View container resource usage
docker stats
# Check why a container exited
docker compose logs web --tail=100
# Remove all stopped containers
docker container prune
# Remove unused images
docker image prune -a
# Nuclear option: clean everything
docker system prune -a --volumes
docker system prune regularly to reclaim disk space. Docker images and build cache can consume tens of gigabytes over time.
Common Issues & Solutions
Click to expand troubleshooting guide
Check what's using it:
lsof -i :8000 or netstat -tulpn | grep 8000Kill the process or change the port mapping in docker-compose.yml
Container can't connect to database
Make sure you're using the service name (e.g., db) not localhost
Check that depends_on and healthcheck are configured correctly
Changes not reflected after code edit
Ensure your volume mount is correct and not being overridden
For some frameworks, you may need to restart the container
Build cache not updating
Use docker compose build --no-cache web
Out of disk space
Run docker system prune -a to clean up unused resources
Best Practices
- Use specific image tags (python:3.12-slim not python:latest)
- Order Dockerfile commands from least to most frequently changing for better caching
- Use .dockerignore to exclude files from the build context
- Never store secrets in images - use environment variables or secrets management
- Use multi-stage builds for smaller production images
- Run containers as non-root users
- Use health checks to ensure services are ready
- Pin your Docker Compose version for reproducibility
Related Posts
Introduction to Machine Learning with Python
Start your ML journey with Python and scikit-learn. Build your first machine learning models with practical examples.
1 min read
Go Language Fundamentals
A comprehensive introduction to the Go programming language. Learn the syntax, patterns, and idioms that make Go unique.
1 min read
PostgreSQL Performance Tuning
Optimize your PostgreSQL database for better performance. Learn configuration tuning, query analysis, and indexing strategies.
1 min read
10 Tailwind CSS Tips You Need to Know
Level up your Tailwind CSS skills with these 10 practical tips. From responsive design to custom configurations, become a Tailwind power user.
1 min read
Comments
Log in to leave a comment.
Log In
Loading comments...