Tens els quatre serveis declarats i domines la CLI. Falta allò que de debò converteix quatre contenidors en una aplicació: com es troben entre ells, què pot parlar amb què, i en quin ordre han d'estar preparats.
En aquesta lliçó muntes la pila definitiva d'Aurora Libros: DNS intern, dues xarxes segmentades perquè la web no pugui tocar la base de dades, arrencada coordinada amb sondes de salut reals, un servei de migració que corre una vegada i acaba, i el patró de reintent que cal encara que tot l'anterior estigui bé. Al final, els quinze passos d'onboarding de la lliçó 01-07 s'hauran quedat en dos.
Contingut
- L'arquitectura final
- Com es troben els serveis: el DNS de Compose
- Qui parla amb qui i per quin port
- Segmentació en dues xarxes
- Demostració: la web no arriba a la base de dades
- L'ordre d'arrencada: per què
depends_ona seques no n'hi ha prou - Sondes de salut reals i
condition: service_healthy - Un servei que corre una vegada:
service_completed_successfully - Per què l'aplicació ha de reintentar igualment
- El
compose.yamlcomplet i comentat - Posada en marxa end-to-end
- El recompte de l'onboarding
- L'arquitectura final
graph TB
U["Navegador<br/>localhost:8080"] --> W
subgraph FRONTAL["xarxa frontal (bridge)"]
W["aurora-web<br/>nginx:alpine<br/>proxy invers"]
A1["aurora-api"]
end
subgraph POSTERIOR["xarxa posterior (internal: true)"]
A2["aurora-api<br/>node:22-alpine :3000"]
D["aurora-db<br/>postgres:16 :5432"]
C["aurora-cache<br/>redis:7 :6379"]
M["aurora-migracions<br/>corre una vegada"]
end
W -->|"proxy /api → aurora-api:3000"| A1
A1 -.mateix contenidor.- A2
A2 -->|"SQL :5432"| D
A2 -->|"cache-aside :6379"| C
M -->|"aplica l'esquema"| D
D --> V[("volum<br/>aurora-dades")]
aurora-api és l'únic servei que està a les dues xarxes: és la frontera. Tot el que entra des de fora passa per aurora-web, i tot el que toca les dades viu en una xarxa sense sortida a l'exterior.
- Com es troben els serveis: el DNS de Compose
A la lliçó 03-05 vas veure que una xarxa bridge d'usuari incorpora un servidor DNS intern a 127.0.0.11. Compose es recolza exactament en això, amb una precisió que convé gravar-se:
El nom de host d'un servei és el nom del servei, no el del contenidor.
El contenidor es diu aurora-libros-aurora-db-1, però des de l'API et connectes a aurora-db. Compose registra al DNS de cada xarxa:
| Nom registrat | Origen |
|---|---|
aurora-db |
Nom del servei (sempre) |
base-de-dades |
Qualsevol aliases que declaris |
aurora-libros-aurora-db-1 |
Nom del contenidor |
Els àlies resulten molt útils en migrar: si el codi heretat busca postgres, hi afegeixes aliases: [postgres] i funciona sense tocar ni una línia de l'aplicació.
Una conseqüència important: la resolució és per xarxa. Un servei només resol els noms dels serveis amb qui comparteix alguna xarxa. És la base de la segmentació de l'apartat 4.
- Qui parla amb qui i per quin port
Aquí hi ha l'error conceptual més repetit amb Compose: fer servir el port publicat en comptes de l'intern. La publicació (ports) és una porta des del host cap a dins; entre contenidors no hi intervé per a res.
| Origen | Destí | Host que fa servir | Port | Xarxa |
|---|---|---|---|---|
| Navegador | aurora-web |
localhost |
8080 (publicat) | — |
aurora-web |
aurora-api |
aurora-api |
3000 (intern) | frontal |
aurora-api |
aurora-db |
aurora-db |
5432 (intern) | posterior |
aurora-api |
aurora-cache |
aurora-cache |
6379 (intern) | posterior |
aurora-migracions |
aurora-db |
aurora-db |
5432 (intern) | posterior |
Només la primera fila fa servir un port publicat, perquè és l'única que entra des del host. La resta viatja per la xarxa interna de Docker.
Això es reflecteix al web/nginx.conf que ja vas escriure al mòdul 3, on proxy_pass http://aurora-api:3000/; fa servir nom de servei i port intern. I a les variables de l'API: DB_HOST=aurora-db, REDIS_HOST=aurora-cache. Res de localhost, res d'adreces IP, res de ports publicats.
- Segmentació en dues xarxes
Amb una sola xarxa, els quatre serveis es veuen entre ells. Funciona, però significa que si algú compromet el contenidor de nginx —el més exposat, l'únic que rep trànsit de fora— té accés directe al port 5432 de PostgreSQL. La bona pràctica és segmentar per zones:
| Xarxa | internal |
Serveis | Funció |
|---|---|---|---|
frontal |
no | aurora-web, aurora-api |
Trànsit d'entrada i proxy invers |
posterior |
sí | aurora-api, aurora-db, aurora-cache, aurora-migracions |
Dades, sense sortida a Internet |
internal: true fa dues coses: els contenidors d'aquesta xarxa no tenen ruta cap a l'exterior (ni tan sols poden fer ping a Internet) i ningú des de fora del host no els pot abastar. Si una dependència compromesa de PostgreSQL intentés trucar a casa, no tindria per on.
Efecte col·lateral que convé conèixer: un contenidor connectat només a xarxes internes no pot publicar ports al host. Per això aurora-db deixa de publicar 127.0.0.1:5432; per accedir a la base de dades faràs servir docker compose exec, i l'entorn de desenvolupament (lliçó 04-07) la tornarà a exposar afegint el servei a una xarxa no interna.
- Demostració: la web no arriba a la base de dades
La segmentació no és teoria: es comprova.
docker compose exec aurora-web getent hosts aurora-api
docker compose exec aurora-web getent hosts aurora-dbLa primera resol; la segona no retorna res i acaba amb codi 2. aurora-web i aurora-db no comparteixen cap xarxa, així que per a nginx la base de dades senzillament no existeix al DNS. Amb la caixa d'eines de xarxa de la lliçó 03-04, la diferència entre les dues xarxes és taxativa:
docker run --rm --network aurora-libros_frontal nicolaka/netshoot nc -zv -w 2 aurora-db 5432
docker run --rm --network aurora-libros_posterior nicolaka/netshoot nc -zv -w 2 aurora-db 5432
docker compose exec aurora-db ping -c 1 -W 2 8.8.8.8nc: getaddrinfo for host "aurora-db" port 5432: Name does not resolve
Connection to aurora-db (172.21.0.3) 5432 port [tcp/*] succeeded!
ping: sendto: Network is unreachableDes de frontal el nom ni tan sols resol; des de posterior connecta; i la mateixa base de dades no té sortida a Internet. Aquesta és la diferència entre "funciona" i "funciona i a més conté el dany". L'enduriment complet arriba a la lliçó 05-03.
- L'ordre d'arrencada: per què
depends_on a seques no n'hi ha prou
depends_on a seques no n'hi ha prouProva què passa sense cap condició, amb depends_on: [aurora-db] a l'API:
aurora-api-1 | Error: connect ECONNREFUSED 172.21.0.3:5432
aurora-api-1 | Fallada en connectar amb la base de dades, sortint
aurora-api-1 | exited with code 1Compose ha complert la seva promesa: va arrencar aurora-db abans. El problema és què significa "abans". Hi ha tres estats diferents i només el tercer serveix:
| Estat | Significa | Accepta connexions? |
|---|---|---|
| Creat | El contenidor existeix | No |
| Arrencat | El procés està corrent (depends_on curt) |
Encara no |
Preparat (healthy) |
La sonda de salut passa | Sí |
PostgreSQL triga entre 3 i 10 segons des que el procés arrenca fins que accepta connexions, i a la primera arrencada, amb init.sql per executar, força més. La distinció entre "arrencat" i "preparat" és la que trenca la meitat dels compose.yaml que circulen per aquí.
- Sondes de salut reals i
condition: service_healthy
condition: service_healthyLa solució té dues meitats. Primera: sondes que diguin la veritat sobre cada servei.
| Servei | test |
Per què aquesta comprovació |
|---|---|---|
aurora-db |
pg_isready -U aurora -d aurora_llibres |
Eina oficial de PostgreSQL: retorna 0 només quan accepta connexions en aquesta base. Durant la inicialització, el port està obert però les connexions es rebutgen |
aurora-cache |
redis-cli ping |
Retorna PONG i codi 0 només si el servidor respon de debò |
aurora-api |
wget --spider -q http://localhost:3000/salut |
L'endpoint propi, que al seu torn comprova base de dades i memòria cau |
aurora-web |
wget --spider -q http://localhost/ |
nginx serveix la pàgina |
Segona meitat: declarar la dependència de la salut, no de l'arrencada.
aurora-api:
depends_on:
aurora-db:
condition: service_healthy
aurora-cache:
condition: service_healthyAra Compose no llança l'API fins que totes dues sondes passen. Si una no arriba mai a healthy, up --wait falla amb un missatge clar en comptes de deixar-te un servei reiniciant-se en bucle.
- Un servei que corre una vegada:
service_completed_successfully
service_completed_successfullyAurora Libros necessita aplicar l'esquema i les migracions abans que l'API atengui peticions. Això no és un servei permanent: és una tasca que corre, acaba i desapareix.
aurora-migracions:
image: auroralibros/aurora-api:1.2.0 # mateixa imatge, una altra comanda
command: ["node", "migrar.js"]
environment:
DB_HOST: aurora-db
DB_USER: aurora
DB_PASSWORD: aurora_secreta
DB_NAME: aurora_llibres
depends_on:
aurora-db:
condition: service_healthy
restart: "no" # que NO es reiniciï en acabar
networks: [posterior]I l'API espera que acabi bé:
Dos detalls que es passen per alt: restart: "no" és imprescindible —amb unless-stopped heretat d'una àncora, el contenidor es reiniciaria en bucle eternament en acabar—, i les cometes també, perquè no sense elles és el booleà false en YAML. A més, la condició exigeix codi de sortida 0: si la migració falla, l'API ni tan sols es crea, i aquest és justament el comportament correcte.
- Per què l'aplicació ha de reintentar igualment
Amb tot l'anterior, l'arrencada en fred està resolta. Però no la resta de casos: si aurora-db es reinicia a les tres de la matinada per una fallada de disc, l'API ja està corrent i depends_on no es torna a avaluar; en un orquestrador, els contenidors es reprogramen en qualsevol ordre; i una caiguda de xarxa de dos segons no l'arregla cap fitxer YAML.
depends_on resol l'arrencada; la reconnexió és responsabilitat de l'aplicació. Afegeix a api/server.js un reintent amb retrocés exponencial:
async function connectarAmbReintents(crearConnexio, { intents = 8, baseMs = 500 } = {}) {
for (let i = 1; i <= intents; i++) {
try {
return await crearConnexio();
} catch (err) {
if (i === intents) throw err;
// 0,5 s · 1 s · 2 s · 4 s ... amb jitter per no sincronitzar reintents
const espera = Math.min(baseMs * 2 ** (i - 1), 30_000) + Math.random() * 250;
console.warn(`Connexió fallida (intent ${i}/${intents}): ${err.message}. ` +
`Reintent en ${Math.round(espera)} ms`);
await new Promise((r) => setTimeout(r, espera));
}
}
}
const pool = await connectarAmbReintents(async () => {
const p = new Pool({ host: process.env.DB_HOST, user: process.env.DB_USER,
password: process.env.DB_PASSWORD, database: process.env.DB_NAME });
await p.query('SELECT 1'); // no n'hi ha prou de crear el pool: cal provar-lo
return p;
});Tres decisions de disseny: el retrocés exponencial evita martellejar una base de dades que està arrencant, el jitter aleatori impedeix que deu rèpliques reintentin a l'uníson, i la prova SELECT 1 és el que distingeix "tinc un objecte de connexió" de "la base de dades em respon". La memòria cau mereix un tracte diferent: si Redis no hi és, /llibres ha de continuar servint des de PostgreSQL amb origen: db. Una memòria cau és un accelerador, mai una dependència dura.
- El
compose.yaml complet i comentat
compose.yaml complet i comentat# compose.yaml — Aurora Libros S.L. — plataforma completa
name: aurora-libros
x-comu: &comu
restart: unless-stopped
logging:
driver: json-file
options: { max-size: "10m", max-file: "3" }
labels: { com.auroralibros.projecte: "aurora-libros" }
services:
# --- Dades: PostgreSQL amb el catàleg ----------------------------------
aurora-db:
<<: *comu
image: postgres:16-alpine
environment:
POSTGRES_USER: aurora
POSTGRES_PASSWORD: aurora_secreta
POSTGRES_DB: aurora_llibres
volumes:
- aurora-dades:/var/lib/postgresql/data
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U aurora -d aurora_llibres"]
interval: 5s
timeout: 5s
retries: 10
start_period: 30s # la primera inicialització executa init.sql
stop_grace_period: 30s # marge per tancar el checkpoint
deploy:
resources: { limits: { memory: 512M, cpus: "1.0", pids: 200 }, reservations: { memory: 256M } }
networks: [posterior] # NOMÉS a la xarxa interna
# --- Memòria cau: Redis en mode cache-aside ----------------------------
aurora-cache:
<<: *comu
image: redis:7-alpine
command: ["redis-server", "--maxmemory", "200mb", "--maxmemory-policy", "allkeys-lru"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
deploy:
resources: { limits: { memory: 256M, cpus: "0.5", pids: 100 } }
networks: [posterior]
# --- Migracions: corre una vegada i acaba ------------------------------
aurora-migracions:
image: auroralibros/aurora-api:1.2.0
command: ["node", "migrar.js"]
environment:
DB_HOST: aurora-db
DB_USER: aurora
DB_PASSWORD: aurora_secreta
DB_NAME: aurora_llibres
depends_on:
aurora-db: { condition: service_healthy }
restart: "no" # entre cometes: sense elles seria el booleà false
networks: [posterior]
# --- API: la frontera entre les dues xarxes ----------------------------
aurora-api:
<<: *comu
build:
context: ./api
dockerfile: Dockerfile
image: auroralibros/aurora-api:1.2.0
environment:
PORT: "3000"
DB_HOST: aurora-db # nom de SERVEI
DB_USER: aurora
DB_PASSWORD: aurora_secreta
DB_NAME: aurora_llibres
REDIS_HOST: aurora-cache
depends_on:
aurora-db: { condition: service_healthy }
aurora-cache: { condition: service_healthy }
aurora-migracions: { condition: service_completed_successfully }
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/salut"]
interval: 10s
timeout: 3s
retries: 3
start_period: 20s
restart: on-failure:3
deploy:
resources: { limits: { memory: 256M, cpus: "1.0", pids: 100 }, reservations: { memory: 128M } }
networks: [frontal, posterior] # l'únic servei a totes dues
# --- Web: pàgina estàtica i proxy invers -------------------------------
aurora-web:
<<: *comu
image: nginx:alpine
ports:
- "8080:80" # l'ÚNICA porta des del host
volumes:
- ./web/index.html:/usr/share/nginx/html/index.html:ro
- ./web/nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
aurora-api: { condition: service_healthy }
stop_signal: SIGQUIT # nginx s'atura ordenadament amb SIGQUIT
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost/"]
interval: 15s
timeout: 3s
retries: 3
deploy:
resources: { limits: { memory: 128M, cpus: "0.5", pids: 50 } }
networks: [frontal] # sense accés a les dades
volumes:
aurora-dades:
networks:
frontal:
driver: bridge
posterior:
driver: bridge
internal: true # sense sortida a Internet ni entrada des de foraCent trenta línies comentades que substitueixen cinquanta línies de bash i, sobretot, expressen coses que l'script no sabia dir: qui depèn de qui, què significa estar preparat, i què pot parlar amb què.
- Posada en marxa end-to-end
cd ~/aurora-libros
docker compose down -v # partim de zero, és un entorn de proves
docker compose up -d --build --wait[+] Running 8/8
✔ Network aurora-libros_frontal Created
✔ Network aurora-libros_posterior Created
✔ Volume "aurora-libros_aurora-dades" Created
✔ Container aurora-libros-aurora-db-1 Healthy
✔ Container aurora-libros-aurora-cache-1 Healthy
✔ Container aurora-libros-aurora-migracions-1 Exited
✔ Container aurora-libros-aurora-api-1 Healthy
✔ Container aurora-libros-aurora-web-1 HealthyLlegeix la seqüència: les dues xarxes i el volum primer, després base de dades i memòria cau fins a Healthy, tot seguit les migracions fins a Exited amb codi 0, i només llavors l'API i la web. L'ordre ja no l'escrius tu: el dedueix Compose del graf de dependències.
SERVICE STATUS
aurora-api Up 20 seconds (healthy)
aurora-cache Up 46 seconds (healthy)
aurora-db Up 46 seconds (healthy)
aurora-migracions Exited (0) 32 seconds ago
aurora-web Up 8 seconds (healthy)La prova de foc: la cache-aside en funcionament i, després, la resiliència que vam exigir a l'apartat 9.
curl -s http://localhost:8080/api/llibres | jq '{origen, total: (.llibres|length)}'
curl -s http://localhost:8080/api/llibres | jq '{origen, total: (.llibres|length)}'
docker compose stop aurora-cache
curl -s http://localhost:8080/api/llibres | jq '{origen, total: (.llibres|length)}'
docker compose start aurora-cachePrimera petició des de PostgreSQL, segona des de Redis: els nou títols travessant web → api → db → cache exactament com es va dissenyar, i http://localhost:8080 al navegador mostra el catàleg complet. I amb la memòria cau aturada, l'API continua servint des de la base de dades: degradació elegant, es perd velocitat, no servei.
- El recompte de l'onboarding
| Moment | Passos per tenir Aurora Libros funcionant |
|---|---|
| Lliçó 01-07, sense Docker | 15 passos manuals: Node, PostgreSQL, Redis, nginx, usuaris, esquema... |
Mòdul 3, amb docker run |
Un script de 50 línies que cal mantenir a mà |
| Ara | 2 comandes |
git clone https://github.com/auroralibros/plataforma.git && cd plataforma
docker compose up -d --waitAixò és tot. Algú que entra avui a l'equip té la plataforma completa —quatre serveis, dues xarxes, un volum, migracions aplicades i sondes de salut verificades— en menys d'un minut, i amb exactament la mateixa configuració que la resta de l'equip, perquè és a Git.
Errors Habituals i Consells
Fer servir el port publicat entre contenidors. DB_HOST=localhost:5432 des de l'API no troba res: dins del contenidor, localhost és ell mateix. Nom de servei i port intern, sempre.
Confiar en depends_on sense condition. Només garanteix ordre d'arrencada. Sense sondes de salut, continuaràs tenint curses.
Sondar el port en comptes del servei. nc -z aurora-db 5432 dóna verd mentre PostgreSQL encara rebutja connexions. Fes servir pg_isready.
Oblidar restart: "no" en un servei d'un sol ús. Amb una política heretada, la migració es reinicia en bucle i el service_completed_successfully no es compleix mai.
Suposar que depends_on reconnecta. No es torna a avaluar després de l'arrencada. La reconnexió amb reintents és de l'aplicació.
Tractar la memòria cau com una dependència dura. Si la teva API mor perquè Redis no respon, has convertit un accelerador opcional en un punt únic de fallada.
Consell: quan dos serveis no es vegin, la primera comprovació és sempre docker compose exec <origen> getent hosts <destí>. Si no resol, no és un problema de l'aplicació: és que no comparteixen xarxa.
Exercicis
Exercici 1. Afegeix a aurora-db l'àlies de xarxa postgres i demostra que l'API es pot connectar indistintament per aurora-db o per postgres, però que aurora-web no en resol cap dels dos.
Exercici 2. Trenca l'arrencada expressament: fes que aurora-migracions acabi amb codi 1 (per exemple, command: ["sh", "-c", "echo 'migració fallida'; exit 1"]) i observa què fa docker compose up -d --wait amb l'API i amb la web. Explica el resultat i per què és el comportament desitjable.
Exercici 3. Demostra que l'aïllament de posterior és real en les dues direccions: (a) aurora-db no pot sortir a Internet, (b) des d'una altra màquina de la teva xarxa local no es pot abastar el 5432, i (c) aurora-api sí que pot sortir a Internet. Explica per què (c) funciona tot i estar a la xarxa interna.
Solucions
Solució 1.
docker compose up -d
docker compose exec aurora-api getent hosts aurora-db
docker compose exec aurora-api getent hosts postgres
docker compose exec aurora-web getent hosts postgres; echo "codi: $?"La mateixa adreça per als dos noms: l'àlies és una entrada DNS addicional en aquesta xarxa, no un altre contenidor. Per a aurora-web, codi 2 (no resol), perquè els àlies viuen dins de la xarxa on es declaren i nginx no és a posterior. Aquest és el mecanisme amb què es migra un servei sense tocar el codi dels seus clients: primer s'afegeix l'àlies nou, després es canvia el nom del servei.
Solució 2.
docker compose up -d --wait; echo "codi de sortida: $?"
docker compose ps -a --format "table {{.Service}}\t{{.Status}}"dependency failed to start: container aurora-libros-aurora-migracions-1 exited (1)
codi de sortida: 1
SERVICE STATUS
aurora-cache Up 15 seconds (healthy)
aurora-db Up 15 seconds (healthy)
aurora-migracions Exited (1) 3 seconds agoNi aurora-api ni aurora-web no arriben a crear-se. Compose talla la cadena: si una dependència amb service_completed_successfully surt amb codi diferent de 0, tot el que en depèn es cancel·la, i aquesta fallada es propaga en cascada a la web, que depèn de l'API.
És exactament el que vols. L'alternativa —arrencar l'API contra un esquema a mig migrar— produiria errors intermitents, dades corruptes i una hora de depuració. A més, --wait retorna codi 1, així que un pipeline de CI es posa en vermell automàticament en comptes de continuar sobre una base trencada. Compara-ho amb l'script de bash del mòdul 3: allà, si el pas 4 fallava, els passos 5, 6 i 7 s'executaven igualment.
Solució 3.
# (a) la base de dades no surt a Internet
docker compose exec aurora-db ping -c 1 -W 2 1.1.1.1
# (b) el port 5432 no està publicat en cap interfície
ss -ltnp | grep 5432 || echo "5432 no publicat al host"
# (c) l'API sí que surt
docker compose exec aurora-api wget -qO- -T 3 https://example.com > /dev/null \
&& echo "l'API sí que té sortida"(a) i (b) confirmen el doble aïllament: internal: true elimina la ruta per defecte d'aquesta xarxa, i com que no hi ha ports a aurora-db, no existeix cap regla al host que hi redirigeixi —ni tan sols des del mateix host, i encara menys des d'una altra màquina de la xarxa local—.
(c) funciona perquè aurora-api és a les dues xarxes. Un contenidor connectat a diverses xarxes té una interfície a cadascuna, i la ruta per defecte l'hi dóna frontal, que no és interna. D'aquí que l'API sigui la "frontera": és l'únic punt pel qual la zona de dades es comunica amb el món, i per tant l'únic que cal vigilar de prop.
Conclusió
Aurora Libros està muntada de debò. Saps que els serveis es troben pel nom del servei —no el del contenidor— gràcies al DNS intern de cada xarxa, que els aliases afegeixen noms extra dins de la xarxa on es declaren, i que entre contenidors sempre es fa servir el port intern: la publicació de ports només obre una porta des del host, i en aquesta arquitectura n'hi ha exactament una, el 8080 de la web.
Has segmentat la plataforma en dues zones: una de frontal amb la web i l'API, i una de posterior marcada com a internal amb les dades i les migracions, i ho has demostrat en les dues direccions —nginx no resol ni tan sols el nom de la base de dades, i PostgreSQL no té ruta cap a Internet—, amb aurora-api com a única frontera per ser a totes dues xarxes. I tens resolta l'arrencada amb la distinció que separa un fitxer que funciona al teu portàtil d'un que funciona sempre: arrencat no és el mateix que preparat. pg_isready i redis-cli ping com a sondes honestes, condition: service_healthy per esperar que ho estiguin, service_completed_successfully amb restart: "no" per a la migració que corre una vegada, i el reintent amb retrocés exponencial i jitter a l'aplicació, perquè depends_on cobreix l'arrencada i res més. La memòria cau, tractada com el que és: un accelerador la caiguda del qual degrada el servei però no el tomba.
El recompte parla sol: de quinze passos manuals a un script de cinquanta línies, i d'aquí a git clone i docker compose up -d --wait. Però el fitxer encara té les contrasenyes escrites en clar, la versió de la imatge fixada a mà i els ports incrustats: exactament el que impedeix fer-lo servir en més d'un entorn. A la lliçó següent, Variables d'Entorn a Docker Compose, separaràs els dos sistemes que tothom confon —la substitució ${VAR} que Compose fa sobre el mateix YAML, i les variables que veu el procés dins del contenidor—, amb la seva taula de precedència completa, el fitxer .env del projecte i el seu .env.example versionat, i el bloc secrets: perquè les credencials deixin de ser visibles en un docker inspect.
Docker: De Principiant a Avançat
Mòdul 1: Introducció a Docker
- Què és Docker?
- Instal·lant Docker
- Arquitectura de Docker
- Comandes Bàsiques de Docker
- Entenent les Imatges de Docker
- Creant el teu Primer Contenidor Docker
- El Projecte del Curs: la Plataforma Aurora Libros
Mòdul 2: Treballant amb Imatges Docker
- Docker Hub i Repositoris
- Construint Imatges Docker
- Conceptes Bàsics de Dockerfile
- Instruccions Avançades del Dockerfile
- Gestionant Imatges Docker
- Etiquetatge i Publicació d'Imatges
Mòdul 3: Contenidors Docker
- Executant Contenidors
- Cicle de Vida del Contenidor
- Gestionant Contenidors
- Inspecció i Depuració de Contenidors
- Xarxes a Docker
- Persistència de Dades amb Volums
- Límits de Recursos i Polítiques de Reinici
Mòdul 4: Docker Compose
- Introducció a Docker Compose
- Definint Serveis a Docker Compose
- Comandes de Docker Compose
- Aplicacions Multi-Contenidor
- Variables d'Entorn a Docker Compose
- Perfils, Overrides i Múltiples Entorns
- Desenvolupament Local amb Docker Compose
Mòdul 5: Conceptes Avançats de Docker
- Aprofundiment en Xarxes Docker
- Opcions d'Emmagatzematge Docker
- Millors Pràctiques de Seguretat a Docker
- Optimitzant Imatges Docker
- Builds Avançades amb BuildKit i Buildx
- Registre i Monitoratge a Docker
- El Runtime per Dins: Namespaces, Cgroups i Capes
Mòdul 6: Docker en Producció
- Preparar una Imatge per a Producció
- CI/CD amb Docker
- Orquestrant Contenidors amb Docker Swarm
- Introducció a Kubernetes
- Desplegant Contenidors Docker a Kubernetes
- Escalat i Balanceig de Càrrega
- Estratègies de Desplegament i Rollback
