What is the need for Docker Compose? #
Running Individual Containers is Repetitive
- Microservices have complex needs: When developing microservices, we often need to run multiple containers together—e.g., a frontend, backend service, database, and other dependencies.
- Repetitive: Running each container individually using
docker runis repetitive and error-prone- Create and manage shared networks, volumes, ..
- Launch individual containers
- Define and maintain environment variables, port mappings, and restart policies
- Set up service dependencies
Example for Two Microservices
Let’s consider two services: currency-exchange and currency-conversion.
currency-exchange: The Currency Exchange Service provides exchange rates for currency pairs—for example, it can tell you that 1 USD equals 60 INR.currency-conversion: The Currency Conversion Service uses these rates to calculate conversions (e.g., 10 USD = 600 INR) by calling the Currency Exchange Service and multiplying the result based on the requested quantity.- You want to launch both the services on your local machine
💡 Explore the Microservices project with detailed guides
Create a Docker Network
docker network create currency-compose-network
Run currency-exchange Container
docker run -d \
--name currency-exchange \
--network currency-compose-network \
-p 8000:8000 \
--restart always \
in28min/currency-exchange:0.0.1-RELEASE
Run currency-conversion Container
docker run -d \
--name currency-conversion \
--network currency-compose-network \
-p 8100:8100 \
--restart always \
-e CURRENCY_EXCHANGE_SERVICE_HOST=http://currency-exchange \
in28min/currency-conversion:0.0.1-RELEASE
Clean-up Commands
docker stop currency-conversion currency-exchange
docker rm currency-conversion currency-exchange
docker network rm currency-compose-network
Docker Compose Makes it Simple
- Declarative Approach: Provides a declarative approach to managing multi-container applications.
- Single YAML file with definitions: Define services, networks, volumes, dependencies, and environment variables in one
docker-compose.ymlfile - Easy Command to Launch: Bring up the entire stack with a single command:
docker compose up - Easy Command to Tear Down: Tear everything down cleanly:
docker compose down - Version Controlled: Maintain a version-controlled setup
- Ensure Consistency: Ensure consistent, reproducible deployments
- Easily Shareable: Easily share your setup with teammates
Summary: Without vs With Compose
| Task | Manual Docker Commands | Docker Compose |
|---|---|---|
| Create Network (Or Volume, ..) | docker network create |
Declared in YAML |
| Start Containers | Multiple docker run |
docker compose up |
| Set Environment Variables | -e flags |
environment: section |
| Manage Dependencies | Manual order handling | depends_on: |
| Clean Up | stop, rm, network rm |
docker compose down |
| Maintain Consistency | Error-prone | Version-controlled YAML |
How is Docker Compose different from Docker Swarm or Kubernetes? #
Docker Compose vs Docker Swarm vs Kubernetes
- Docker Compose: For local development, testing, and simple setup on a single host.
- Easy local multi-container orchestration
- Use Case: Developers running microservices on their laptop
- Docker Swarm: For lightweight container orchestration across multiple machines
- Docker-native clustering/orchestration
- Use Case: Small-to-medium-scale production deployments where full Kubernetes is overkill (Very rarely used these days!)
- Kubernetes: Enterprise-grade container orchestration at scale.
- Multi-cloud and hybrid deployment support
- Use Case: Large-scale production environments where reliability, scaling, and flexibility are critical
Comparison Table
| Feature / Tool | Docker Compose | Docker Swarm | Kubernetes |
|---|---|---|---|
| Deployment Scope | Single host | Multi-host (cluster) | Multi-host, multi-cloud (cluster) |
| Complexity | Low | Medium | High |
| Orchestration Support | ❌ | ✅ | ✅✅ |
| Ecosystem | Minimal | Limited | Rich and Extensible |
| Learning Curve | Easy | Moderate | Steep |
| Use Case | Local Dev | Lightweight Prod | Enterprise Production |
| Community Adoption | High (developers) | Very low | Very High |
Explain docker-compose.yml, with an example #
docker-compose.yml
- docker-compose.yml: A YAML file where you configure the services that make up your application
- Run Multiple Containers: Enables you to run multiple Docker containers as a single application
Example 1: docker-compose.yml
services:
currency-exchange:
image: in28min/currency-exchange:0.0.1-RELEASE
ports:
- "8000:8000"
restart: always
networks:
- currency-compose-network
currency-conversion:
image: in28min/currency-conversion:0.0.1-RELEASE
ports:
- "8100:8100"
restart: always
environment:
CURRENCY_EXCHANGE_SERVICE_HOST: http://currency-exchange
depends_on:
- currency-exchange
networks:
- currency-compose-network
# Networks to be created to facilitate communication between containers
networks:
currency-compose-network:
Understand it:
services: Heart of the Docker Compose file. Defines all the containers that will be run.services > container_name > image: Uses the specified docker image from Docker Hub or a local registry.services > container_name > ports: Similar to-pflagservices > container_name > restart: always: Ensures container automatically restarts if it crashes or host rebootsservices > container_name > networks: Connects this service to the shared network so it can be discovered by others (e.g., currency-conversion).services > container_name > depends_on: Tells Docker Compose to start currency-exchange before this service. (Note: doesn’t wait for service to be ready—just started.)services > container_name > environment: Sets an env variable so the service knows where to contact the currency-exchange microservice. Uses Docker DNS-based service discovery (i.e., http://currency-exchange).
networks: Defines a custom user-defined bridge networkvolumes: Defines a custom user-defined volume
Run it:
# Build and Run the Microservices
docker compose up
# Accessing the Microservices
# Currency Exchange API:
curl http://localhost:8000/currency-exchange/from/USD/to/INR
# Currency Conversion API
curl http://localhost:8100/currency-conversion/from/USD/to/INR/quantity/10
# Stopping and Cleaning Up
docker compose down
Another Example: With MySQL Database
- What?: Demonstrates a typical web application and database setup using Docker Compose
- todo-web-application: A Java-based web app that connects to a MySQL database using environment variables.
- mysql: A MySQL container that stores todos data and credentials defined via environment variables.
Notes
- depends_on: The
depends_onentry ensures that mysql starts before the web application. - mysql-database-data-volume: Ensures data persistence
- Your database files will be retained across container restarts
- Environment Configuration
- mysql: Bootstraps DB, user, and password on startup
MYSQL_ROOT_PASSWORD: Sets the root (admin) password for MySQLMYSQL_USER: Creates a new non-root user (todos-user)MYSQL_PASSWORD: Password for that non-root userMYSQL_DATABASE: Creates a database namedtodosand grants access to the above user
- todo-web-application: Read by the app to configure its database connection.
RDS_HOSTNAME: Hostname of the MySQL server (here, the service name mysql, which Docker Compose resolves automatically via internal DNS)RDS_PORT: MySQL port (3306 by default)RDS_DB_NAME: Database name to connect to (todos)RDS_USERNAME: MySQL username (todos-user)RDS_PASSWORD: Password used by the app to connect to the DB
- mysql: Bootstraps DB, user, and password on startup
Example 2: docker-compose.yml
services:
todo-web-application:
image: in28min/todo-web-application-mysql:0.0.1-SNAPSHOT
#build:
#context: .
#dockerfile: Dockerfile
ports:
- "8080:8080"
restart: always
depends_on: # Start the depends_on first
- mysql
environment:
RDS_HOSTNAME: mysql
RDS_PORT: 3306
RDS_DB_NAME: todos
RDS_USERNAME: todos-user
RDS_PASSWORD: dummytodos
networks:
- todo-web-application-network
mysql:
image: mysql:5.7
ports:
- "3306:3306"
restart: always
environment:
MYSQL_ROOT_PASSWORD: dummypassword
MYSQL_USER: todos-user
MYSQL_PASSWORD: dummytodos
MYSQL_DATABASE: todos
volumes:
- mysql-database-data-volume:/var/lib/mysql
networks:
- todo-web-application-network
# Volumes
volumes:
mysql-database-data-volume:
networks:
todo-web-application-network:
How can you use Docker Compose to launch and tear down applications? #
Up:
- Builds, (re)creates, starts, and attaches to containers for a service
docker compose up # For detach mode (running in background), use the -d (follow) option docker compose up -d
Down:
- Stops and removes containers, networks, volumes, and images created by up
docker compose down
Restart specific service:
- Command stops and then starts only the specific service without affecting the other running services
docker compose restart <NAME_OF_SERVICE>
Scale services:
- To scale or run multiple instances of the service
docker compose up --scale <NAME_OF_SERVICE>=<NO_OF_INSTANCES> # Example: docker compose up --scale currency-conversion=3
Build:
- Builds or rebuilds services defined in the
docker-compose.ymldocker compose buildservices: todo-web-application: image: in28min/todo-web-application-mysql:0.0.1-SNAPSHOT #build: #context: . #dockerfile: Dockerfile
Start:
- Starts existing containers defined in the
docker-compose.ymldocker compose start
Logs:
- View the logs of all services defined in the
docker-compose.ymldocker compose logs # For continuous, real-time logs, you can use the -f (follow) option docker compose logs -f
What is the use of .env files in Docker Compose? #
.env files
- By using
.envfiles, you can separate environment-specific configurations from your maindocker-compose.yml - These files help you manage variables like port numbers, image names, volumes, or environment modes.
- Define and manage environment variables that are used within your
docker-compose.ymlfile - Docker Compose automatically loads a
.envfile located in the same directory as yourdocker-compose.yml
1) Base Configuration (docker-compose.yml):
services:
web:
image: ${NGINX_IMAGE:-nginx}
environment:
- APP_ENV=${APP_ENV}
volumes:
- ${HTML_VOLUME}:/usr/share/nginx/html
ports:
- "${NGINX_PORT}:80"
2) Default .env File (Auto-loaded)
# Development environment
NGINX_IMAGE=nginx:alpine
NGINX_PORT=8080
3) Custom Environment File: dev.env
# Development environment
APP_ENV=development
HTML_VOLUME=./html/dev
4) Command to Use
docker compose --env-file dev.env up
Docker Compose FAQ #
- Q: What happens if you do not specify a network to connect to?
- Container is connected to
defaultbridgenetwork
- Container is connected to
- Q: Difference between
buildandimagein a service definitionbuild: Builds image from localDockerfileimage: Uses an existing image
- Q: How can you pass environment variables to a service in Docker Compose?
- Using
environment:orenv_file:in the YAML
- Using
- Q: How can you scale a service using Docker Compose?
docker compose up --scale service_name=3
- Q: Can Docker Compose be used in production?
- Yes for small setups. But lacks advanced orchestration features.
- Kubernetes is better suited for production-scale deployments
- Q: What is the difference between Docker Compose V1 and V2?
- V1: Separate binary, V2: Integrated with Docker CLI
- Syntax - V1:
docker-compose up, V2:docker compose up - V2 is the future — it replaces the need for a separate
docker-composebinary