Docker Compose Installation and Multi-Container Applications: Complete Beginner's Guide (Part 1)

Learn to install Docker Compose and create your first multi-container application. Master docker-compose.yml configuration, service definitions, volumes, networks, and essential compose commands.

15 min read

Managing multiple Docker containers manually can quickly become overwhelming. Docker Compose solves this by allowing you to define and run multi-container applications using a single YAML configuration file. This comprehensive guide walks you through installing Docker Compose and building your first multi-container application.

šŸ’”

šŸŽÆ What You'll Learn: In this hands-on tutorial, you'll discover:

  • How to install Docker Compose on Linux systems
  • Understanding the docker-compose.yml file structure
  • Defining multiple services (web server and database)
  • Configuring volumes for data persistence
  • Setting up custom networks for service communication
  • Essential Docker Compose commands for managing applications
  • Viewing logs and accessing running containers

šŸš€ Why Docker Compose Matters

Docker Compose transforms complex multi-container deployments into simple, reproducible configurations. Instead of running multiple docker run commands with dozens of flags, you define everything in a single file and launch your entire application stack with one command.

Prerequisites

Before we begin, make sure you have:

  • Docker installed and running
  • Basic understanding of Docker containers
  • A Linux system (CentOS, RHEL, Fedora, or Ubuntu)
  • Root or sudo privileges
  • Internet connection for downloading packages

šŸ“¦ Step 1: Install Docker Compose

Docker Compose is now available as a Docker plugin, which means it integrates directly with the Docker CLI.

Download Docker Compose Binary

Download the latest version of Docker Compose from the official GitHub repository:

sudo curl -SL https://github.com/docker/compose/releases/download/v2.39.4/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

What this command does:

  • curl: Downloads files from the internet
  • -SL: Shows errors (-S) and follows redirects (-L)
  • -o /usr/local/bin/docker-compose: Saves the file to the specified location

Expected Output:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 72.8M  100 72.8M    0     0  7015k      0  0:00:10  0:00:10 --:--:-- 7806k

This shows the download progress as it retrieves approximately 72.8 MB.

āš ļø

āš ļø Permission Error: If you see "Permission denied", make sure to use sudo at the beginning of the command. Regular users don't have write access to /usr/local/bin/.

Make the Binary Executable

Set execute permissions on the downloaded file:

sudo chmod +x /usr/local/bin/docker-compose

This command uses chmod +x to add execute permission, allowing the file to run as a program.

For easier access, create a symbolic link in /usr/bin:

sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

Note: If you see File exists error, the symlink is already created - this is fine.

Verify Installation

Check the installed Docker Compose version:

docker compose version

Expected Output:

Docker Compose version v2.39.2
āœ…

āœ… Installation Complete: You now have Docker Compose installed and ready to use. Note that the command is docker compose (with a space) rather than the older docker-compose (with a hyphen).

šŸ“‹ Step 2: Understanding Docker Compose Help

View available Docker Compose commands and options:

docker compose --help

Key Output Sections:

Usage:  docker compose [OPTIONS] COMMAND

Define and run multi-container applications with Docker

Options:
  --env-file stringArray       Specify an alternate environment file
  -f, --file stringArray       Compose configuration files
  -p, --project-name string    Project name

Commands:
  build       Build or rebuild services
  config      Parse, resolve and render compose file in canonical format
  down        Stop and remove containers, networks
  exec        Execute a command in a running container
  logs        View output from containers
  ps          List containers
  pull        Pull service images
  restart     Restart service containers
  start       Start services
  stop        Stop services
  up          Create and start containers

This gives you an overview of the most important commands you'll use to manage your applications.

šŸ—ļø Step 3: Create Project Structure

Let's create a practical multi-container application with a web server and database.

Create Project Directory

mkdir docker-compose-practice
cd docker-compose-practice

Create Directory Structure

Set up the directory structure for our application:

mkdir -p web/html
mkdir -p database/init

The -p flag creates parent directories if they don't exist.

View Directory Structure

Use the tree command to visualize your directory structure:

tree

Output:

.
ā”œā”€ā”€ database
│   └── init
└── web
    └── html

4 directories, 0 files

šŸ“„ Step 4: Create HTML File for Web Server

Create a simple HTML page that will be served by Nginx:

touch web/html/index.html

Edit the file with your preferred text editor and add the following content:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Docker Compose Lab</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 50px auto;
            padding: 20px;
            background-color: #f4f4f4;
        }
        .container {
            background-color: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
        }
        h1 {
            color: #333;
            text-align: center;
        }
        .info {
            background-color: #e7f3ff;
            padding: 15px;
            border-left: 4px solid #2196F3;
            margin: 20px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Welcome to Docker Compose Lab!</h1>
        <div class="info">
            <h3>Multi-Container Application</h3>
            <p>This web page is served by an Nginx container, which is part of a multi-container application managed by Docker Compose.</p>
            <p><strong>Services Running:</strong></p>
            <ul>
                <li>Web Server: Nginx (Port 8080)</li>
                <li>Database: MySQL (Port 3306)</li>
            </ul>
        </div>
        <p>Congratulations! You have successfully deployed a multi-container application using Docker Compose.</p>
    </div>
</body>
</html>

This creates a styled welcome page that confirms your multi-container setup is working.

šŸ—„ļø Step 5: Create Database Initialization Script

Create an SQL script that will run when the MySQL container starts:

touch database/init/init.sql

Add the following SQL content:

-- Create a sample database
CREATE DATABASE IF NOT EXISTS sampleapp;

-- Use the database
USE sampleapp;

-- Create a users table
CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Insert sample data
INSERT INTO users (username, email) VALUES
('john_doe', 'john@example.com'),
('jane_smith', 'jane@example.com'),
('docker_user', 'docker@compose.com');

-- Create a simple view
CREATE VIEW user_count AS
SELECT COUNT(*) as total_users FROM users;

What this script does:

  • Creates a database named sampleapp
  • Creates a users table with basic fields
  • Inserts three sample user records
  • Creates a view to count total users

This file will be automatically executed when the MySQL container starts for the first time.

āš™ļø Step 6: Create docker-compose.yml File

Now comes the most important part - the Docker Compose configuration file:

touch docker-compose.yml

Add the following configuration:

version: '3.8'

services:
  webserver:
    image: nginx:alpine
    container_name: compose-webserver
    ports:
      - "8080:80"
    volumes:
      - ./web/html:/usr/share/nginx/html:ro
    depends_on:
      - database
    networks:
      - app-network
    restart: unless-stopped

  database:
    image: mysql:8.0
    container_name: compose-database
    environment:
      - MYSQL_ROOT_PASSWORD=rootpassword123
      - MYSQL_DATABASE=sampleapp
      - MYSQL_USER=appuser
      - MYSQL_PASSWORD=apppassword123
    ports:
      - "3306:3306"
    volumes:
      - ./database/init:/docker-entrypoint-initdb.d:ro
      - mysql-data:/var/lib/mysql
    networks:
      - app-network
    restart: unless-stopped

volumes:
  mysql-data:
    driver: local

networks:
  app-network:
    driver: bridge

Understanding the Configuration

SectionParameterPurpose
version'3.8'Compose file format version (now optional)
services-Defines all containers in your application
webserverimageUses Nginx Alpine image (lightweight)
webserverportsMaps host port 8080 to container port 80
webservervolumesMounts local HTML files into container (read-only)
webserverdepends_onEnsures database starts before webserver
databaseenvironmentSets MySQL configuration variables
databasevolumesMounts init scripts and persistent data storage
networksapp-networkCreates isolated network for service communication
restartunless-stoppedAlways restart containers except when manually stopped
šŸ’”

šŸ’” Version Note: The version field is now considered obsolete in Docker Compose v2 and can be omitted. However, it's still commonly included for backwards compatibility.

šŸš€ Step 7: Launch Your Multi-Container Application

Start all services defined in your docker-compose.yml file:

docker compose up -d

Command Breakdown:

  • up: Creates and starts containers
  • -d: Runs in detached mode (background)

Expected Output:

[+] Running 4/4
 āœ” Network docker-compose-practice_app-network  Created                    0.6s
 āœ” Volume "docker-compose-practice_mysql-data"  Created                    0.0s
 āœ” Container compose-database                   Started                    1.1s
 āœ” Container compose-webserver                  Started                    1.8s

What happened:

  1. Docker Compose created a custom network called docker-compose-practice_app-network
  2. Created a named volume docker-compose-practice_mysql-data for database persistence
  3. Started the database container first (due to depends_on)
  4. Started the webserver container
āœ…

āœ… Application Running: Your multi-container application is now running! The webserver is accessible at http://localhost:8080 and the MySQL database is listening on port 3306.

šŸ“Š Step 8: View Container Logs

Monitor what's happening inside your containers:

View All Logs

docker compose logs

This displays logs from both the webserver and database containers.

View Logs for Specific Service

docker compose logs webserver

Expected Output (abbreviated):

compose-webserver  | /docker-entrypoint.sh: Configuration complete; ready for start up
compose-webserver  | 2025/10/02 14:13:31 [notice] 1#1: using the "epoll" event method
compose-webserver  | 2025/10/02 14:13:31 [notice] 1#1: nginx/1.29.1
compose-webserver  | 2025/10/02 14:13:31 [notice] 1#1: start worker processes
docker compose logs database

Expected Output (abbreviated):

compose-database  | 2025-10-02 14:13:31+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.43-1.el9 started.
compose-database  | 2025-10-02 14:13:32+00:00 [Note] [Entrypoint]: Initializing database files
compose-database  | 2025-10-02 14:13:50+00:00 [Note] [Entrypoint]: Creating database sampleapp
compose-database  | 2025-10-02 14:13:50+00:00 [Note] [Entrypoint]: Creating user appuser
compose-database  | 2025-10-02 14:13:50+00:00 [Note] [Entrypoint]: running /docker-entrypoint-initdb.d/init.sql
compose-database  | 2025-10-02T14:13:55.220344Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections.

Key observations from database logs:

  • MySQL initialized the database files
  • Created the sampleapp database
  • Created the appuser user
  • Executed our initialization script (init.sql)
  • MySQL is ready for connections on port 3306

Follow Logs in Real-Time

docker compose logs -f

The -f flag follows the log output (similar to tail -f). Press Ctrl+C to stop following.

šŸ” Step 9: Check Running Containers

Using Docker Compose PS

docker compose ps

Expected Output:

NAME                IMAGE          COMMAND                  SERVICE     CREATED              STATUS              PORTS
compose-database    mysql:8.0      "docker-entrypoint.s…"   database    About a minute ago   Up About a minute   0.0.0.0:3306->3306/tcp, 33060/tcp
compose-webserver   nginx:alpine   "/docker-entrypoint.…"   webserver   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp

Using Standard Docker PS

docker ps

Output:

CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                                                    NAMES
3d96f6859c75   nginx:alpine   "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp                  compose-webserver
7588d5d02737   mysql:8.0      "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp   compose-database

Both commands show the running containers, but docker compose ps is specific to your compose project.

🌐 Step 10: Verify the Network

Check that Docker Compose created the custom network:

docker network ls

Expected Output:

NETWORK ID     NAME                                  DRIVER    SCOPE
6c4642b06759   bridge                                bridge    local
7b20c076257a   docker-compose-practice_app-network   bridge    local
4014e1a64d4c   host                                  host      local
b84fc03ca6b5   none                                  null      local

The docker-compose-practice_app-network is automatically created and both services are connected to it, allowing them to communicate using service names.

šŸŒ Step 11: Test the Web Application

Access your web application using curl:

curl http://localhost:8080

Expected Output (HTML):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Docker Compose Lab</title>
    ...
    <h1>Welcome to Docker Compose Lab!</h1>
    ...
</html>

You can also open http://localhost:8080 in your web browser to see the styled page.

šŸ’¾ Step 12: Test the Database

Execute a MySQL query inside the running database container:

docker compose exec database mysql -u appuser -papppassword123 -e "SELECT * FROM sampleapp.users"

Command Breakdown:

  • exec database: Execute command in database service
  • mysql: Run MySQL client
  • -u appuser: Login as appuser
  • -papppassword123: Password (note: no space after -p)
  • -e "...": Execute the SQL query

Expected Output:

mysql: [Warning] Using a password on the command line interface can be insecure.
+----+-------------+--------------------+---------------------+
| id | username    | email              | created_at          |
+----+-------------+--------------------+---------------------+
|  1 | john_doe    | john@example.com   | 2025-10-02 14:13:50 |
|  2 | jane_smith  | jane@example.com   | 2025-10-02 14:13:50 |
|  3 | docker_user | docker@compose.com | 2025-10-02 14:13:50 |
+----+-------------+--------------------+---------------------+

This confirms that:

  • The database is running properly
  • The initialization script executed successfully
  • The sample data was inserted
  • You can query the database from outside the container
āš ļø

āš ļø Security Note: Passing passwords on the command line is insecure for production use. This is fine for learning, but use environment files or secrets management in production.

šŸŽÆ Essential Docker Compose Commands Reference

CommandPurposeExample
docker compose up -dStart all services in backgroundLaunch application
docker compose downStop and remove containers, networksTear down application
docker compose psList containers in projectCheck status
docker compose logsView container logsDebug issues
docker compose logs -fFollow logs in real-timeMonitor activity
docker compose logs -tShow timestamps in logsTime-based debugging
docker compose exec [service] [cmd]Run command in service containerExecute MySQL queries
docker compose stopStop services without removingPause application
docker compose startStart stopped servicesResume application
docker compose restartRestart all servicesApply config changes

šŸŽÆ Key Takeaways

āœ… Remember These Points

  1. Single Configuration File: Docker Compose uses docker-compose.yml to define entire application stacks
  2. Service Dependencies: Use depends_on to control startup order
  3. Volume Persistence: Named volumes preserve data even when containers are removed
  4. Network Isolation: Compose creates custom networks for secure service communication
  5. Service Names: Containers can communicate using service names as hostnames
  6. Environment Variables: Configure applications using the environment section
  7. Port Mapping: Map host ports to container ports for external access

šŸš€ What's Next?

In Part 2, we'll cover advanced Docker Compose features:

  • Scaling services horizontally
  • Load balancing with Nginx
  • Using custom configuration files
  • Validating configurations with docker compose config
  • Managing volumes and cleanup strategies
  • Override files for different environments
  • Advanced troubleshooting techniques

šŸ“– Further Reading

Official Resources


āœ…

šŸŽ‰ Excellent Work! You've successfully installed Docker Compose and created your first multi-container application. You now understand how to define services, manage volumes, configure networks, and use essential compose commands.

Next Steps: Practice modifying the docker-compose.yml file, add more services, and get ready for Part 2 where we'll explore scaling and advanced features!

šŸ’¬ Discussion

Share your Docker Compose experience:

  • What multi-container applications are you planning to build?
  • Have you encountered any challenges setting up services?
  • What other services would you like to see in a tutorial?
  • How is Docker Compose improving your development workflow?

Connect with me:

  • šŸ™ GitHub - Docker Compose examples
  • šŸ“§ Contact - Questions and discussions
Owais

Written by Owais

I'm an AIOps Engineer with a passion for AI, Operating Systems, Cloud, and Security—sharing insights that matter in today's tech world.

I completed the UK's Eduqual Level 6 Diploma in AIOps from Al Nafi International College, a globally recognized program that's changing careers worldwide. This diploma is:

  • āœ… Available online in 17+ languages
  • āœ… Includes free student visa guidance for Master's programs in Computer Science fields across the UK, USA, Canada, and more
  • āœ… Comes with job placement support and a 90-day success plan once you land a role
  • āœ… Offers a 1-year internship experience letter while you study—all with no hidden costs

It's not just a diploma—it's a career accelerator.

šŸ‘‰ Start your journey today with a 7-day free trial

Related Articles

Continue exploring with these handpicked articles that complement what you just read

More Reading

One more article you might find interesting