BLOG POSTS
How to Install and Use Docker Compose on Ubuntu 24

How to Install and Use Docker Compose on Ubuntu 24

Docker Compose is a powerful orchestration tool that simplifies the deployment and management of multi-container Docker applications. By defining your entire application stack in a single YAML file, you can spin up complex environments with multiple interconnected services using just one command. This guide will walk you through installing Docker Compose on Ubuntu 24, demonstrate practical usage scenarios, and share troubleshooting tips that’ll save you from the common headaches most developers encounter when first diving into container orchestration.

Understanding Docker Compose and Its Architecture

Docker Compose sits on top of Docker Engine and provides a declarative way to define multi-container applications. Unlike running individual Docker containers with lengthy docker run commands, Compose uses a docker-compose.yml file to specify services, networks, and volumes in a structured format.

The tool operates on three core concepts:

  • Services: Individual containers that make up your application (web server, database, cache, etc.)
  • Networks: Virtual networks that allow containers to communicate securely
  • Volumes: Persistent storage that survives container restarts and updates

When you run docker compose up, the tool reads your configuration file, creates the necessary networks and volumes, then starts all services in the correct order based on their dependencies.

Installing Docker Compose on Ubuntu 24

Ubuntu 24 ships with updated package repositories, making Docker Compose installation straightforward. There are two primary installation methods: using the official Docker repository (recommended) or installing via pip.

Method 1: Official Docker Repository Installation

First, update your package index and install prerequisite packages:

sudo apt update
sudo apt install ca-certificates curl gnupg lsb-release

Add Docker’s official GPG key and repository:

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker Engine and Docker Compose:

sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Verify the installation:

docker compose version

Method 2: Standalone Binary Installation

For environments where you prefer standalone binaries or need the latest version immediately:

sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

Post-Installation Configuration

Add your user to the docker group to run Docker commands without sudo:

sudo usermod -aG docker $USER
newgrp docker

Test the installation with a simple hello-world container:

docker run hello-world

Real-World Implementation Examples

Example 1: LAMP Stack with WordPress

Here’s a practical docker-compose.yml file for a WordPress development environment:

version: '3.8'

services:
  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppassword
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wordpress_data:/var/www/html
    depends_on:
      - db
    networks:
      - wp_network

  db:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppassword
      MYSQL_ROOT_PASSWORD: rootpassword
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - wp_network

  phpmyadmin:
    image: phpmyadmin:latest
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db
      MYSQL_ROOT_PASSWORD: rootpassword
    depends_on:
      - db
    networks:
      - wp_network

volumes:
  wordpress_data:
  db_data:

networks:
  wp_network:
    driver: bridge

Start the entire stack:

docker compose up -d

Example 2: Development Environment with Hot Reload

For Node.js applications with live reloading:

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - CHOKIDAR_USEPOLLING=true
    depends_on:
      - redis
      - postgres

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: devdb
      POSTGRES_USER: devuser
      POSTGRES_PASSWORD: devpass
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  postgres_data:

Docker Compose vs Alternative Solutions

Feature Docker Compose Kubernetes Docker Swarm Podman Compose
Learning Curve Low High Medium Low
Multi-host Support No Yes Yes No
Production Ready Single host only Yes Yes Limited
Resource Usage Low High Medium Low
Configuration Format YAML YAML YAML YAML

Performance Considerations and Best Practices

Docker Compose performance can vary significantly based on your configuration choices:

  • Volume Performance: Named volumes typically perform better than bind mounts for database storage
  • Network Overhead: Custom networks add minimal latency (< 1ms) but provide better isolation
  • Image Size Impact: Alpine-based images start 2-3x faster than full distributions
  • Memory Usage: A typical LAMP stack with Compose overhead uses ~200MB base memory

Security Best Practices

Always follow these security guidelines:

  • Use environment files (.env) for sensitive data instead of hardcoding secrets
  • Run containers as non-root users when possible
  • Limit container capabilities with security_opt settings
  • Use read-only filesystems for stateless services
  • Regularly update base images to patch security vulnerabilities

Example secure configuration:

version: '3.8'

services:
  app:
    image: node:18-alpine
    user: "1000:1000"
    read_only: true
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
    tmpfs:
      - /tmp
    environment:
      - NODE_ENV=production

Common Issues and Troubleshooting

Port Conflicts

One of the most frequent issues is port conflicts. Check what’s using a port:

sudo netstat -tulpn | grep :8080
sudo lsof -i :8080

Use different ports in your docker-compose.yml or stop conflicting services.

Permission Issues

If you encounter permission denied errors:

# Check Docker daemon status
sudo systemctl status docker

# Restart Docker service
sudo systemctl restart docker

# Verify group membership
groups $USER

Container Communication Problems

When containers can’t communicate, check network configuration:

# List Docker networks
docker network ls

# Inspect specific network
docker network inspect project_default

# Check container connectivity
docker compose exec service1 ping service2

Volume Mount Issues

For bind mount problems on Ubuntu 24:

# Check SELinux context (if enabled)
ls -Z /path/to/host/directory

# Fix ownership issues
sudo chown -R $USER:$USER ./project-directory

# Check AppArmor logs
sudo dmesg | grep -i apparmor

Advanced Usage Patterns

Multi-Environment Configuration

Use override files for different environments:

# docker-compose.yml (base)
version: '3.8'
services:
  app:
    image: myapp:latest
    environment:
      - NODE_ENV=production

# docker-compose.override.yml (development)
version: '3.8'
services:
  app:
    build: .
    volumes:
      - .:/app
    environment:
      - NODE_ENV=development

For production, use a specific override file:

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Health Checks and Dependencies

Implement proper health checks for reliable startup:

services:
  db:
    image: postgres:15
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5

  app:
    image: myapp:latest
    depends_on:
      db:
        condition: service_healthy

Monitoring and Logging

Set up centralized logging with the ELK stack:

version: '3.8'

services:
  app:
    image: myapp:latest
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  elasticsearch:
    image: elasticsearch:8.5.0
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"

  logstash:
    image: logstash:8.5.0
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf

  kibana:
    image: kibana:8.5.0
    ports:
      - "5601:5601"

Monitor container resource usage:

# Real-time resource monitoring
docker compose top

# Detailed stats
docker stats $(docker compose ps -q)

# Check logs
docker compose logs -f service_name

Integration with CI/CD Pipelines

Docker Compose integrates seamlessly with GitLab CI, GitHub Actions, and Jenkins. Here’s a GitHub Actions example:

name: Deploy with Docker Compose
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Docker Compose
        run: |
          docker compose --version
          
      - name: Build and test
        run: |
          docker compose -f docker-compose.test.yml up --build --abort-on-container-exit
          
      - name: Deploy to staging
        run: |
          docker compose -f docker-compose.staging.yml up -d

For more comprehensive information about Docker Compose features and advanced configurations, check the official Docker Compose documentation.

Docker Compose transforms complex multi-container deployments into simple, reproducible processes. Whether you’re setting up development environments, running integration tests, or managing small-scale production deployments, mastering Compose will significantly streamline your containerization workflow. The key is starting with simple configurations and gradually incorporating advanced features as your infrastructure needs grow.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked