Reservalia té cinc workflows, setze jobs i un problema que cap lliçó anterior no ha tocat: el bloc de checkout + setup-node + npm ci apareix copiat sis vegades. Quan a la 04-04 es va millorar la memòria cau es va haver d'aplicar el canvi sis vegades, i el dia que algú toqui una còpia i oblidi les altres cinc, el pipeline tindrà comportaments diferents segons el workflow sense que ningú sàpiga per què. I ve el pitjor: el mòdul 5 hi afegirà una aplicació mòbil i uns microserveis que necessiten exactament el mateix. La idea central d'aquesta lliçó és fàcil d'enunciar i difícil d'aplicar: el pipeline és codi de producció i mereix el mateix tracte —revisió, versionat, refactorització i, sobretot, proves—. Veurem els tres mecanismes de reutilització de GitHub Actions i quan fer servir cadascun, extraurem de debò una composite action i un workflow reutilitzable, reescriurem el ci.yml a sobre, discutirem el repositori central de plantilles i els seus riscos, fixarem convencions de llegibilitat i acabarem amb el que gairebé ningú no fa: provar el pipeline abans de fusionar-lo.
Contingut
- El pipeline és codi, i avui no es tracta com a tal
- El problema real de Reservalia, explicat amb números
- Els tres mecanismes de reutilització comparats
- Extreure una composite action:
preparar-node - Extreure un workflow reutilitzable:
reusable-build-publicar.yml - El
ci.ymlde Reservalia: abans i després - Un repositori central de workflows i els seus riscos
- Convencions perquè un pipeline sigui llegible
- Provar el pipeline
- Migració progressiva sense congelar l'equip
- Errors Comuns i Consells
- Exercicis
- Conclusió
- El pipeline és codi, i avui no es tracta com a tal
Compara com tracta Reservalia el seu codi d'aplicació i com tracta el seu YAML:
| Pràctica | apps/api |
.github/workflows/ |
|---|---|---|
| Control de versions i revisió en PR | Sí | Sí (CODEOWNERS) |
| Format i lint automàtics | Prettier + ESLint | No |
| Proves automatitzades | Unitàries i integració | No |
| Refactorització quan fa mal | Habitual | Mai |
| Reutilització del que es repeteix | Funcions i paquets | Copiar i enganxar |
| Es desplega després de verificar | Sí | Es fusiona i es mira què passa |
Les quatre files en negreta són la lliçó. I no és una qüestió de polidesa: el pipeline és el sistema que decideix què arriba a producció, així que una fallada en ell té el mateix abast que una fallada a l'aplicació, amb l'agreujant que el pipeline no té qui el verifiqui. Quan la 04-01 va diagnosticar "la lògica de negoci amagada al YAML" i "el pipeline que només entén la Nuria" en descrivia els símptomes; aquesta lliçó en dona el tractament.
- El problema real de Reservalia, explicat amb números
| Bloc duplicat | On apareix | Vegades |
|---|---|---|
checkout + setup-node + npm ci |
ci.yml (×4 jobs), nocturn.yml, cd.yml (job web) |
6 |
| Credencials OIDC + login a ECR | ci.yml (publicar), cd.yml (×3), rollback.yml |
5 |
docker build amb memòria cau de registre |
ci.yml (×2), nocturn.yml |
3 |
Smoke test contra /version |
cd.yml (×3), rollback.yml |
4 |
Quatre conseqüències concretes, cap de teòrica. Tota millora costa ×6: la memòria cau de capes de la 04-04 es va aplicar bé a ci.yml i es va oblidar a nocturn.yml, que continua trigant dos minuts de més. Les còpies divergeixen: dos jobs ja fan servir actions/checkout@v4 i un es va quedar a @v3. La revisió es torna inútil, perquè un diff de 200 línies de YAML repetit no es llegeix, s'aprova. I afegir un servei nou és copiar 150 línies i confiar a no haver-se oblidat res. La regla que s'aplica al codi serveix igual aquí: a la tercera repetició, extreu. Amb dues còpies, l'abstracció prematura sol sortir malament; amb sis, el cost ja s'està pagant cada dia.
- Els tres mecanismes de reutilització comparats
| Composite action | Reusable workflow | Matrix | |
|---|---|---|---|
| Què encapsula | Una seqüència de steps | Un o diversos jobs complets | El mateix job amb dades diferents |
| On viu | .github/actions/<nom>/action.yml o un repositori propi |
.github/workflows/<nom>.yml |
Dins del job |
| S'invoca amb | uses: dins d'un job |
uses: a nivell de job |
strategy: matrix |
Defineix runs-on? |
No: hereta el del job que la crida | Sí: defineix els seus propis jobs | No |
| Rep / retorna | inputs / outputs |
inputs, secrets / outputs |
Valors de la matriu / res |
| Accés a secrets | Només els que li passis com a input | Explícits o amb secrets: inherit |
— |
| Quan fer-lo servir | Repetir passos dins de jobs diferents | Repetir jobs sencers o pipelines complets | Repetir el mateix amb dades diferents |
La regla d'elecció, en una frase: si el que es repeteix són passos dins d'un job, composite action; si és el job sencer o un pipeline complet, reusable workflow; si és la mateixa feina amb paràmetres diferents, matrix. I una limitació que sorprèn i convé conèixer abans de dissenyar res: una composite action no pot definir services:, així que el PostgreSQL de les proves no s'hi pot encapsular; ha de quedar-se al job o pujar a un reusable workflow.
- Extreure una composite action:
preparar-node
preparar-nodeComencem pel que més es repeteix. El bloc que apareix sis vegades és aquest:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version-file: .nvmrc, cache: npm }
- run: npm ciI es converteix en una acció local:
# .github/actions/preparar-node/action.yml
name: Preparar Node
description: Checkout, Node des de .nvmrc amb memoria cau de npm, i instal·lacio reproduible.
inputs:
fetch-depth:
description: Profunditat de l historial. 0 per a l historial complet.
required: false
default: '1' # 1
runs:
using: composite # 2
steps:
- uses: actions/checkout@v4
with: { fetch-depth: '${{ inputs.fetch-depth }}' }
- uses: actions/setup-node@v4
with: { node-version-file: .nvmrc, cache: npm }
- name: Instal·lar dependencies
shell: bash # 3
run: npm ci- Els
inputsambdefaultsón el que fa usable l'acció. El cas normal no necessita configurar res; el jobseguretat, que necessita l'historial complet per a gitleaks, passafetch-depth: 0. Sense aquell input caldria triar entre duplicar l'acció o portar sempre l'historial sencer, que és lent. using: compositedistingeix una acció de passos d'una acció de JavaScript o de contenidor. Ishell: bashés obligatori (3) a cadarund'una composite action: la seva absència és l'error número u en escriure la primera, i el missatge resultant no és especialment clar.
L'ús queda així en qualsevol job:
- uses: ./.github/actions/preparar-node # 1 · cas normal
- uses: ./.github/actions/preparar-node # al job seguretat
with: { fetch-depth: '0' }- La ruta comença per
./perquè és una acció local, del mateix repositori: GitHub descarrega el repositori per resoldre-la, de manera que el patró funciona encara que el checkout el faci la mateixa acció. Si visqués en un altre repositori es referenciaria comreservalia/accions/preparar-node@v1i se li aplicaria la regla de fixar per SHA de la 04-03.
- Extreure un workflow reutilitzable:
reusable-build-publicar.yml
reusable-build-publicar.ymlLa composite action resol els steps repetits, però build i publicar són jobs sencers que es repeteixen amb variacions entre ci.yml i nocturn.yml, i que el mòdul 5 voldrà reutilitzar per al mòbil i els microserveis. Això és un reusable workflow:
# .github/workflows/reusable-build-publicar.yml
name: Reusable · build i publicar
on:
workflow_call: # 1 · el que el fa invocable
inputs:
dockerfile: { type: string, required: true }
repositori: { type: string, required: true } # p. ex. reservalia/api
publicar: { type: boolean, required: false, default: false }
secrets:
AWS_ROLE: { required: true } # 2 · explicit, no inherit
outputs: # 3
digest: { description: Digest de la imatge, value: '${{ jobs.construir.outputs.digest }}' }
jobs:
construir:
runs-on: ubuntu-22.04
timeout-minutes: 15
permissions: { contents: read, id-token: write }
outputs:
digest: ${{ steps.imatge.outputs.digest }}
steps:
- uses: ./.github/actions/preparar-node
- run: npm run build
- uses: aws-actions/configure-aws-credentials@v4
if: inputs.publicar # 4
with: { role-to-assume: '${{ secrets.AWS_ROLE }}', aws-region: eu-west-1 }
- uses: aws-actions/amazon-ecr-login@v2
if: inputs.publicar
- uses: docker/setup-buildx-action@v3
- id: imatge
uses: docker/build-push-action@v5
with:
context: .
file: ${{ inputs.dockerfile }}
push: ${{ inputs.publicar }}
tags: ${{ vars.ECR_REGISTRY }}/${{ inputs.repositori }}:${{ github.sha }}
cache-from: type=registry,ref=${{ vars.ECR_REGISTRY }}/${{ inputs.repositori }}:cache
cache-to: type=registry,ref=${{ vars.ECR_REGISTRY }}/${{ inputs.repositori }}:cache,mode=maxon: workflow_callconverteix el fitxer en una cosa invocable des d'un altre workflow, i elsinputsamb tipus són un contracte verificat: passar una cadena on s'espera un booleà falla en analitzar el fitxer, abans d'executar res.- Els secrets es declaren un a un. Existeix
secrets: inherit, que passa tots els del cridador, i és còmode i mala idea: trenca el mínim privilegi de la 04-03 i fa impossible saber a què té accés el workflow llegint-ne la capçalera. - Els
outputsdel workflow reutilitzable s'alimenten dels outputs dels seus jobs, i són el que permet que el cridador rebi el digest i el promocioni: el mecanisme de la 04-01, un nivell més amunt.if: inputs.publicar(4) permet a més un sol workflow per a dos comportaments: en un pull request es construeix sense publicar i sense demanar credencials; amaines publica. Un paràmetre en comptes de dos fitxers gairebé iguals.
- El
ci.yml de Reservalia: abans i després
ci.yml de Reservalia: abans i desprésAbans, els jobs build i publicar ocupaven unes 45 línies amb el bloc de preparació repetit a cadascun:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version-file: .nvmrc, cache: npm }
- run: npm ci
- run: npm run build
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with: { context: ., file: apps/api/Dockerfile, push: false, cache-from: '…' }
publicar:
needs: [qualitat, test, build]
if: github.ref == 'refs/heads/main'
permissions: { contents: read, id-token: write }
steps:
- uses: actions/checkout@v4 # ← una altra vegada
- uses: actions/setup-node@v4 # ← una altra vegada
with: { node-version-file: .nvmrc, cache: npm }
- run: npm ci # ← i credencials, login a ECR,
# … build i push duplicats respecte al job anteriorDesprés, els dos jobs es converteixen en dues crides:
jobs:
qualitat:
runs-on: ubuntu-22.04
steps:
- uses: ./.github/actions/preparar-node # 1
- run: npx prettier --check .
- run: npm run lint
- run: npm run typecheck
build: # 2
uses: ./.github/workflows/reusable-build-publicar.yml
with: { dockerfile: apps/api/Dockerfile, repositori: reservalia/api, publicar: false }
secrets: { AWS_ROLE: '${{ secrets.AWS_ROLE_CI }}' }
publicar:
needs: [qualitat, test, build, seguretat]
if: github.ref == 'refs/heads/main'
uses: ./.github/workflows/reusable-build-publicar.yml
with: { dockerfile: apps/api/Dockerfile, repositori: reservalia/api, publicar: true }
secrets: { AWS_ROLE: '${{ secrets.AWS_ROLE_CI }}' }- Un
uses:substitueix tres steps, als sis llocs on eren. - Un job que crida un reusable workflow no té
stepsniruns-on: els defineix el workflow cridat. Té, això sí,needs,if,withisecrets. És el que més confon al principi, perquè sembla un job i es comporta com una crida a funció.
Balanç: ci.yml passa d'unes 180 línies a unes 95, la memòria cau es configura en un sol lloc, i afegir el microservei del mòdul 5 serà afegir un job de quatre línies amb un altre dockerfile i un altre repositori. Amb un avís honest: la indirecció té un cost real de llegibilitat —per saber què fa build ara cal obrir un altre fitxer, i a la interfície els jobs apareixen imbricats—. Extreure una cosa que només es fa servir una vegada empitjora el pipeline; la regla de la tercera repetició evita justament això.
- Un repositori central de workflows i els seus riscos
Quan el mòdul 5 afegeixi el mòbil i els microserveis, la pregunta següent és si aquelles plantilles han de viure a cada repositori o en un de central, tipus reservalia/accions.
| Plantilles a cada repositori | Repositori central | |
|---|---|---|
| Duplicació | Alta entre repositoris | Cap |
| Autonomia de cada equip | Total | Limitada |
| Propagar una millora | Repositori a repositori | Una vegada, per a tothom |
| Radi d'un error | Un repositori | Tots alhora |
| Qui el manté | Cada equip | Cal un propietari amb nom |
El risc és a la fila del radi d'error: un canvi a la plantilla central arriba a tots els equips alhora i, si trenca alguna cosa, trenca tots els pipelines de l'empresa un dimarts al matí. La mitigació és la mateixa que per a qualsevol dependència compartida, com vam veure a la 04-02: versionar per etiqueta i no consumir main.
- Amb
@v2, un canvi a la plantilla no arriba fins que cada equip puja la seva referència. Consumir@mainsignifica que qualsevol commit del repositori central es desplega instantàniament a tots els pipelines, sense revisió ni proves per part de qui ho pateix. La convenció pràctica és una etiqueta major mòbil (v2apuntant sempre a l'última 2.x) per rebre correccions compatibles, i un canvi explícit d'etiqueta per a les majors. I el repositori central necessita el seu propi pipeline: proves, revisió i unCHANGELOGque expliqui què canvia a cada versió, perquè és una llibreria encara que no ho sembli.
- Convencions perquè un pipeline sigui llegible
L'antipatró "el pipeline que només entén la Nuria" de la 04-01 es combat amb quatre convencions barates. Noms explícits, en jobs i en steps: name: Publicar imatge a ECR en lloc de publicar-2; els noms són el que es veu a la interfície quan alguna cosa falla i als checks obligatoris, així que un nom dolent costa un clic cada vegada, per sempre. env centralitzat a la capçalera: regió, zona horària, versions d'eines i noms de recursos en un únic bloc a nivell de workflow, en comptes de repetits a cada step; canviar de regió ha de ser canviar una línia. Fitxers curts amb una responsabilitat: si un workflow supera les 150 línies o barreja dos propòsits, probablement són dos workflows, que és la mateixa heurística que aplicaries a un mòdul de codi. I comentaris que expliquin el perquè, mai el què: # instal·la dependències sobre un npm ci és soroll; el que cal escriure és la raó no evident:
# cancel-in-progress: false a main expressament: cada commit de main produeix
# un artefacte publicable i cancel·lar deixaria commits sense imatge (veure 02-07).
concurrency: { group: cd-main, cancel-in-progress: false }
- Provar el pipeline
Aquí hi ha el forat més gran, i el que dona títol a la lliçó. Avui, l'única manera que té Reservalia de saber si un canvi al pipeline funciona és fusionar-lo i mirar. Això és provar en producció, amb la particularitat que la producció del pipeline és la capacitat de l'equip de lliurar programari: si es trenca, ningú no desplega.
| Nivell | Què comprova | Cost | Quan s'executa |
|---|---|---|---|
Lint i validació d'esquema (actionlint) |
Sintaxi, expressions, referències a jobs inexistents | Segons | A cada PR |
Execució local (act) |
Que els steps fan el que creus | Minuts | Al portàtil |
| Branca de prova | El flux complet amb disparadors reals | Una execució | Abans de fusionar |
| Servei de baix risc primer | El canvi contra una cosa real que no és crítica | Un desplegament | En desplegar el canvi |
actionlint és l'eina de més rendiment i s'afegeix al job qualitat en dues línies: descarregar el binari amb l'script oficial i executar ./actionlint -color.
Detecta el que l'editor no veu: una expressió ${{ }} mal formada, un needs: [buidl] amb una errada que deixaria el job sense executar-se en silenci, un runs-on inexistent, un shell que falta en una composite action, i fins i tot errors de shell dins dels blocs run, perquè incorpora shellcheck. És la diferència entre assabentar-se'n en vint segons i assabentar-se'n quan el workflow ja és a main.
act executa els workflows localment en contenidors. Serveix per iterar sobre la lògica d'un job sense gastar vint minuts per intent, i té límits que convé conèixer per no confiar-s'hi: no reprodueix els entorns de GitHub, ni les regles de protecció, ni el token OIDC, ni els services amb exactitud. La regla pràctica: act serveix per depurar, no per validar. La branca de prova cobreix el que act no pot: es crea prova/pipeline-plantilles, s'apunten els disparadors a aquella branca i s'executa el flux real, amb els seus entorns i els seus permisos, contra recursos de dev. És l'única manera de verificar de debò un canvi a cd.yml. I finalment, el desplegament del canvi a un servei de baix risc primer. Quan les plantilles siguin centrals, la versió nova s'aplica abans a un servei intern la caiguda del qual no noti cap client, es deixa una setmana i només aleshores es propaga. És exactament el canari de la 03-04 aplicat al pipeline, i per la mateixa raó: és l'únic desplegament progressiu possible quan el radi d'impacte és tota l'organització.
- Migració progressiva sense congelar l'equip
La temptació de reescriure els cinc workflows en un pull request gegant s'ha de resistir: seria un PR de 800 línies impossible de revisar que, si surt malament, deixa l'equip sense pipeline i sense saber quina part ha fallat. El pla de Reservalia són cinc passos, cap de bloquejant:
- Afegir
actionlintprimer, sobre els workflows actuals. És la xarxa que farà segurs els quatre passos següents, i troba tres errades el primer dia. - Extreure
preparar-nodei fer-la servir en un sol job,qualitat. Un PR de vint línies, revisable, amb risc acotat a un job. - Propagar-la als cinc jobs restants, un o dos per PR, verificant cada vegada. Aquí és on es corregeixen les divergències acumulades, com el
checkout@v3oblidat. - Extreure
reusable-build-publicar.ymli fer-lo servir primer anocturn.yml, el workflow de menys risc: si falla no bloqueja ningú i s'arregla al matí. - Migrar
ci.ymlicd.yml, només quan els passos anteriors portin un parell de setmanes funcionant.
Dos principis sostenen el pla. Cada pas deixa el sistema funcionant: en cap moment hi ha un estat intermedi trencat, i es pot parar al pas 3 durant un mes si sorgeix alguna cosa urgent. I es comença pel de menys risc i més repetició, que és on el benefici arriba abans i l'error costa menys. És la mateixa estratègia que aplicaries a refactoritzar un mòdul de producció, perquè el problema és exactament el mateix.
Errors Comuns i Consells
Error 1: extreure a la primera repetició. Una abstracció construïda sobre un sol cas acaba plena de paràmetres per acomodar el segon; espera a la tercera. Error 2: oblidar shell: bash als run d'una composite action, amb un missatge d'error poc clar.
Error 3: fer servir secrets: inherit per comoditat. Passa tots els secrets del cridador i trenca el mínim privilegi; declara els que calguin. Error 4: consumir plantilles centrals des de main, amb la qual cosa un commit aliè canvia el pipeline de tothom sense avís. Error 5: posar steps en un job que crida un reusable workflow: no és un job normal, és una crida, i falla en analitzar el fitxer.
Error 6: sobreabstreure fins que entendre per què ha fallat el pipeline exigeixi obrir quatre fitxers; de vegades deu línies duplicades i clares són millors que una plantilla amb nou paràmetres. Error 7: fusionar un canvi de pipeline sense haver-lo executat mai, que és provar en producció amb l'equip sencer de conillet d'índies. Error 8: reescriure els cinc workflows en un PR, impossible de revisar i de diagnosticar si alguna cosa va malament. Consell 1: afegeix actionlint avui, encara que no hagis de refactoritzar res; és la millor relació benefici/esforç de tota la lliçó. Consell 2: versiona les plantilles per etiqueta i publica un CHANGELOG. Consell 3: documenta al README de les plantilles com es fan servir i com es proven, o tornaràs a tenir un sistema que només entén una persona. Consell 4: aplica al pipeline les mateixes revisions que al codi, començant per CODEOWNERS sobre .github/.
Exercicis
Exercici 1
En aquests tres casos, decideix quin mecanisme de reutilització faries servir i justifica-ho: (a) quatre jobs repeteixen els mateixos cinc steps de preparació; (b) tres repositoris diferents necessiten el mateix pipeline complet de construcció i publicació d'imatges; (c) cal executar la mateixa suite de proves contra Node 18, 20 i 22.
Exercici 2
Un equip extreu les seves plantilles a empresa/workflows i tots els repositoris les consumeixen amb @main. Un dimarts al matí algú fusiona un canvi a la plantilla i tots els pipelines de l'empresa fallen. Explica què va fallar en el disseny, quines pràctiques d'aquesta lliçó ho haurien evitat i com ho arreglaries, distingint la resposta immediata de l'estructural.
Exercici 3
Dissenya l'estratègia de proves per a un canvi a cd.yml que afegeix una verificació de signatura amb cosign abans de desplegar a prod. Indica què comprovaries a cada nivell, en quin ordre i què faries si alguna cosa falla a l'últim.
Solucions
Solució 1. (a) Composite action. El que es repeteix són steps dins de jobs que continuen sent diferents entre si; una composite action s'insereix amb un uses: i hereta el runs-on del job que la crida, que és justament el que es vol. Un reusable workflow seria excessiu, perquè obligaria a convertir cada job en una crida i a redefinir la resta del seu contingut.
(b) Reusable workflow, allotjat en un repositori central i consumit per etiqueta. El que es repeteix és un pipeline sencer amb els seus jobs, els seus runs-on i els seus permisos, i això una composite action no ho pot encapsular. Els inputs parametritzen el que canvia —dockerfile, repositori d'imatges, si publica— i els secrets es declaren explícitament. (c) Matrix. No hi ha res per extreure: és el mateix job executat tres vegades amb una dada diferent. strategy: matrix: { node: [18, 20, 22] } amb fail-fast: false per veure els tres resultats. Convé a més el job agregador de la 04-04, perquè els checks obligatoris es configuren per nom i els noms inclouen el valor de la matriu.
Solució 2. Què va fallar: consumir una dependència compartida des de la seva branca de desenvolupament. @main significa que qualsevol commit del repositori central entra en producció —la producció de tots els pipelines— sense revisió, sense proves i sense que els consumidors puguin triar quan. És exactament el que a la 04-02 seria no tenir lockfile: totes les dependències en latest. Què ho hauria evitat: (1) versionar per etiqueta (@v2), de manera que un canvi al central no arribi fins que cada equip pugi la seva referència; (2) que el repositori central tingui el seu propi pipeline amb actionlint, validació d'esquema i proves, més revisió obligatòria amb CODEOWNERS; (3) provar el canvi en un repositori de baix risc abans de publicar l'etiqueta, que és el canari de l'apartat 9; i (4) un CHANGELOG que permeti als consumidors saber què canvia abans de pujar de versió.
Resposta immediata: revertir el commit al repositori central, cosa que restableix tots els pipelines alhora, i només després investigar. La temptació d'arreglar cap endavant amb l'equip sencer bloquejat és l'error clàssic de gestió d'incidents, i aquí s'aplica igual que a producció: revertir primer, diagnosticar després. Resposta estructural: publicar una etiqueta v1 amb l'estat bo conegut, migrar tots els repositoris de @main a @v1 i, a partir d'aquí, adoptar el cicle de versionat amb proves.
Solució 3. Cinc nivells, en ordre de cost creixent:
actionlinten local i al PR. Detecta expressions mal formades i errors de shell al blocrunde cosign. Segons, i descarta la meitat dels errors possibles.- Verificació manual de l'ordre fora del pipeline. Executar
cosign verifydes d'un portàtil contra una imatge real ja publicada, comprovant que falla amb una imatge no signada. Això és clau: una verificació que sempre passa no verifica res, així que cal provar el cas negatiu abans que el positiu. actper iterar sobre la lògica del step, sabent que no reproduirà l'OIDC ni els entorns: serveix per afinar l'script, no per donar el vistiplau.- Branca de prova amb desplegament real a
dev, el primer nivell que exercita el flux complet amb permisos i entorns reals. Es comproven els dos camins: imatge signada, que desplega, i imatge sense signar, que s'atura; sense el cas negatiu, la porta no està provada. - Aplicar el canvi primer a
devistagingdurant una setmana, i només després aprod. La verificació de signatura és una porta nova, i el seu mode de fallada més probable no és deixar passar alguna cosa dolenta, sinó bloquejar un desplegament legítim un dia que calgui desplegar de pressa.
Si alguna cosa falla a l'últim nivell —la verificació bloqueja un desplegament legítim a prod—, hi ha dues respostes i només una és correcta. La incorrecta és desactivar la verificació "temporalment", perquè aquella desactivació no es reverteix mai. La correcta és tractar-ho com un incident: fer servir rollback.yml per tornar a la versió anterior si urgeix, i diagnosticar per què la signatura no era vàlida —el rol OIDC va canviar, la identitat del signant no coincideix amb l'expressió regular, la imatge es va republicar sense signar— per arreglar-ne la causa. I preparar-ho per endavant: documentar a SECURITY.md qui pot autoritzar una excepció, amb quina justificació i amb quina data de revisió, perquè aquella decisió no s'improvisi a les onze de la nit.
Conclusió
El pipeline de Reservalia ha deixat de ser sis còpies del mateix YAML. Una composite action, .github/actions/preparar-node, concentra el checkout, la instal·lació de Node des de .nvmrc i l'npm ci amb memòria cau, parametritzada amb fetch-depth perquè el job seguretat obtingui l'historial complet sense duplicar res. Un reusable workflow, .github/workflows/reusable-build-publicar.yml, encapsula la construcció i la publicació amb inputs tipats, secrets declarats un a un —mai inherit— i un output amb el digest, de manera que un únic fitxer cobreix el cas "construir sense publicar" dels pull requests i el cas "publicar" de main. El ci.yml ha passat de 180 línies a 95, la memòria cau es configura en un sol lloc, i el mòbil i els microserveis del mòdul 5 seran quatre línies cadascun. Amb la regla que evita l'excés: a la tercera repetició s'extreu, i una abstracció que només es fa servir una vegada empitjora el pipeline. I sabem triar el mecanisme —composite action per a steps, reusable workflow per a jobs o pipelines complets, matrix per a la mateixa feina amb dades diferents—, quan compensa un repositori central i quin és el seu risc real: que el seu radi d'impacte és tota l'organització, motiu pel qual es consumeix per etiqueta i mai des de main, amb el seu propi pipeline, la seva revisió i el seu CHANGELOG. I tenim convencions que impedeixen tornar al pipeline que només entén una persona: noms explícits, env centralitzat, fitxers curts amb una responsabilitat i comentaris que expliquin el perquè.
El que més canvia, tanmateix, és l'últim. Reservalia ja no fusiona canvis de pipeline per veure què passa: els passa per actionlint a cada pull request —que va trobar tres errades el primer dia, entre elles un needs mal escrit que deixava un job sense executar-se en silenci—, els itera en local amb act sabent que serveix per depurar i no per validar, els executa en una branca de prova amb disparadors i entorns reals, i els aplica primer al servei de menys risc. Tot això per migració progressiva, en cinc passos que deixen el sistema funcionant a cadascun, sense congelar la feina de ningú. Queda el quart front, i és el que més desplegaments trenca. Tot el que s'ha construït en tres mòduls s'apuntala en una propietat que l'esquema de la base de dades no té: un artefacte és immutable i se substitueix per l'anterior en quatre minuts, però una columna esborrada no torna, i el rollback.yml de la 03-05 no sap desfer un DROP COLUMN. La lliçó següent, Bases de Dades al Pipeline: Migracions Segures, aborda l'estat compartit: migracions versionades executades des del pipeline i mai des d'un portàtil, el patró expand and contract desenvolupat pas a pas sobre un cas real de Reservalia, la classificació dels canvis d'esquema en segurs, perillosos i prohibits en calent, els bloquejos que un ALTER TABLE pot provocar en producció, i per què les dades de clients no han d'acabar mai a staging.
Curs de CI/CD: Integració i Desplegament Continu
Mòdul 1: Introducció al CI/CD
- Conceptes Bàsics de CI/CD
- Beneficis del CI/CD
- Eines Populars de CI/CD
- El Projecte del Curs: l'Aplicació que Automatitzarem
- Mètriques DORA: Com es Mesura el Lliurament de Programari
Mòdul 2: Integració Contínua (CI)
- Introducció a la Integració Contínua
- Configuració d'un Entorn de CI
- Automatització de la Construcció
- Proves Automatitzades
- Qualitat de Codi i Anàlisi Estàtica
- Artefactes, Versionat i Promoció
- Integració amb el Control de Versions
Mòdul 3: Desplegament Continu (CD)
- Introducció al Desplegament Continu
- Automatització del Desplegament
- Infraestructura com a Codi i Entorns Reproduïbles
- Estratègies de Desplegament
- Feature Flags, Rollback i Recuperació davant Errors
- Monitoratge i Retroalimentació
Mòdul 4: Pràctiques Avançades de CI/CD
- Pipelines de CI/CD
- Gestió de Dependències
- Seguretat en CI/CD
- Escalabilitat i Rendiment
- Pipeline as Code: Plantilles, Reutilització i Proves del Pipeline
- Bases de Dades al Pipeline: Migracions Segures
Mòdul 5: Implementació de CI/CD en Projectes Reals
- Cas d'Estudi: Projecte Web
- Cas d'Estudi: Aplicació Mòbil
- Cas d'Estudi: Microserveis
- Cas d'Estudi: Modernitzar un Projecte Legacy
Mòdul 6: Eines i Tecnologies
- Jenkins
- GitLab CI/CD
- CircleCI
- Travis CI
- Docker i Kubernetes
- GitHub Actions a Fons
- Comparativa i Criteris per Triar Eina
Mòdul 7: Exercicis Pràctics
- Exercici 1: Configuració d'un Pipeline Bàsic
- Exercici 2: Integració de Proves Automatitzades
- Exercici 3: Desplegament en un Entorn de Producció
- Exercici 4: Monitoratge i Retroalimentació
- Exercici 5: Enfortir el Pipeline amb Seguretat i Secrets
- Projecte Final: Pipeline Complet d'Extrem a Extrem
