# Tutorial 3: Dipendenze tra Servizi con Healthchecks In questo tutorial imparerai a configurare dipendenze tra servizi usando `depends_on`, assicurando che i servizi partano nell'ordine corretto. ## Obiettivi di Apprendimento Al termine di questo tutorial sarai in grado di: - Comprendere le dipendenze tra servizi in applicazioni multi-tier - Configurare `depends_on` con conditions - Implementare startup ordinato con healthchecks - Verificare l'ordine di avvio dei servizi --- ## Prerequisiti - Completamento di Tutorial 1 e 2 - Servizi configurati con resource limits e healthchecks - Comprensione base di architetture multi-tier --- ## Parte 1: Dipendenze tra Servizi ### Cos'è una Dipendenza? In un'applicazione multi-tier, i servizi dipendono l'uno dall'altro: ``` Web → App → Database ``` - Il **Web** server ha bisogno dell'**App** server - L'**App** server ha bisogno del **Database** - Il **Database** non dipende da nessuno (parte prima) ### Perché sono Importanti? 1. **Prevenzione Errori:** Evita connection error a servizi non pronti 2. **Startup Affidabile:** Ogni servizio aspetta che le sue dipendenze siano pronte 3. **Zero-Downtime:** Durante deployment, i nuovi servizi aspettano i vecchi 4. **Debugging:** Problemi di connessione sono più facili da diagnosticare --- ## Parte 2: Tipi di Dipendenze ### depends_on: service_started (Default) ```yaml services: app: depends_on: - db ``` **Comportamento:** `app` parte quando `db` è **avviato** (non necessariamente healthy) **Problema:** Il database potrebbe ancora essere inizializzando → connection errors ### depends_on: service_healthy (Raccomandato) ```yaml services: app: depends_on: db: condition: service_healthy ``` **Comportamento:** `app` parte quando `db` è **healthy** (dopo healthcheck pass) **Vantaggio:** Il database è completamente pronto → nessun connection error --- ## Parte 3: Pratica - Architettura Multi-Tier Creiamo un'applicazione a 3 tier con dipendenze: ``` Web (t2.micro) → App (t2.small) → DB (t2.medium) ``` ### Step 1: Configurare il Database (Primo) ```yaml version: "3.8" services: # Tier 3: Database - nessuna dipendenza db: image: postgres:16-alpine container_name: lab03-db hostname: db environment: POSTGRES_DB: lab03_db POSTGRES_USER: lab03_user POSTGRES_PASSWORD: lab03_password deploy: resources: limits: cpus: '2' memory: 4G healthcheck: test: ["CMD-SHELL", "pg_isready -U lab03_user -d lab03_db || exit 1"] interval: 10s timeout: 5s retries: 5 start_period: 10s volumes: - db-data:/var/lib/postgresql/data restart: unless-stopped volumes: db-data: ``` **Nota:** Il database non ha `depends_on` - è il primo a partire. ### Step 2: Configurare l'App Server ```yaml # Tier 2: Application - dipende dal database app: image: nginx:alpine container_name: lab03-app hostname: app deploy: resources: limits: cpus: '1' memory: 2G healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"] interval: 10s timeout: 5s retries: 3 start_period: 5s ports: - "127.0.0.1:8081:80" # Dipende dal database healthy depends_on: db: condition: service_healthy restart: unless-stopped ``` **Nota:** `app` parte SOLO quando `db` è `healthy`. ### Step 3: Configurare il Web Server ```yaml # Tier 1: Web - dipende dall'app web: image: nginx:alpine container_name: lab03-web hostname: web deploy: resources: limits: cpus: '1' memory: 1G healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"] interval: 10s timeout: 5s retries: 3 start_period: 5s ports: - "127.0.0.1:8080:80" # Dipende dall'app healthy depends_on: app: condition: service_healthy restart: unless-stopped ``` **Nota:** `web` parte SOLO quando `db` → `app` sono entrambi `healthy`. --- ## Parte 4: Avvio e Verifica ### Step 1: Avviare tutti i servizi ```bash cd labs/lab-03-compute docker compose up -d ``` ### Step 2: Osservare l'ordine di avvio ```bash # Monitora lo stato in tempo reale watch -n 2 'docker ps --format "table {{.Names}}\t{{.Status}}"' ``` **Sequenza prevista:** 1. `lab03-db` parte → `starting` → `(healthy)` dopo ~10-20s 2. `lab03-app` parte → `starting` → `(healthy)` dopo che `db` è healthy 3. `lab03-web` parte → `starting` → `(healthy)` dopo che `app` è healthy ### Step 3: Verificare l'ordine nei log ```bash docker compose logs --tail=50 ``` Cerca messaggi tipo: ``` lab03-db | database system is ready to accept connections lab03-app | Waiting for db to be healthy... lab03-web | Waiting for app to be healthy... ``` --- ## Parte 5: Testare le Dipendenze ### Test 1: Riavviare il database ```bash # Ferma il database docker compose stop db # Guarda lo stato di app e web docker ps ``` **Risultato:** `app` e `web` rimangono in esecuzione (non dipendono dal runtime di db, solo dall'avvio iniziale) ### Test 2: Ferma e riavvia l'app ```bash # Ferma l'app docker compose stop app # Guarda lo stato del web docker ps ``` **Risultato:** `web` continua a funzionare (stessa logica) ### Test 3: Riavvio completo ```bash # Ferma tutto docker compose down # Riavvia docker compose up -d # Osserva l'ordine di startup docker compose up -d && docker compose logs -f ``` Vedrai: `db` → `app` → `web` in ordine. --- ## Parte 6: Parallelismo AWS ### ECS Task Definitions In AWS ECS, le dipendenze si configurano nel Task Definition: ```json { "containerDefinitions": [ { "name": "db", "essential": true, "healthCheck": { "command": ["CMD-SHELL", "pg_isready -U postgres"], "interval": 10, "timeout": 5, "retries": 5 } }, { "name": "app", "essential": true, "dependsOn": [ { "containerName": "db", "condition": "HEALTHY" } ] }, { "name": "web", "essential": true, "dependsOn": [ { "containerName": "app", "condition": "HEALTHY" } ] } ] } ``` ### Condizioni di Dipendenza ECS | Condizione | Docker Equivalente | Descrizione | |------------|-------------------|-------------| | START | `depends_on` (default) | Container avviato | | HEALTHY | `condition: service_healthy` | Healthcheck passing | | COMPLETE | - | Container exit code 0 | | SUCCESS | - | Container exit code 0 | --- ## Parte 7: Best Practices ### 1. Usa Sempre service_healthy ```yaml # ✓ GOOD depends_on: db: condition: service_healthy # ✗ AVOID (se possibile) depends_on: - db ``` ### 2. Configura healthcheck appropriati ```yaml # Database - startup più lento healthcheck: retries: 5 start_period: 10s # Web server - startup veloce healthcheck: retries: 3 start_period: 5s ``` ### 3. Previeni loop di dipendenze ```yaml # ✗ WRONG - circular dependency web: depends_on: app: {condition: service_healthy} app: depends_on: web: {condition: service_healthy} # LOOP! # ✓ GOOD - directional dependency web: depends_on: app: {condition: service_healthy} app: depends_on: db: {condition: service_healthy} # OK db: # No dependencies - base tier ``` --- ## Riepilogo In questo tutorial hai imparato: ✓ **Concetto:** Dipendenze tra servizi per startup ordinato ✓ **Sintassi:** `depends_on` con `condition: service_healthy` ✓ **Pratica:** Architettura multi-tier Web → App → DB ✓ **Verifica:** Osservare l'ordine di startup ✓ **Parallelismo:** ECS `dependsOn` con condizione HEALTHY --- ## Complimenti! Hai completato i tutorial di Lab 03 - Compute & EC2! **Competenze Acquisite:** - Configurare limiti delle risorse (EC2 instance types) - Implementare healthchecks (ELB health checks) - Gestire dipendenze tra servizi (ECS task definitions) **Prossimi Passi:** - Esegui i test di verifica: `bash tests/run-all-tests.sh` - Esplora le guide How-to per procedure specifiche - Consulta i documenti Reference per sintassi completa - Leggi Explanation per approfondire i parallelismi cloud