Docker for Beginners: A Hands-On Tutorial to Master Containers from Scratch

2.86K 0 0 0 0

✅ Chapter 4: Docker Compose and Multi-Container Applications

🔍 Introduction

As you’ve learned from previous chapters, Docker is a powerful tool for building and running isolated containers. But what happens when your application grows beyond a single container?

Real-world applications often rely on multiple services—for example, a web frontend, backend API, database, and caching layer. Managing these components manually with docker run becomes messy and error-prone.

That’s where Docker Compose steps in. It simplifies the definition, orchestration, and management of multi-container Docker applications.


🧱 What is Docker Compose?

Docker Compose is a tool that allows you to define and run multi-container Docker applications using a YAML file called docker-compose.yml.

With just one command, docker-compose up, you can:

  • Spin up multiple containers
  • Define networks and volumes
  • Handle dependencies
  • Set environment variables
  • Restart policies and more

🗂️ Key Benefits of Docker Compose

  • Simplified orchestration for microservices
  • Cleaner project structure
  • Environment reproducibility
  • Easy local development and testing
  • Declarative configuration in one file

🧾 Basic Docker Compose File Structure

A docker-compose.yml file follows this format:

yaml

 

version: '3.8'

 

services:

  service_name:

    image: <image>

    ports:

      - "host:container"

    volumes:

      - ./host_path:/container_path

    environment:

      - VAR=value


🧪 Example 1: Running Nginx with Docker Compose

Create a simple docker-compose.yml:

yaml

 

version: '3.8'

 

services:

  web:

    image: nginx:latest

    ports:

      - "8080:80"

Run it:

bash

 

docker-compose up

Stop it:

bash

 

docker-compose down

Visit http://localhost:8080 to see Nginx running.


🧰 Useful Docker Compose Commands

Command

Description

docker-compose up

Starts services

docker-compose down

Stops and removes services

docker-compose build

Builds images defined in the file

docker-compose logs

Shows service logs

docker-compose ps

Lists running services

docker-compose exec

Executes commands in a container


🧪 Example 2: Flask + Redis App

Let’s build a simple Python app that stores visit counts using Redis.

📁 Project Structure

 

flask-redis/

── app.py

── requirements.txt

└── docker-compose.yml

🐍 app.py

python

 

from flask import Flask

import redis

 

app = Flask(__name__)

r = redis.Redis(host='redis', port=6379)

 

@app.route('/')

def hello():

    count = r.incr('hits')

    return f'Hello! This page has been viewed {count} times.'

 

if __name__ == '__main__':

    app.run(host='0.0.0.0', port=5000)

📦 requirements.txt

nginx

 

flask

redis


🧱 Dockerfile

Dockerfile

 

FROM python:3.10

 

WORKDIR /app

 

COPY requirements.txt .

RUN pip install -r requirements.txt

 

COPY . .

 

CMD ["python", "app.py"]


🧾 docker-compose.yml

yaml

 

version: '3.8'

 

services:

  web:

    build: .

    ports:

      - "5000:5000"

    depends_on:

      - redis

 

  redis:

    image: redis:alpine


🚀 Running the App

  1. Build and run the containers:

bash

 

docker-compose up --build

  1. Visit http://localhost:5000

You’ll see visit count increasing with each refresh.


🔧 depends_on Explained

depends_on ensures that Redis starts before Flask, but it doesn’t wait for Redis to be "ready". For readiness, use health checks or entrypoint scripts.


🔗 Networking in Docker Compose

All services in the same Compose file automatically share a private bridge network.

  • You can refer to services by name (e.g., redis)
  • No need to expose ports internally unless you need host access

🧩 Volumes in Docker Compose

You can define persistent volumes directly in Compose.

yaml

 

version: '3.8'

 

services:

  db:

    image: mysql

    volumes:

      - db_data:/var/lib/mysql

    environment:

      MYSQL_ROOT_PASSWORD: password

 

volumes:

  db_data:


📊 Docker Compose vs docker run

Feature

docker run

docker-compose

Single container

Multiple containers

🚫

Config file

Networking setup

Manual

Automatic

Scaling services

Hard

Easy with --scale


📦 Using .env Files with Compose

Create a .env file in the same directory:

ini

 

MYSQL_ROOT_PASSWORD=supersecret

Reference it in docker-compose.yml:

yaml

 

environment:

  - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}

Keeps sensitive or environment-specific values separate from your Compose config.


🧪 Example 3: WordPress + MySQL with Compose

yaml

 

version: '3.8'

 

services:

  wordpress:

    image: wordpress

    ports:

      - "8080:80"

    environment:

      - WORDPRESS_DB_HOST=mysql

      - WORDPRESS_DB_USER=root

      - WORDPRESS_DB_PASSWORD=root

    depends_on:

      - mysql

 

  mysql:

    image: mysql:5.7

    environment:

      - MYSQL_ROOT_PASSWORD=root

    volumes:

      - mysql_data:/var/lib/mysql

 

volumes:

  mysql_data:

Visit http://localhost:8080 to install WordPress.


🔁 Restart Policies in Compose

Ensure services restart on failure:

yaml

 

restart: unless-stopped


🛠 Debugging Compose Issues

Symptom

Fix

Container exits immediately

Check docker-compose logs

Port already in use

Change host port

Dependency not ready

Use health checks or wait-for-it script

Permission issues

Check volume paths and user rights


🚀 Scaling with Docker Compose

You can scale a service horizontally using:

bash

 

docker-compose up --scale web=3

Note: You’ll need a load balancer (like Nginx or HAProxy) for proper request distribution.


🔐 Security Best Practices

  • Never store secrets directly in docker-compose.yml
  • Use .env files or secret managers (Vault, AWS Secrets Manager)
  • Set proper restart policies
  • Avoid using latest tag in production (use fixed versions)

Summary of Chapter 4

You’ve now learned:

  • What Docker Compose is and why it’s important
  • How to write and use docker-compose.yml
  • How to manage multi-container apps
  • How services share networks and volumes
  • Real-world examples using Flask + Redis, WordPress + MySQL
  • How to use .env files, health checks, scaling, and restart policies


With Compose, your development and deployment become cleaner, scalable, and easier to manage.

Back

FAQs


✅ 1. What is Docker and why should I use it?

Answer: Docker is a containerization platform that allows developers to package applications and their dependencies into isolated units called containers. It ensures consistency across different environments, speeds up deployment, and makes application scaling easier.

✅ 2. What is the difference between a Docker container and a virtual machine (VM)?

Answer: Containers share the host system’s OS kernel, making them lightweight and fast, while VMs run a full guest OS, making them heavier and slower. Containers are ideal for microservices and rapid deployment, whereas VMs are better suited for full OS-level isolation.

✅ 3. Do I need to know Linux to use Docker?

Answer: While basic knowledge of Linux command-line tools is helpful, it’s not mandatory to start with Docker. Docker also works on Windows and macOS, and many beginner tutorials (including this one) walk you through all required commands step-by-step.

✅ 4. What is the difference between a Docker image and a Docker container?

Answer: A Docker image is a read-only template used to create containers, while a Docker container is a running instance of an image. You can think of an image as a blueprint and a container as the building made from it.

✅ 5. How do I install Docker on my computer?

Answer: You can download Docker Desktop for Windows or macOS from https://www.docker.com, or install Docker Engine on Linux using your distro’s package manager (like apt, yum, or dnf).

✅ 6. What is a Dockerfile and how is it used?

Answer: A Dockerfile is a script that contains a set of instructions for building a Docker image. It typically includes a base image, environment setup, file copying, and the command to run when the container starts.

✅ 7. What is Docker Hub and is it free?

Answer: Docker Hub is a cloud-based repository where users can share and store Docker images. It has free tiers and allows you to download popular open-source images or push your own images to share with others or use in CI/CD pipelines.

✅ 8. Can I run multiple containers at the same time?

Answer: Yes, you can run multiple containers simultaneously. Tools like Docker Compose even allow you to define and manage multi-container applications using a simple YAML configuration file.

✅ 9. How do I persist data in a Docker container?

Answer: You can use volumes or bind mounts to persist data outside the container’s lifecycle. This allows your application data to survive container restarts or recreations.

✅ 10. Is Docker secure?

Answer: Docker offers many security benefits like container isolation and image scanning. However, security also depends on your image sources, proper configurations, and updates. It's important to follow Docker security best practices for production deployments.