Vas acabar el mòdul 3 amb un script de bash de cinquanta línies que aixeca Aurora Libros. Funciona, però descriu com arribar a l'estat desitjat: crea la xarxa, crea el volum, arrenca la base de dades, espera amb un bucle, arrenca la memòria cau, l'API i la web, cadascuna amb les seves catorze línies d'opcions.

Docker Compose capgira el plantejament. En comptes d'una seqüència d'ordres, escrius un fitxer que diu quin és l'estat desitjat —quatre serveis, una xarxa, un volum— i deixes que Compose calculi els passos. El fitxer es diu compose.yaml, viu al repositori al costat del codi, es revisa en una pull request i s'aixeca amb una sola comanda.

En aquesta lliçó veuràs quin problema resol exactament Compose (i quin no resol), el YAML mínim imprescindible per no barallar-te amb la sintaxi, com Compose fa servir el concepte de projecte com a espai de noms, i escriuràs el teu primer compose.yaml amb dos dels quatre serveis d'Aurora Libros.

Contingut

  1. De cinquanta línies imperatives a quaranta declaratives
  2. Imperatiu enfront de declaratiu
  3. Què és Docker Compose i què no és
  4. Compose v2: un plugin de la CLI de Docker
  5. El mínim de YAML que necessites
  6. Errors de sintaxi YAML que veuràs segur
  7. Anatomia d'un compose.yaml
  8. El projecte com a espai de noms
  9. El teu primer compose.yaml: base de dades i memòria cau
  10. up, ps, logs, down: el cicle complet

  1. De cinquanta línies imperatives a quaranta declaratives

Recupera dos fragments de l'script del mòdul 3, el de la base de dades i el de la memòria cau:

docker network create aurora-net
docker volume create aurora-dades

docker run -d --name aurora-db --network aurora-net \
  -e POSTGRES_USER=aurora -e POSTGRES_PASSWORD=aurora_secreta \
  -e POSTGRES_DB=aurora_llibres \
  -p 127.0.0.1:5432:5432 \
  --mount type=volume,src=aurora-dades,dst=/var/lib/postgresql/data \
  --memory 512m --cpus 1.0 --restart unless-stopped \
  postgres:16-alpine

docker run -d --name aurora-cache --network aurora-net \
  --memory 256m --cpus 0.5 --restart unless-stopped \
  redis:7-alpine redis-server --maxmemory 200mb --maxmemory-policy allkeys-lru

I ara la mateixa informació en compose.yaml:

services:
  aurora-db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: aurora
      POSTGRES_PASSWORD: aurora_secreta
      POSTGRES_DB: aurora_llibres
    ports:
      - "127.0.0.1:5432:5432"
    volumes:
      - aurora-dades:/var/lib/postgresql/data
    restart: unless-stopped

  aurora-cache:
    image: redis:7-alpine
    command: redis-server --maxmemory 200mb --maxmemory-policy allkeys-lru
    restart: unless-stopped

volumes:
  aurora-dades:

No hi ha docker network create: Compose crea una xarxa per al projecte automàticament. No hi ha docker volume create: n'hi ha prou de declarar el volum. No hi ha --name: el nom del servei ja identifica el contenidor. I no hi ha ordre d'execució, perquè el fitxer no és una seqüència, és una descripció.

  1. Imperatiu enfront de declaratiu

Aspecte Imperatiu (docker run) Declaratiu (compose.yaml)
Què escrius La seqüència de passos L'estat final desitjat
Qui calcula el camí Tu, en l'ordre correcte Compose, comparant el real amb el declarat
Repetir l'execució Falla: "el contenidor ja existeix" És idempotent: no canvia el que ja coincideix
Canviar una variable Esborrar el contenidor i reescriure les seves 14 línies Editar una línia i tornar a executar up -d
Aturar-ho tot Un altre script, amb els noms repetits docker compose down
Revisar canvis Impossible en una pull request git diff d'un fitxer de text
Font de veritat El que hi ha corrent a la màquina El fitxer versionat
Deriva de configuració Invisible: ningú sap si algú va tocar alguna cosa a mà up -d reconcilia i torna a l'estat declarat

La paraula clau és reconciliació. Quan executes docker compose up -d per segona vegada, Compose no torna a crear res: compara la configuració de cada contenidor en marxa amb la que declara el fitxer i només recrea allò que ha canviat. Si edites la memòria de la memòria cau i executes up -d, es recrea la memòria cau i els altres tres serveis ni se n'assabenten.

  1. Què és Docker Compose i què no és

Compose és una eina per definir i executar aplicacions multicontenidor en un únic host Docker. El seu terreny natural:

  • L'entorn de desenvolupament de qualsevol equip: git clone i docker compose up -d.
  • Proves d'integració a CI, on necessites una base de dades real i efímera.
  • Demostracions i entorns de prova reproduïbles.
  • Desplegaments petits en un sol servidor, quan l'alta disponibilitat no és un requisit.

Compose no és un orquestrador de producció multinode. No sap repartir contenidors entre deu màquines, no reprograma un servei quan mor el servidor que l'allotjava, no fa desplegaments progressius amb tornada enrere automàtica ni balanceig entre rèpliques en màquines diferents. Tot això arriba al mòdul 6 amb Swarm i Kubernetes.

Necessitat Compose Orquestrador (mòdul 6)
Diversos contenidors en un host Sí, és la seva raó de ser També, però amb més complexitat
Diversos hosts en clúster No
Reprogramar si cau un node No
Escalat local de rèpliques up --scale, amb limitacions Sí, amb balanceig real
Desplegament progressiu i rollback No
Corba d'aprenentatge Una tarda Setmanes

La bona notícia és que el compose.yaml que escriguis aquí no és feina per llençar: els conceptes —servei, imatge, variables, volums, sondes de salut— són els mateixos que veuràs a Kubernetes amb una altra sintaxi.

  1. Compose v2: un plugin de la CLI de Docker

Compose va néixer com un programa independent escrit en Python que s'invocava amb docker-compose (amb guionet) i llegia un fitxer docker-compose.yml. Aquesta és la sintaxi antiga. Des de Compose v2, reescrit en Go, és un plugin de la CLI de Docker i s'invoca com a subcomanda: docker compose, sense guionet. El nom de fitxer preferent avui és compose.yaml, i l'antiga clau version: "3.8" de la primera línia està obsoleta: si la poses, Compose la ignora i avisa. Oblida-te'n.

Comprova la teva instal·lació:

docker compose version
Docker Compose version v2.35.1

Si aquesta comanda falla però docker-compose version funciona, tens la v1: instal·la el plugin (docker-compose-plugin als repositoris de Docker) abans de continuar. Docker Desktop l'inclou de sèrie.

Compose busca el fitxer al directori actual i cap amunt, en aquest ordre de preferència:

Ordre Nom de fitxer
1 compose.yaml
2 compose.yml
3 docker-compose.yaml
4 docker-compose.yml (nom històric)

Fes servir sempre compose.yaml. Els altres existeixen per compatibilitat.

  1. El mínim de YAML que necessites

YAML és un format de serialització de dades pensat perquè el llegeixin persones. Només necessites cinc idees.

Indentació amb espais, mai tabuladors. La jerarquia s'expressa amb sagnat. Dos espais per nivell és la convenció universal. Un tabulador és un error de sintaxi en YAML, sense excepcions.

Mapes (parells clau-valor), separats per dos punts i un espai:

image: postgres:16-alpine
restart: unless-stopped

Llistes, amb guionet i espai. Cada element al mateix nivell de sagnat:

volumes:
  - aurora-dades:/var/lib/postgresql/data
  - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro

Imbricació: mapes dins de mapes i llistes dins de mapes. Així es construeix tot un compose.yaml: services és un mapa les claus del qual són noms de servei, i el valor de cadascun és un altre mapa amb image, ports, etc.

Escalars i cometes. YAML endevina el tipus: 5432 és un enter, true un booleà, 1.2 un decimal, postgres:16-alpine una cadena. Pots fer servir cometes simples o dobles; les dobles interpreten seqüències d'escapament (\n), les simples no. La regla pràctica a Compose:

Situació Escriu Per què
Ports "8080:80" Sense cometes, YAML 1.1 pot llegir-ho com un nombre sexagesimal
Valors que comencen per *, &, %, @, ` Entre cometes Són caràcters reservats
Cadenes /no/on/off/true "true" Sense cometes es converteixen en booleans
Versions tipus 1.2.0 "1.2.0" Sense cometes pot perdre el dígit final
Noms d'imatge normals Sense cometes No hi ha ambigüitat

Comentaris: tot el que segueix a # fins al final de línia. Fes-ne servir sense por, un compose.yaml ben comentat és documentació viva.

Per a cadenes llargues, YAML ofereix dos blocs: | conserva els salts de línia i > els converteix en espais. Els veuràs a command i a healthcheck.

  1. Errors de sintaxi YAML que veuràs segur

Error Símptoma Solució
Tabulador per sagnar found character '\t' that cannot start any token Configura el teu editor: 2 espais
Falta l'espai després de : mapping values are not allowed here image: nginx, no image:nginx
Sagnat inconsistent Una clau "desapareix" o canvia de servei Alinea tot el bloc al mateix nivell
8080:80 sense cometes El port publicat no és el que esperaves Posa sempre els ports entre cometes
Barrejar llista i mapa expected <block end> O tot amb guionets, o tot amb clau: valor
Duplicar una clau El segon valor guanya en silenci Revisa-ho amb docker compose config

Aquesta última comanda és la teva xarxa de seguretat: docker compose config llegeix el fitxer, el valida, resol variables i et retorna la configuració final tal com l'entén Compose. Executa-la sempre que alguna cosa no quadri.

  1. Anatomia d'un compose.yaml

Un fitxer de Compose té quatre seccions de primer nivell d'ús habitual:

services:     # OBLIGATÒRIA: els contenidors de l'aplicació
  ...
volumes:      # volums amb nom que gestiona Compose
  ...
networks:     # xarxes personalitzades
  ...
secrets:      # fitxers amb dades sensibles (lliçó 04-05)
  ...

Només services és obligatòria. Les altres existeixen perquè un volum o una xarxa no pertanyen a un servei: són recursos compartits que diversos serveis fan servir, i per això es declaren a part i es referencien des de dins de cada servei.

graph TD
    F["compose.yaml"] --> S["services:"]
    F --> V["volumes:"]
    F --> N["networks:"]
    S --> C1["contenidor<br/>aurora-libros-aurora-db-1"]
    S --> C2["contenidor<br/>aurora-libros-aurora-cache-1"]
    V --> VOL["volum<br/>aurora-libros_aurora-dades"]
    N --> NET["xarxa bridge<br/>aurora-libros_default"]
    C1 -.connectat a.-> NET
    C2 -.connectat a.-> NET
    C1 -.munta.-> VOL

Cada línia del fitxer es converteix en objectes Docker reals dels quals ja ho saps tot: contenidors, xarxes bridge i volums. Compose no inventa res de nou per sota; parla amb el mateix dimoni i la mateixa API que feies servir amb docker run. Pots continuar inspeccionant-ho tot amb docker ps, docker network inspect o docker volume ls.

  1. El projecte com a espai de noms

Compose agrupa tot el que crea sota un projecte. El nom del projecte per defecte és el del directori que conté el fitxer, en minúscules i sense caràcters estranys. Si el teu fitxer és a ~/aurora-libros/, el projecte es diu aurora-libros.

Aquest nom es fa servir com a prefix:

Objecte Patró de nom Exemple
Contenidor <projecte>-<servei>-<número> aurora-libros-aurora-db-1
Xarxa per defecte <projecte>_default aurora-libros_default
Xarxa declarada <projecte>_<nom> aurora-libros_posterior
Volum amb nom <projecte>_<nom> aurora-libros_aurora-dades

A més, Compose etiqueta cada objecte amb com.docker.compose.project=<projecte> i com.docker.compose.service=<servei>. Així és com sap, en una màquina amb vint contenidors, quins són seus.

El prefixat té una conseqüència pràctica molt útil: dos projectes diferents poden fer servir el mateix compose.yaml sense trepitjar-se. Tres maneres de fixar el nom del projecte, de major a menor prioritat:

docker compose -p aurora-proves up -d          # 1. opció de la CLI
COMPOSE_PROJECT_NAME=aurora-proves docker compose up -d   # 2. variable d'entorn
name: aurora-libros    # 3. clau de primer nivell al mateix fitxer
services:
  ...

Fixar name: al fitxer és bona pràctica: garanteix que el projecte es diu igual encara que algú cloni el repositori en una carpeta amb un altre nom.

  1. El teu primer compose.yaml: base de dades i memòria cau

Començaràs per allò petit: només aurora-db i aurora-cache. L'API i la web arriben a la lliçó 04-04, quan ja sàpigues declarar dependències i sondes de salut.

mkdir -p ~/aurora-libros && cd ~/aurora-libros
docker rm -f aurora-db aurora-cache aurora-api aurora-web 2>/dev/null
docker network rm aurora-net 2>/dev/null

Has esborrat els contenidors del mòdul 3 perquè no hi hagi conflictes de nom ni de ports. El volum aurora-dades continua intacte, però Compose crearà el seu propi amb prefix, així que començaràs amb una base de dades neta poblada per db/init.sql.

Crea ~/aurora-libros/compose.yaml:

# compose.yaml — Aurora Libros S.L. (versió mínima: dades i memòria cau)
name: aurora-libros

services:

  aurora-db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: aurora
      POSTGRES_PASSWORD: aurora_secreta
      POSTGRES_DB: aurora_llibres
    ports:
      - "127.0.0.1:5432:5432"     # només accessible des del mateix host
    volumes:
      - aurora-dades:/var/lib/postgresql/data
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    restart: unless-stopped

  aurora-cache:
    image: redis:7-alpine
    command: redis-server --maxmemory 200mb --maxmemory-policy allkeys-lru
    restart: unless-stopped

volumes:
  aurora-dades:

Tres detalls que mereixen atenció:

  • ./db/init.sql: les rutes relatives es resolen des del directori del fitxer, no des del teu cwd. Per això desapareix el $HOME de l'script de bash i el fitxer es torna portable.
  • No hi ha networks:: Compose crea aurora-libros_default i hi connecta tots dos serveis, amb DNS intern —exactament igual que la xarxa d'usuari aurora-net que vas crear a mà a la lliçó 03-05—.
  • No hi ha --name: no cal. El nom del servei és el nom DNS.

Valida abans d'arrencar:

docker compose config --quiet && echo "Sintaxi correcta"

  1. up, ps, logs, down: el cicle complet

docker compose up -d
[+] Running 4/4
 ✔ Network aurora-libros_default        Created
 ✔ Volume "aurora-libros_aurora-dades"  Created
 ✔ Container aurora-libros-aurora-db-1     Started
 ✔ Container aurora-libros-aurora-cache-1  Started

Aquí hi ha tot el que promet el model declaratiu: la xarxa i el volum s'han creat sols, amb el seu prefix de projecte, i els dos contenidors estan en marxa. Ni una línia de docker network create.

docker compose ps
NAME                         IMAGE              SERVICE        STATUS         PORTS
aurora-libros-aurora-cache-1 redis:7-alpine     aurora-cache   Up 12 seconds  6379/tcp
aurora-libros-aurora-db-1    postgres:16-alpine aurora-db      Up 12 seconds  127.0.0.1:5432->5432/tcp

Fixa't en la columna SERVICE: aquest és el nom que faràs servir a totes les comandes, no el del contenidor. Comprova que els objectes són Docker corrent:

docker network ls --filter name=aurora-libros
docker volume ls --filter name=aurora-libros
NETWORK ID     NAME                     DRIVER    SCOPE
b3f1a9c04e77   aurora-libros_default    bridge    local
DRIVER    VOLUME NAME
local     aurora-libros_aurora-dades

Els logs, agregats i acolorits per servei:

docker compose logs --tail 3
aurora-db-1     | PostgreSQL init process complete; ready for start up.
aurora-db-1     | LOG:  database system is ready to accept connections
aurora-cache-1  | * Ready to accept connections tcp

Verifica que init.sql es va executar i que el DNS funciona entre serveis:

docker compose exec aurora-db psql -U aurora -d aurora_llibres -c "SELECT count(*) FROM llibres;"
docker compose exec aurora-cache redis-cli -h aurora-cache PING
 count
-------
     9
(1 row)
PONG

Nou llibres —els vuit originals més El Aleph— i la memòria cau responent pel seu nom de servei. Ara la part que cap script de bash no et donava de franc:

docker compose down
[+] Running 3/3
 ✔ Container aurora-libros-aurora-cache-1  Removed
 ✔ Container aurora-libros-aurora-db-1     Removed
 ✔ Network aurora-libros_default           Removed

Una comanda per a tota la plataforma i neteja la xarxa. El volum no s'ha esborrat: down conserva les dades per disseny. Comprova-ho i torna a aixecar:

docker volume ls --filter name=aurora-libros --format "{{.Name}}"
docker compose up -d
docker compose exec aurora-db psql -U aurora -d aurora_llibres -c "SELECT count(*) FROM llibres;"
aurora-libros_aurora-dades
 count
-------
     9

Els nou llibres continuen allà. I si ara executes docker compose up -d una tercera vegada, veuràs la reconciliació en acció:

 ✔ Container aurora-libros-aurora-db-1     Running
 ✔ Container aurora-libros-aurora-cache-1  Running

Running, no Recreated: res no ha canviat al fitxer, així que Compose no toca res. Això és idempotència.

Errors Habituals i Consells

Fer servir tabuladors per sagnar. L'error més freqüent i el més desconcertant, perquè visualment no es distingeix. Configura el teu editor perquè insereixi espais als fitxers .yaml i activa la visualització de caràcters invisibles.

Escriure version: "3.8" a la primera línia. Està obsolet des de Compose v2. Compose la ignora i emet un avís. Esborra-la.

Fer servir docker-compose amb guionet. És la v1, sense manteniment des del 2023. Tot el que aprenguis aquí funciona amb docker compose; a la inversa, no.

Creure que down esborra les dades. No esborra volums amb nom... llevat que hi afegeixis -v. Aquest -v és la comanda més perillosa de Compose i apareix en detall a la lliçó 04-03.

Executar comandes des d'una altra carpeta. Compose busca el fitxer des del directori actual cap amunt. Si llances docker compose ps des de /tmp no trobarà res, o pitjor, trobarà un altre projecte. Fes servir -f ~/aurora-libros/compose.yaml quan no estiguis al lloc.

Oblidar que el nom del projecte depèn de la carpeta. Dues persones que clonen el repositori en carpetes amb noms diferents obtenen projectes diferents. Fixa name: al fitxer.

No posar els ports entre cometes. - 8080:80 sembla inofensiu, però és la mena de fallada que et fa perdre mitja hora. Cometes sempre.

Consell: executa docker compose config després de cada edició no trivial. És gratis, instantani i t'estalvia aixecar una pila trencada.

Exercicis

Exercici 1. El fragment següent té cinc errors (de sintaxi YAML o d'ús de Compose). Troba'ls, explica cadascun i escriu la versió corregida.

version: "3.8"
services:
  aurora-cache:
  image:redis:7-alpine
    ports:
      - 6379:6379
    restart: unless-stoped

Exercici 2. Sense esborrar el teu projecte actual, aixeca una segona còpia aïllada de la mateixa pila amb el nom de projecte aurora-proves, comprova que els seus contenidors, xarxa i volum són independents, i explica per què falla si no canvies res més. Després, elimina la còpia per complet, volums inclosos.

Exercici 3. Demostra amb comandes que Compose no crea res de màgic: partint del projecte aixecat, obtén (a) les etiquetes que Compose ha posat al contenidor de la memòria cau, (b) el nom real de la xarxa i el rang d'adreces que assigna, i (c) la ruta del volum al host.

Solucions

Solució 1.

# Error Explicació
1 version: "3.8" Clau obsoleta des de Compose v2; s'ignora i genera un avís
2 image:redis:7-alpine Falta l'espai després dels dos punts: YAML no ho llegeix com un mapa
3 image mal sagnat Està al mateix nivell que aurora-cache, no dins del servei
4 - 6379:6379 Port sense cometes: risc d'interpretació numèrica
5 unless-stoped Valor no vàlid, hi falta una p. Els quatre vàlids són no, always, on-failure, unless-stopped
name: aurora-libros
services:
  aurora-cache:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    restart: unless-stopped
docker compose config --quiet && echo OK

Solució 2.

cd ~/aurora-libros
docker compose -p aurora-proves up -d
Error response from daemon: driver failed programming external connectivity:
Bind for 127.0.0.1:5432 failed: port is already allocated

L'aïllament de Compose arriba a contenidors, xarxes i volums, però no als ports del host: només hi ha un 127.0.0.1:5432, i ja el té el projecte original. La solució més neta és no publicar port a la còpia; els serveis es parlen per la xarxa interna igualment.

# Còpia del fitxer sense la secció "ports"
sed '/127.0.0.1:5432/d; /ports:/d' compose.yaml > compose.proves.yaml
docker compose -p aurora-proves -f compose.proves.yaml up -d
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep aurora
docker volume ls --format "{{.Name}}" | grep aurora
aurora-proves-aurora-db-1     5432/tcp
aurora-proves-aurora-cache-1
aurora-libros-aurora-db-1      127.0.0.1:5432->5432/tcp
aurora-libros-aurora-cache-1
aurora-libros_aurora-dades
aurora-proves_aurora-dades

Dues piles completes a la mateixa màquina, cadascuna amb el seu propi volum prefixat, sense compartir ni un sol byte. Neteja total de la còpia:

docker compose -p aurora-proves -f compose.proves.yaml down -v
rm compose.proves.yaml

down -v sí que esborra els volums amb nom del projecte. Aquí és el que vols; al projecte real, gairebé mai.

Solució 3.

# (a) etiquetes que Compose afegeix
docker inspect aurora-libros-aurora-cache-1 \
  --format '{{range $k, $v := .Config.Labels}}{{$k}}={{$v}}{{"\n"}}{{end}}' \
  | grep com.docker.compose
com.docker.compose.project=aurora-libros
com.docker.compose.service=aurora-cache
com.docker.compose.container-number=1
com.docker.compose.oneoff=False
com.docker.compose.config-hash=7f3c1a...

Aquest config-hash és la clau de la reconciliació: és el resum de la configuració declarada. Quan executes up -d, Compose el recalcula i només recrea el contenidor si el hash ha canviat.

# (b) xarxa i subxarxa
docker network inspect aurora-libros_default \
  --format '{{.Name}} | {{(index .IPAM.Config 0).Subnet}} | driver={{.Driver}}'
# (c) ruta del volum al host
docker volume inspect aurora-libros_aurora-dades --format '{{.Mountpoint}}'
aurora-libros_default | 172.20.0.0/16 | driver=bridge
/var/lib/docker/volumes/aurora-libros_aurora-dades/_data

Una xarxa bridge d'usuari i un volum local a la ruta de sempre. Compose és una capa de conveniència sobre la mateixa API que ja coneixies: tot el que has après al mòdul 3 continua sent vàlid per inspeccionar i depurar.

Conclusió

Has canviat de paradigma. Un script de bash descriu com arribar a l'estat desitjat i falla si l'executes dues vegades; un compose.yaml descriu quin és aquest estat, és idempotent i viu versionat a Git al costat del codi. Saps que Compose v2 és un plugin de la CLI (docker compose, sense guionet), que el fitxer es diu compose.yaml i que version: està obsoleta. Domines el YAML que necessites —espais i mai tabuladors, mapes, llistes, cometes als ports— i reconeixes els sis errors de sintaxi que veuràs una vegada i una altra.

Entens que Compose ho organitza tot sota un projecte que actua com a espai de noms: prefixa contenidors, xarxes i volums, els etiqueta amb com.docker.compose.* i permet que dues piles idèntiques convisquin a la mateixa màquina. I has comprovat amb les teves mans que la xarxa i el volum es creen i es destrueixen sols, que down respecta les dades, i que up -d repetit no recrea res perquè compara el config-hash del que està declarat amb el que hi ha corrent.

El teu compose.yaml de dos serveis funciona, però només fa servir un grapat de claus. A la lliçó següent, Definint Serveis a Docker Compose, veuràs la referència pràctica completa: cada bloc d'un servei —imatge i build, identitat, execució, xarxa i ports, dades, salut i dependències, recursos i reinici, etiquetes— amb el seu equivalent exacte a les opcions de docker run que ja coneixes, a més dels blocs de nivell superior volumes: i networks: i les àncores de YAML per no repetir configuració. Al final d'aquella lliçó tindràs els quatre serveis d'Aurora Libros declarats en un sol fitxer.

Docker: De Principiant a Avançat

Mòdul 1: Introducció a Docker

Mòdul 2: Treballant amb Imatges Docker

Mòdul 3: Contenidors Docker

Mòdul 4: Docker Compose

Mòdul 5: Conceptes Avançats de Docker

Mòdul 6: Docker en Producció

Mòdul 7: Ecosistema i Eines de Docker

© Copyright 2026. Tots els drets reservats