Introduction
Building on our introduction to Docker Compose, this lesson dives deeper into the practical aspects of writing robust docker-compose.yml files. We'll explore various configuration options within the services section, demonstrating how to define images, build custom services, manage ports, set environment variables, and establish dependencies. A well-structured Compose file is the key to a manageable multi-container application.
Key Concepts
services Section Deep Dive
Each entry under the services key represents an individual component of your application.
Let's look at common configuration options:
-
imagevs.build: You can either specify an existing Docker image (image: nginx:latest) or provide a path to a Dockerfile (build: ./backend-service) to build a custom image for that service. -
ports: Maps host ports to container ports (e.g.,- "8000:80"). This allows external access to your service. You can map multiple ports. -
environment: Sets environment variables inside the container. This is crucial for passing configuration, API keys, or database credentials securely (though for production secrets, dedicated secret management is better).- Example:
environment: - DB_HOST=database - API_KEY=your_secret_key
- Example:
-
volumes: Mounts host paths or named volumes into the container. This is essential for persistent data and code syncing in development.- Example:
- "./app:/app"(bind mount) or- "db_data:/var/lib/postgresql/data"(named volume).
- Example:
-
networks: Connects services to specific networks. Compose automatically creates a default network, but custom networks provide better organization and isolation. Services on the same network can communicate by service name.- Example:
networks: - frontend_network
- Example:
-
depends_on: Declares dependencies between services. This ensures that dependent services are started before the service that relies on them. Important:depends_ononly ensures startup order, not readiness. For true readiness, your application code should implement retries or health checks.- Example:
depends_on: - database_service
- Example:
volumes and networks (Top-Level)
These top-level keys are used to define named volumes and custom networks that can then be referenced by individual services. Defining them here allows for global management and clarity.
-
Top-level
volumes: Declares named volumes.- Example:
volumes: db_data:
- Example:
-
Top-level
networks: Declares custom networks.- Example:
networks: web_tier: driver: bridge
- Example:
Example/Code
Let's refine a docker-compose.yml for a full-stack application:
yamlversion: '3.8' services: # Frontend service (e.g., React app served by Nginx) frontend: build: ./frontend ports: - "80:80" volumes: - frontend_data:/var/www/html depends_on: - api networks: - app_network # Backend API service (e.g., Node.js Express app) api: build: ./api environment: NODE_ENV: production DB_HOST: database DB_PORT: 5432 DB_USER: admin DB_PASSWORD: supersecretpassword ports: - "3000:3000" # Expose for internal debugging, or remove depends_on: - database networks: - app_network - db_network # Database service (e.g., PostgreSQL) database: image: postgres:14-alpine environment: POSTGRES_DB: myappdb POSTGRES_USER: admin POSTGRES_PASSWORD: supersecretpassword volumes: - db_data:/var/lib/postgresql/data networks: - db_network volumes: frontend_data: db_data: networks: app_network: db_network:
This example demonstrates defining build contexts, port mappings, environment variables, named volumes, custom networks, and dependencies for a coherent application stack.
Summary/Key Takeaways
-
servicesconfiguration includesimage/build,ports,environment,volumes,networks, anddepends_on. -
depends_onensures startup order but not service readiness. -
Top-level
volumesandnetworksdefine reusable resources. -
A well-structured
docker-compose.ymlis crucial for managing complex applications easily.