Lesson 7 of 9 ↓
- 1.Docker Comprehensive Guide: From Zero to Hero
- 2.Docker Environment Variables: the Ultimate Guide
- 3.Docker Images: the Ultimate Comprehensive Guide
- 4.Docker: Cmd vs. Entrypoint - the Comprehensive Guide
- 5.Docker Networking: the Ultimate Deep Dive
- 6.Docker Storage & Filesystem: the Complete Reference
- 7.Docker Compose: the Ultimate Master Guide
- 8.Docker Registry: the Ultimate Master Guide
- 9.Docker Engine: the Ultimate Deep Dive
5 min read
Docker Compose: the Ultimate Master Guide
This guide covers Docker Compose from basic concepts to advanced networking and versioning. It explains how to manage multi-container applications easily using a YAML file instead of running complex commands manually.
The Problem: the "matrix From Hell"
Before Docker Compose, if you wanted to run a complex application (like the Voting App), you had to run many commands manually and link them together.
The Hard Way (manual docker Run)
Imagine you have an app with a Web Server, Database, Redis, and Ansible. You would have to type this every time:
# 1. Start the Web App
docker run -d --name simple-webapp mmumshad/simple-webapp
# 2. Start MongoDB
docker run -d --name mongodb mongodb
# 3. Start Redis
docker run -d --name redis redis:alpine
# 4. Start Ansible
docker run -d --name ansible ansibleThe Issues:
-
Tedious: You have to remember long commands and flags.
-
Linking: Connecting containers manually (
--link) is messy. -
Dependencies: You must remember to start the Database before the Web App.
The Solution: docker-compose.yml
Docker Compose allows you to write all these configurations into a single file named docker-compose.yml.
Example 1: Simple Webapp
Here is how the commands above translate into a Compose file:
# docker-compose.yml
version: '3' # Always specify the version
services: # Define your containers here
web:
image: mmumshad/simple-webapp
ports:
- "8080:80"
database:
image: mongodb
messaging:
image: redis:alpine
orchestration:
image: ansibleHow to Run It?
Instead of typing 4 commands, you simply type:
Command:
docker-compose up- What it does: It reads the file, pulls the images, creates the network, and starts all containers in the correct order.
Essential Docker Compose Commands
These are the commands you will use daily.
Start Everything (up)
Command: docker-compose up
-
Flags:
-
-d(Detached): Runs containers in the background (very important so your terminal doesn't get stuck). -
--build: Forces Docker to rebuild images from Dockerfiles (useful if you changed code).
-
Stop Everything (down)
Command: docker-compose down
-
What it does: Stops containers AND removes them. It also removes the created networks.
-
Why use it? It cleans up your environment completely.
View Logs (logs)
Command: docker-compose logs -f
-
Flags:
-f(Follow): Streams the logs live (liketail -f).
List Containers (ps)
Command: docker-compose ps
- What it does: Lists only the containers related to the current
docker-compose.ymlfile.
Real World Scenario: the Voting App
Let's look at the complex example provided in your notes (The "Cats vs Dogs" voting app). This app has 5 components:
-
Voting-App (Python): Front-end for users to vote (Cats or Dogs).
-
Redis (In-Memory DB): Collects votes temporarily.
-
Worker (.NET): Processes votes and moves them to DB.
-
DB (Postgres): Persistent database.
-
Result-App (NodeJS): Front-end to show results.
Configuration A: Using Images (the Basic Way)
If all images are already built and pushed to Docker Hub:
redis:
image: redis
db:
image: postgres:9.4
vote:
image: voting-app
ports:
- "5000:80"
links: # Deprecated (See Section 6)
- redis
result:
image: result
ports:
- "5001:80"
links:
- db
worker:
image: worker
links:
- redis
- dbConfiguration B: Using build (the Developer Way)
Usually, you have the source code on your laptop and want Docker to build the image for you.
redis:
image: redis
db:
image: postgres:9.4
vote:
build: ./vote # Path to the folder containing Dockerfile
ports:
- "5000:80"
result:
build: ./result # Path to Result App code
ports:
- "5001:80"
worker:
build: ./worker # Path to Worker App codeKey Difference:
-
image: xxx: Docker pulls it from the internet. -
build: ./xxx: Docker runsdocker build -t ...using the Dockerfile in that folder.
Evolution of Versions (v1 vs V2 vs V3)
Docker Compose has changed over time.
Version 1 (legacy)
-
Structure: No
versionline. Just lists containers directly. -
Networking: Uses the default Bridge. Links (
links:) are mandatory to enable communication. -
Status: Deprecated. Do not use.
Version 2 (major Change)
-
Structure: Must start with
version: "2"and put containers underservices:. -
Networking: Creates a dedicated Bridge Network for the project. All containers can talk to each other automatically using their service name (e.g.,
ping redis). -
Feature (
depends_on): Introduced to specify startup order. For example, ensuring Redis starts before the Voting App.
version: "2"
services:
redis:
image: redis
vote:
image: voting-app
ports:
- "5000:80"
depends_on: # <--- Start redis first
- redisVersion 3 (swarm Compatible)
-
Structure: Similar to v2 (
version: "3"). -
Focus: Designed for Docker Swarm (Clusters).
-
Changes: Some options like
mem_limitmoved underdeploykey.
Advanced Networking (front-end vs Back-end)
In a professional setup, you don't want everyone talking to everyone.
-
Front-end: Accessible by users.
-
Back-end: Accessible only by internal apps (Database should not be public).
The Architecture
-
Voting App: Needs
front-end(Users vote) ANDback-end(Sends vote to Redis). -
Redis: Needs
back-endonly. -
Worker: Needs
back-endonly. -
DB: Needs
back-endonly. -
Result App: Needs
front-end(Users see results) ANDback-end(Reads from DB).
The Docker Compose File
version: "2"
services:
vote:
image: voting-app
ports:
- "5000:80"
networks:
- front-end
- back-end
redis:
image: redis
networks:
- back-end
worker:
image: worker
networks:
- back-end
db:
image: postgres:9.4
networks:
- back-end
result:
image: result
ports:
- "5001:80"
networks:
- front-end
- back-end
# Define the networks here
networks:
front-end:
back-end:Why is this important?
-
Security: If a hacker hacks the
voteapp, they cannot easily attack the Database because they are segmented. -
Organization: Keeps traffic clean.
Deprecation Warning: Links
You might see --link in old tutorials.
-
Old Way:
docker run --link redis:redis ... -
New Way: Just use the service name!
- If you name your service
redisindocker-compose.yml, other containers can simply connect to the hostredis. Docker handles the DNS.
- If you name your service
Practice
To master this, try deploying the full Voting App yourself. The code is available here: Link: https://github.com/dockersamples/example-voting-app
Comments
Loading the discussion…