Docker for Developers: Images, Containers, and Compose
You've probably heard about Docker and how it can simplify your development workflow. But when you first encounter terms like images, containers, and Docker Compose, it can feel overwhelming. This guide cuts through the noise and shows you exactly how to use Docker effectively in your projects.
What is Docker and Why Should You Care?
Docker is a platform that packages your application and its dependencies into a standardized unit called a container. Containers are lightweight, portable, and isolated from each other. They solve the classic "it works on my machine" problem by ensuring your app runs the same way everywhere.
Unlike virtual machines, containers share the host OS kernel, making them faster to start and more efficient. This is why Docker has become a staple in modern development and deployment pipelines.
Images vs. Containers: The Building Blocks
An image is a read-only template that contains your application code, runtime, libraries, and settings. A container is a running instance of an image. Think of an image as a class and a container as an object.
You create images using a Dockerfile. Here's a simple example for a Node.js app:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Each line in the Dockerfile creates a layer. Layers are cached, so rebuilds are faster when only later steps change.
Common Docker Commands
docker build -t my-app .— build an image from the current directorydocker run -p 3000:3000 my-app— run a container and map portsdocker ps— list running containersdocker stop <container_id>— stop a containerdocker rmi <image_id>— remove an image
Docker Compose: Managing Multi-Container Apps
Real-world apps often need more than one service: a web server, a database, a cache. Docker Compose lets you define and run multi-container applications with a single YAML file.
Here's a docker-compose.yml for a Node.js app with PostgreSQL and Redis:
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
- REDIS_URL=redis://cache:6379
depends_on:
- db
- cache
db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
cache:
image: redis:7
volumes:
pgdata:
Run docker compose up and all services start together. The depends_on ensures the database and cache start before the web service.
Key Compose Commands
docker compose up -d— start all services in detached modedocker compose down— stop and remove containers, networksdocker compose logs -f web— follow logs for a specific servicedocker compose exec web sh— open a shell inside a running container
Best Practices for Development
- Use .dockerignore to exclude node_modules, .git, and other unnecessary files from the build context.
- Keep images small by using Alpine-based images and multi-stage builds.
- Don't run as root — create a non-root user in your Dockerfile for security.
- Use volumes for persistent data and bind mounts for live code reloading during development.
- Pin versions in your Dockerfile and Compose file to avoid unexpected updates.
When to Use Docker (and When Not To)
Docker shines when you need consistent environments across teams, easy dependency management, or microservices. It might be overkill for simple static sites or scripts. Evaluate based on your project's complexity and deployment needs.
FAQ
What is the difference between an image and a container?
An image is a static template; a container is a running instance of that image. You can run multiple containers from the same image.
Do I need Docker Compose for a single container?
No, for a single container you can use docker run. Compose is useful when you have multiple services that need to communicate.
How do I persist data in Docker?
Use volumes or bind mounts. Volumes are managed by Docker and are ideal for databases; bind mounts map a host directory into the container, useful for development.
Ready to optimize your Dockerized apps? If you're working with Nginx logs inside containers, try our Nginx Log Analyzer to parse and analyze logs quickly.