Traduction anglaise de la page de documentation concernant Docker et Compose #11

Merged
Tellsanguis merged 1 commit from contenu into main 2025-12-19 18:07:37 +00:00

View file

@ -1,17 +1,18 @@
--- ---
sidebar_position: 3 sidebar_position: 3
tags: [docker, docker-compose, containerization, homelab]
last_update:
date: 2025-11-25
--- ---
# Docker and Docker Compose # Docker and Docker Compose
:::info
Full English translation coming soon.
:::
Docker is a **containerization platform** that allows packaging applications and their dependencies into lightweight and isolated containers.
## What is Docker? ## What is Docker?
Docker is a **containerization platform** that allows you to package applications and their dependencies into lightweight and isolated containers.
### Containers: revolution of modern infrastructure
A container is a standardized software unit that contains: A container is a standardized software unit that contains:
- The application itself - The application itself
- All its dependencies (libraries, runtime, system tools) - All its dependencies (libraries, runtime, system tools)
@ -22,41 +23,452 @@ A container is a standardized software unit that contains:
- **Container**: Shares the host OS kernel, starts in seconds, very lightweight (~MB) - **Container**: Shares the host OS kernel, starts in seconds, very lightweight (~MB)
- **VM**: Emulates a complete OS, starts in minutes, heavier (~GB) - **VM**: Emulates a complete OS, starts in minutes, heavier (~GB)
## Docker Compose: Simplified orchestration ### Advantages of Docker
1. **Portability**: "Runs anywhere" - works identically in development, testing, and production
2. **Isolation**: Each container is isolated, avoiding dependency conflicts
3. **Lightweight**: Consumes fewer resources than a VM (no full virtualization)
4. **Speed**: Instant application startup
5. **Reproducibility**: Docker image = identical environment every time
6. **Ecosystem**: Docker Hub contains thousands of ready-to-use images
## Docker Compose: simplified orchestration
Docker Compose is an **orchestration tool** for defining and managing multi-container applications. Docker Compose is an **orchestration tool** for defining and managing multi-container applications.
### Why Docker Compose? ### Why Docker Compose?
- **Declarative configuration**: Everything defined in a `compose.yml` file Without Compose, deploying an application with multiple containers (app + database + cache + ...) requires long `docker run` commands that are difficult to maintain.
With Compose:
- **Declarative configuration**: Everything is defined in a `compose.yml` file
- **Grouped management**: Start/stop all services with one command - **Grouped management**: Start/stop all services with one command
- **Automatic networks**: Containers communicate easily between them - **Automatic networks**: Containers communicate easily with each other
- **Persistent volumes**: Simple storage management - **Persistent volumes**: Simple storage management
- **Environment variables**: Flexible configuration via `.env` files - **Environment variables**: Flexible configuration via `.env` files
## Configuration examples ### compose.yml file
My Docker Compose stacks are available in the Ansible repository under `stacks/`. Key examples include: A Compose file defines:
- **Traefik**: Advanced reverse proxy with two instances (public and private) - **Services** (containers)
- **Photoprism**: Application with database (app + DB) - **Networks** (communication between containers)
- **Mobilizon**: Multi-container application with multiple networks - **Volumes** (data persistence)
- **Vaultwarden**: Security-focused configuration - **Environment variables** (configuration)
## Docker Compose stack examples
My Docker Compose stacks are available in the Ansible repository under `stacks/`. Here are some representative examples:
### Example 1: Traefik - Advanced Reverse Proxy
Traefik is the entry point for the entire infrastructure. This compose illustrates an advanced configuration with **two Traefik instances** (public and private):
```yaml
services:
traefik-public:
image: traefik:v3
container_name: traefik-public
restart: unless-stopped
ports:
- "192.168.1.2:80:80"
- "192.168.1.2:443:443"
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
- traefik_network
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik-public.yml:/etc/traefik/traefik.yml:ro
- ./dynamic-public:/etc/traefik/dynamic:ro
- ./letsencrypt-public:/letsencrypt
- /var/log/traefik:/var/log/traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik-dashboard-public.rule=Host(`traefik-public.local.tellserv.fr`)"
- "traefik.http.routers.traefik-dashboard-public.entrypoints=local"
- "traefik.http.routers.traefik-dashboard-public.tls.certresolver=cloudflare-local"
- "traefik.http.routers.traefik-dashboard-public.tls=true"
- "traefik.http.routers.traefik-dashboard-public.service=api@internal"
- "traefik.http.middlewares.crowdsec-bouncer.forwardauth.address=http://crowdsec-bouncer:8080/api/v1/forwardAuth"
environment:
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
- TZ=Europe/Paris
traefik-private:
image: traefik:v3
container_name: traefik-private
restart: unless-stopped
ports:
- "192.168.1.3:80:80"
- "192.168.1.3:443:443"
networks:
- traefik_network
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik-private.yml:/etc/traefik/traefik.yml:ro
- ./dynamic-private:/etc/traefik/dynamic:ro
- ./letsencrypt-private:/letsencrypt
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik-dashboard-local.rule=Host(`traefik-private.local.tellserv.fr`)"
environment:
- TZ=Europe/Paris
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
networks:
traefik_network:
external: true
```
**Key points**:
- **Two instances**: Separation of public (Internet) and private (local network only)
- **Docker socket**: Traefik automatically detects new containers via `/var/run/docker.sock`
- **Let's Encrypt certificates**: Automatic generation with DNS-01 challenge (Cloudflare)
- **Traefik labels**: Dynamic configuration via Docker labels
- **CrowdSec middleware**: Integration with CrowdSec to block malicious IPs
- **External network**: All services connect to the `traefik_network` network
### Example 2: Photoprism - Application with database
Photoprism illustrates a classic application stack (app + DB) with advanced configuration:
```yaml
services:
photoprism:
image: photoprism/photoprism:241021
stop_grace_period: 10s
depends_on:
- mariadb
restart: unless-stopped
security_opt:
- seccomp:unconfined
- apparmor:unconfined
working_dir: "/photoprism"
volumes:
- "/mnt/storage/photos:/photoprism/import"
- "/mnt/storage/photoprism/originals:/photoprism/originals"
- "/mnt/storage/photoprism/storage:/photoprism/storage"
environment:
- PHOTOPRISM_DATABASE_DRIVER=mysql
- PHOTOPRISM_DATABASE_SERVER=mariadb:3306
- PHOTOPRISM_DATABASE_NAME=photoprism
- PHOTOPRISM_DATABASE_USER=${MARIADB_USER}
- PHOTOPRISM_DATABASE_PASSWORD=${PHOTOPRISM_DATABASE_PASSWORD}
- PHOTOPRISM_ADMIN_USER=${PHOTOPRISM_ADMIN_USER}
- PHOTOPRISM_ADMIN_PASSWORD=${PHOTOPRISM_ADMIN_PASSWORD}
- PHOTOPRISM_SITE_URL=https://photoprism.tellserv.fr/
- PHOTOPRISM_HTTP_COMPRESSION=gzip
- PHOTOPRISM_JPEG_QUALITY=85
networks:
- traefik_network
labels:
- "traefik.enable=true"
- "traefik.http.routers.${COMPOSE_PROJECT_NAME}-local.rule=Host(`${COMPOSE_PROJECT_NAME}.local.tellserv.fr`)"
- "traefik.http.routers.${COMPOSE_PROJECT_NAME}-local.entryPoints=local"
- "traefik.http.routers.${COMPOSE_PROJECT_NAME}-local.tls=true"
- "traefik.http.routers.${COMPOSE_PROJECT_NAME}-prod.rule=Host(`${COMPOSE_PROJECT_NAME}.tellserv.fr`)"
- "traefik.http.routers.${COMPOSE_PROJECT_NAME}-prod.entryPoints=websecure"
- "traefik.http.routers.${COMPOSE_PROJECT_NAME}-prod.tls.certResolver=cloudflare"
- "traefik.http.services.${COMPOSE_PROJECT_NAME}.loadbalancer.server.port=2342"
- "com.centurylinklabs.watchtower.enable=true"
mariadb:
image: mariadb:11
restart: unless-stopped
stop_grace_period: 5s
command: >
--innodb-buffer-pool-size=512M
--transaction-isolation=READ-COMMITTED
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--max-connections=512
volumes:
- ./database:/var/lib/mysql
environment:
- MARIADB_DATABASE=photoprism
- MARIADB_USER=${MARIADB_USER}
- MARIADB_PASSWORD=${MARIADB_PASSWORD}
- MARIADB_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD}
networks:
- traefik_network
networks:
traefik_network:
external: true
```
**Key points**:
- **Dependencies**: `depends_on` ensures MariaDB starts before Photoprism
- **Mounted volumes**: Access to MergerFS storage (`/mnt/storage`) for photos
- **Database**: MariaDB optimized for Photoprism (buffer pool, character set UTF-8)
- **Environment variables**: Secrets injected via `.env` file (not versioned)
- **Dual exposure**: Accessible locally (`.local.tellserv.fr`) and on the Internet (`.tellserv.fr`)
- **Watchtower**: Label to enable automatic updates
- **DB optimizations**: Adapted MariaDB configuration (buffer pool, connections, charset)
### Example 3: Mobilizon - Multi-container application with internal network
Mobilizon demonstrates the use of **multiple Docker networks** (external + internal):
```yaml
services:
mobilizon:
user: "1000:1000"
restart: always
image: docker.io/framasoft/mobilizon
env_file: .env
depends_on:
- db
volumes:
- ./uploads:/var/lib/mobilizon/uploads
- ./tzdata:/var/lib/mobilizon/tzdata
networks:
- traefik_network
- mobilizon_internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.mobilizon-local.rule=Host(`mobilizon.local.tellserv.fr`)"
- "traefik.http.routers.mobilizon-local.entryPoints=local"
- "traefik.http.routers.mobilizon-prod.rule=Host(`mobilizon.tellserv.fr`)"
- "traefik.http.routers.mobilizon-prod.entryPoints=websecure"
- "traefik.http.routers.mobilizon-prod.tls.certResolver=cloudflare"
- "traefik.http.services.mobilizon.loadbalancer.server.port=5005"
db:
image: docker.io/postgis/postgis:15-3.4
restart: always
env_file: .env
volumes:
- ./db:/var/lib/postgresql/data:z
networks:
- mobilizon_internal
networks:
mobilizon_internal:
ipam:
driver: default
traefik_network:
external: true
```
**Key points**:
- **Two networks**:
- `traefik_network` (external): Mobilizon communicates with Traefik
- `mobilizon_internal` (internal): Private communication between Mobilizon and PostgreSQL
- **Security**: The database is not exposed on the Traefik network
- **PostgreSQL with PostGIS**: Geographic extension to manage geolocated events
- **User ID**: Execution with specific UID/GID to manage file permissions
- **Volume with SELinux**: Flag `:z` for SELinux compatibility
### Example 4: Vaultwarden - Secrets management
Vaultwarden (password manager) shows a security-focused configuration:
```yaml
services:
vaultwarden:
image: vaultwarden/server:1.32.7
container_name: vaultwarden
restart: unless-stopped
environment:
- TZ=Europe/Paris
- ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN}
- SIGNUPS_ALLOWED=${SIGNUPS_ALLOWED}
- SMTP_FROM=${SMTP_FROM}
- SMTP_HOST=${SMTP_HOST}
- SMTP_PORT=${SMTP_PORT}
- SMTP_SECURITY=${SMTP_SECURITY}
- SMTP_USERNAME=${SMTP_USERNAME}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- EXPERIMENTAL_CLIENT_FEATURE_FLAGS=ssh-key-vault-item,ssh-agent
volumes:
- ./vw-data:/data
networks:
- traefik_network
labels:
- "traefik.enable=true"
- "traefik.http.routers.vaultwarden-local.rule=Host(`vaultwarden.local.tellserv.fr`)"
- "traefik.http.routers.vaultwarden-prod.rule=Host(`vaultwarden.tellserv.fr`)"
- "traefik.http.routers.vaultwarden-prod.tls.certResolver=cloudflare"
- "com.centurylinklabs.watchtower.enable=true"
networks:
traefik_network:
external: true
```
**Key points**:
- **Secrets via .env**: All passwords and tokens in environment variables
- **SMTP configuration**: Email sending for notifications and account recovery
- **Experimental features**: SSH key support in the vault
- **Data volume**: Vault persistence in `./vw-data`
- **Secure exposure**: HTTPS mandatory via Traefik with Let's Encrypt
## Patterns and best practices ## Patterns and best practices
1. **External network `traefik_network`**: All services share a common Docker network ### 1. External network `traefik_network`
2. **Traefik labels**: Dynamic configuration via Docker labels
3. **Environment variables with .env files**: Secrets extracted from Compose files
4. **Dual exposure**: local and production access for each service
5. **Restart policies**: `unless-stopped` for resilience
6. **Watchtower for monitoring**: Watchtower is used **only for notifications** of available image updates. Updates are performed **manually** to maintain control over changes. In the [Future Homelab](../homelab-futur/index.md), automated update management will be implemented via Renovate Bot integrated directly with Forgejo.
## Benefits for a homelab All my services use a shared **external Docker network**:
- **Simplicity**: Readable and maintainable YAML files ```yaml
- **Performance**: Instant service startup, low overhead networks:
- **Flexibility**: Easy to add/remove services traefik_network:
- **Rich ecosystem**: Docker Hub with thousands of ready-to-use images external: true
```
Advantages:
- Traefik automatically detects new services
- Communication between services via their names (e.g. `http://vaultwarden`)
- Isolation by default (unconnected services cannot communicate)
### 2. Traefik labels for dynamic configuration
Instead of static configuration files, I use **Docker labels**:
```yaml
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`myapp.tellserv.fr`)"
- "traefik.http.routers.myapp.tls.certResolver=cloudflare"
```
Advantages:
- Configuration colocated with the service
- Deploying a new service = automatic addition to Traefik
- No manual Traefik reload
### 3. Environment variables with .env files
All secrets are extracted into `.env` files:
```env
VAULTWARDEN_ADMIN_TOKEN=supersecret123
MARIADB_PASSWORD=dbpassword456
CF_DNS_API_TOKEN=cloudflare_token_789
```
Advantages:
- No secrets in plain text in versioned Compose files
- `.env` files generated dynamically by Ansible (Jinja2 templates)
- Easy secret rotation
### 4. Dual exposure: local and production
Each service has two entries:
- **Local**: `service.local.tellserv.fr` (local network only)
- **Production**: `service.tellserv.fr` (accessible from the Internet)
```yaml
labels:
- "traefik.http.routers.myapp-local.rule=Host(`myapp.local.tellserv.fr`)"
- "traefik.http.routers.myapp-local.entryPoints=local"
- "traefik.http.routers.myapp-prod.rule=Host(`myapp.tellserv.fr`)"
- "traefik.http.routers.myapp-prod.entryPoints=websecure"
```
Advantages:
- Fast local access (no Internet latency)
- Remote access possible when needed
- Ability to restrict certain services to local only
### 5. Restart policies and graceful shutdown
Resilience configuration:
```yaml
restart: unless-stopped
stop_grace_period: 10s
```
- `unless-stopped`: Restarts automatically except if manually stopped
- `stop_grace_period`: Time to terminate cleanly before SIGKILL
### 6. Watchtower for update monitoring
Label to enable monitoring:
```yaml
labels:
- "com.centurylinklabs.watchtower.enable=true"
```
**Important**: Watchtower is used **only for notifications** of new available image versions. Updates are performed **manually** to maintain control over changes.
In the [Future Homelab](../homelab-futur/index.md), automated update management will be implemented via Renovate Bot integrated directly with Forgejo.
## Managing stacks with Docker Compose
### Essential commands
```bash
# Start all services
docker compose up -d
# Stop all services
docker compose down
# View logs for a service
docker compose logs -f service_name
# Restart a service
docker compose restart service_name
# Update images and redeploy
docker compose pull
docker compose up -d
# View container status
docker compose ps
```
### Deployment via Ansible
In my configuration, stacks are automatically deployed by Ansible:
1. Generation of `.env` files from templates
2. Synchronization of `stacks/` folders to `/opt/stacks/`
3. Execution of `docker compose up -d` for each stack
See the [Ansible Playbooks](./playbooks-ansible.md) page for more details.
## Advantages of Docker Compose for a homelab
### Simplicity
- Readable and maintainable YAML files
- No complex syntax like Kubernetes
- Gentle learning curve
### Performance
- Instant service startup
- Low overhead (no Kubernetes cluster)
- Ideal for modest machines
### Flexibility
- Easy to add/remove services
- Ability to quickly test new applications
- Configuration by environment (dev, staging, prod)
### Rich ecosystem
- Docker Hub: thousands of ready-to-use images
- LinuxServer.io: optimized and well-maintained images
- Active community: documentation and support
## Docker Compose limitations
Despite its advantages, Docker Compose has limitations for large-scale production use:
1. **No high availability**: Everything is on a single machine
2. **No horizontal scaling**: Impossible to distribute load across multiple servers
3. **No advanced orchestration**: No rolling updates, canary deployments, etc.
4. **Manual management**: Deployments via Ansible, no native GitOps
**Note**: Using `restart: unless-stopped` ensures automatic restart of containers after an unexpected stop, providing a basic form of resilience.
These limitations explain why I'm migrating to **Kubernetes (K3S)** for the future homelab. See the [Future Homelab](../homelab-futur/index.md) section.
## Why not Docker Swarm? ## Why not Docker Swarm?
@ -89,7 +501,3 @@ When considering the evolution of my infrastructure, **Docker Swarm** was evalua
5. **Learning objective**: My goal being to acquire modern DevOps skills, mastering Kubernetes is a better long-term investment. 5. **Learning objective**: My goal being to acquire modern DevOps skills, mastering Kubernetes is a better long-term investment.
**Conclusion**: Although Docker Swarm is simpler and sufficient for many homelabs, I preferred to invest directly in learning Kubernetes, which has become the essential standard for container orchestration. **Conclusion**: Although Docker Swarm is simpler and sufficient for many homelabs, I preferred to invest directly in learning Kubernetes, which has become the essential standard for container orchestration.
:::note
Detailed English translation of this page is in progress.
:::