La canalització de la lliçó anterior deixa api-reserves en producció amb un artefacte verificat, signat i provat. I tanmateix, en el moment en què Argo CD sincronitza el nou digest, passa una cosa que cap prova prèvia no pot evitar del tot: tots els usuaris passen a la versió nova. Si alguna cosa s'ha escapat —una consulta que es degrada sota càrrega real, una condició de cursa que només apareix amb mil peticions per segon, una integració amb la passarel·la de pagaments que falla amb dades reals—, ho descobreixen tots alhora.

Aquesta lliçó tracta d'eliminar aquest salt. Veurem quatre maneres de reduir el risc de publicar una versió: l'actualització rodant que ja coneixem, el desplegament blau-verd, el canari i les banderes de funcionalitat. I al final aplicarem el que hem après al cas concret que té al davant l'equip de Rutas Norte: publicar la nova versió d'api-reserves la setmana abans del pont de maig, quan el trànsit es multiplica per deu durant tres dies i una fallada costa vendes reals.

Contingut

  1. Per què el RollingUpdate no sempre n'hi ha prou
  2. Blau-verd: dues versions, un interruptor
  3. Migracions de base de dades compatibles amb totes dues versions
  4. Canari: alliberar a un percentatge d'usuaris
  5. Argo Rollouts: automatitzar el canari amb anàlisi
  6. Flagger com a alternativa
  7. Banderes de funcionalitat: separar el desplegament de l'activació
  8. El pla de Rutas Norte per al pont de maig
  9. Comparativa de les quatre estratègies

  1. Per què el RollingUpdate no sempre n'hi ha prou

A 02-04 vam veure el RollingUpdate i amb la configuració d'11-01 (maxSurge: 25%, maxUnavailable: 0) funciona bé: sense tall de servei, sense pèrdua de capacitat. Els seus límits no són a la disponibilitat, sinó al control sobre el risc.

Limitació Conseqüència pràctica a Rutas Norte
Barreja versions durant el desplegament Amb 40 rèpliques i un desplegament de 8 minuts, un usuari pot veure la versió antiga en una petició i la nova en la següent. Si el contracte de l'API va canviar, la SPA es trenca a mitja compra
No permet validar abans de comprometre's Quan notes el problema, la versió nova ja atén una part gran dels usuaris
La reversió no és instantània rollout undo torna a recórrer 40 pods: uns altres 6-8 minuts amb usuaris afectats
El criteri d'avanç és la sonda de preparació Un pod que respon 200 a /preparat però retorna 500 en el 30 % de les compres avança igualment
No hi ha cap anàlisi automàtica Ningú no mira Grafana durant el desplegament d'un dimarts a les 11 del matí

El punt quart és el central. La sonda de preparació respon a "el procés pot atendre?", no a "aquesta versió funciona bé?". Són preguntes molt diferents, i només la segona importa per decidir si continuar endavant.

graph LR
  subgraph RU["RollingUpdate"]
    direction TB
    A1[100% v1] --> A2[75% v1 · 25% v2] --> A3[50/50] --> A4[100% v2]
    A5[Criteri d'avanç:<br/>readinessProbe] -.-> A3
  end
  subgraph BG["Blau-verd"]
    direction TB
    B1[100% blau] --> B2[verd desplegat<br/>sense trànsit real] --> B3[100% verd<br/>canvi instantani]
    B4[Criteri: validació<br/>manual o automàtica] -.-> B3
  end
  subgraph CN["Canari"]
    direction TB
    C1[100% v1] --> C2[95% v1 · 5% v2] --> C3[75/25] --> C4[100% v2]
    C5[Criteri: anàlisi de<br/>mètriques reals] -.-> C3
  end

  1. Blau-verd: dues versions, un interruptor

La idea és simple: dos entorns complets coexistint, un rebent trànsit i l'altre no. El Service apunta a un dels dos mitjançant una etiqueta, i publicar és canviar aquesta etiqueta.

2.1. Els manifests

# Deployment BLAU: la versió que està servint avui.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-reserves-blau
  namespace: rutas-norte-pro
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: api-reserves
      rutasnorte.example/color: blau
  template:
    metadata:
      labels:
        app.kubernetes.io/name: api-reserves
        rutasnorte.example/color: blau     # ← l'etiqueta que ho decideix tot
        rutasnorte.example/versio: "2.7.0"
    spec:
      # ... idèntic al Deployment d'11-01
      containers:
        - name: api
          image: registry.rutasnorte.example/rutasnorte/api-reserves@sha256:3f9c1b7e5a04c2d8f61b93ae7c05d2419e8f6ab3c4d5e6f708192a3b4c5d6e7f
---
# Deployment VERD: la versió candidata.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-reserves-verd
  namespace: rutas-norte-pro
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: api-reserves
      rutasnorte.example/color: verd
  template:
    metadata:
      labels:
        app.kubernetes.io/name: api-reserves
        rutasnorte.example/color: verd
        rutasnorte.example/versio: "2.8.0"
    spec:
      containers:
        - name: api
          image: registry.rutasnorte.example/rutasnorte/api-reserves@sha256:9a8b7c6d5e4f30291a8b7c6d5e4f30291a8b7c6d5e4f30291a8b7c6d5e4f3029
---
# Service PRODUCTIU: el que fa servir l'Ingress. El seu selector és l'interruptor.
apiVersion: v1
kind: Service
metadata:
  name: api-reserves
  namespace: rutas-norte-pro
spec:
  selector:
    app.kubernetes.io/name: api-reserves
    rutasnorte.example/color: blau       # ← canviar aquí = publicar
  ports:
    - { name: http, port: 80, targetPort: http }
---
# Service de PREVISUALITZACIÓ: apunta sempre a verd, sense trànsit d'usuaris.
apiVersion: v1
kind: Service
metadata:
  name: api-reserves-preview
  namespace: rutas-norte-pro
spec:
  selector:
    app.kubernetes.io/name: api-reserves
    rutasnorte.example/color: verd
  ports:
    - { name: http, port: 80, targetPort: http }
---
# Ingress de previsualització: URL interna per validar la candidata.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-reserves-preview
  namespace: rutas-norte-pro
  annotations:
    # Només des de la xarxa corporativa: no és una URL pública.
    nginx.ingress.kubernetes.io/whitelist-source-range: "203.0.113.0/24"
    cert-manager.io/cluster-issuer: letsencrypt-produccio
spec:
  ingressClassName: nginx
  tls:
    - hosts: ["api-preview.rutasnorte.example"]
      secretName: api-preview-tls
  rules:
    - host: api-preview.rutasnorte.example
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service: { name: api-reserves-preview, port: { name: http } }

Cada Deployment porta el seu propi HPA, el seu PDB i el seu ServiceMonitor amb l'etiqueta de color, per poder observar totes dues versions per separat a Grafana.

2.2. El procediment complet

# --- 1. Desplegar la candidata en verd (sense trànsit d'usuaris) ---
kubectl -n rutas-norte-pro set image deploy/api-reserves-verd \
  api=registry.rutasnorte.example/rutasnorte/api-reserves@sha256:9a8b7c6d...
kubectl -n rutas-norte-pro rollout status deploy/api-reserves-verd --timeout=10m
kubectl -n rutas-norte-pro scale deploy/api-reserves-verd --replicas=8

# --- 2. Validar sense trànsit real ---
# Proves de fum contra la URL de previsualització
npm run proves:fum -- --base-url https://api-preview.rutasnorte.example
# Prova de càrrega suau per descartar regressions evidents de rendiment
k6 run --vus 40 --duration 5m proves/carrega-preview.js
# Comprovació manual del flux de compra complet per part de producte

# --- 3. Commutar (això és la publicació: dura mil·lisegons) ---
kubectl -n rutas-norte-pro patch svc api-reserves \
  -p '{"spec":{"selector":{"rutasnorte.example/color":"verd"}}}'

# --- 4. Vigilar ---
watch -n5 'curl -sG http://prometheus.rutas-norte.example/api/v1/query \
  --data-urlencode "query=sum(rate(api_reserves_peticions_total{codi=~\"5..\"}[2m]))
                          / sum(rate(api_reserves_peticions_total[2m]))" | jq -r ".data.result[0].value[1]"'

# --- 5. Revertir, si cal (segons) ---
kubectl -n rutas-norte-pro patch svc api-reserves \
  -p '{"spec":{"selector":{"rutasnorte.example/color":"blau"}}}'

El pas 5 és l'argument de venda del blau-verd: la reversió és un canvi d'etiqueta. La versió anterior continua viva, calenta, amb els seus pods a punt i les seves connexions a base de dades obertes. Es torna enrere en menys de cinc segons, i no en els vuit minuts d'un rollout undo.

2.3. El que costa

Cost Detall a Rutas Norte
Recursos Durant la finestra de validació hi ha doble capacitat desplegada: 8 rèpliques blaves + 8 verdes. Al pic del pont de maig serien 40 + 40, una cosa inassumible
Connexions en curs En commutar, les connexions obertes contra pods blaus continuen allà fins que es tanquen. No és un tall, però sí una transició d'uns segons
Estat compartit Totes dues versions parlen amb la mateixa base de dades i la mateixa memòria cau. Aquest és el problema seriós, i va a l'apartat següent
Complexitat de manifests Tot duplicat: Deployment, HPA, PDB, ServiceMonitor. Amb Kustomize o Helm es gestiona, però és més superfície
Tot o res Es commuta al 100 %. Si la fallada només es manifesta amb càrrega real, la pateixen tots els usuaris durant els segons que trigues a revertir

La regla de Rutas Norte: blau-verd per a canvis grans i arriscats fora de temporada alta; mai durant el pont de maig, perquè duplicar 40 rèpliques no és viable.

  1. Migracions de base de dades compatibles amb totes dues versions

Aquí hi ha el problema real del blau-verd, i també del canari i del RollingUpdate. Es poden tenir dues versions de codi alhora. No es poden tenir dues versions de l'esquema de la base de dades.

Si api-reserves 2.8.0 necessita que la columna seient es digui placa, i la migració s'aplica en commutar, la versió blava deixa de funcionar en aquell instant i la reversió esdevé impossible.

La solució és el patró expandir i contraure: tota migració es divideix en passos, cadascun compatible amb la versió anterior i la següent.

graph LR
  V1[v2.7.0<br/>usa 'seient'] --> E[Desplegament 1: EXPANDIR<br/>afegir columna 'placa'<br/>+ disparador que sincronitza]
  E --> V2[Desplegament 2<br/>v2.8.0 escriu a totes dues<br/>llegeix de 'placa']
  V2 --> V3[Desplegament 3<br/>v2.9.0 només usa 'placa']
  V3 --> C[Desplegament 4: CONTRAURE<br/>eliminar 'seient'<br/>i el disparador]

3.1. L'exemple complet

-- ===== Migració 1: EXPANDIR (compatible amb 2.7.0) =====
-- Afegir, mai reanomenar ni esborrar.
ALTER TABLE reserves ADD COLUMN placa integer;

-- Copiar l'històric en lots, sense bloquejar la taula.
UPDATE reserves SET placa = seient
 WHERE placa IS NULL AND id IN (SELECT id FROM reserves WHERE placa IS NULL LIMIT 5000);
-- (es repeteix fins a exhaurir; en producció, mitjançant un Job per lots)

-- Disparador que manté totes dues columnes sincronitzades mentre
-- conviuen versions que escriuen en una o en l'altra.
CREATE OR REPLACE FUNCTION sincronitzar_placa() RETURNS trigger AS $$
BEGIN
  IF NEW.placa IS NULL THEN NEW.placa := NEW.seient; END IF;
  IF NEW.seient IS NULL THEN NEW.seient := NEW.placa; END IF;
  RETURN NEW;
END; $$ LANGUAGE plpgsql;

CREATE TRIGGER trg_sincronitzar_placa
  BEFORE INSERT OR UPDATE ON reserves
  FOR EACH ROW EXECUTE FUNCTION sincronitzar_placa();
-- ===== Migració 2: CONTRAURE (només quan NINGÚ no usa 'seient') =====
-- Setmanes després, amb la versió antiga ja retirada del tot.
DROP TRIGGER trg_sincronitzar_placa ON reserves;
DROP FUNCTION sincronitzar_placa();
ALTER TABLE reserves DROP COLUMN seient;
ALTER TABLE reserves ALTER COLUMN placa SET NOT NULL;

3.2. Regles pràctiques

Canvi desitjat Com fer-lo compatible
Reanomenar columna Afegir la nova, sincronitzar amb disparador, migrar codi, esborrar l'antiga després
Esborrar columna Deixar de fer-la servir al codi, esperar dues publicacions, esborrar-la
Afegir columna obligatòria Afegir-la anul·lable amb valor per defecte, emplenar, posar NOT NULL en un pas posterior
Canviar el tipus d'una columna Columna nova amb el tipus nou, doble escriptura, migrar lectures, esborrar l'antiga
Afegir índex CREATE INDEX CONCURRENTLY per no bloquejar la taula
Canviar el significat d'un valor Valor nou diferent; mai reinterpretar-ne un d'existent

La regla que ho resumeix tot: l'esquema ha d'anar sempre un pas per davant del codi i no ha de trencar mai la versió anterior. Cada migració s'aplica en el seu propi desplegament, abans que el codi que l'aprofita. És el que a 11-03 obligava a declarar a la petició de canvi de promoció si la migració era compatible cap enrere.

  1. Canari: alliberar a un percentatge d'usuaris

El canari resol el que el blau-verd no: en lloc de commutar al 100 %, s'exposa la versió nova a una fracció petita d'usuaris, s'observen les mètriques reals i s'augmenta progressivament.

4.1. La forma pobra: per nombre de rèpliques

Sense res més que un Service i dos Deployments, el repartiment de trànsit és proporcional al nombre de pods.

# 19 rèpliques estables + 1 de canària ≈ 5 % del trànsit
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-reserves-canari
  namespace: rutas-norte-pro
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: api-reserves
      rutasnorte.example/pista: canari
  template:
    metadata:
      labels:
        app.kubernetes.io/name: api-reserves    # el Service selecciona per aquesta
        rutasnorte.example/pista: canari

El Service productiu selecciona només per app.kubernetes.io/name, així que envia trànsit a tots dos Deployments repartit entre els 20 pods.

Funciona, i en un clúster sense controlador d'Ingress capaç de repartir per pes és una opció raonable. Els seus límits:

  • La granularitat depèn del nombre de rèpliques. Amb 4 rèpliques, el mínim és el 20 %. Baixar al 5 % exigiria 19 rèpliques estables.
  • L'HPA interfereix. Si escala el Deployment estable, el percentatge del canari canvia sol, sense que ningú ho decideixi.
  • No hi ha enganxositat. Un usuari alterna entre versions petició a petició, cosa que en una compra de bitllets és un problema.
  • No es pot segmentar. No es pot dir "només els empleats de Rutas Norte" o "només qui tingui aquesta capçalera".

4.2. La forma bona: pesos a ingress-nginx

ingress-nginx permet declarar un Ingress canari que comparteix host amb el principal i captura un percentatge del trànsit.

# Ingress principal: sense canvis respecte a 11-01.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-reserves
  namespace: rutas-norte-pro
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-produccio
spec:
  ingressClassName: nginx
  tls:
    - hosts: ["api.rutasnorte.example"]
      secretName: api-rutasnorte-tls
  rules:
    - host: api.rutasnorte.example
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service: { name: api-reserves-estable, port: { name: http } }
---
# Ingress CANARI: mateix host, backend diferent, amb pes.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-reserves-canari
  namespace: rutas-norte-pro
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-produccio
    # Activa el mode canari per a aquest Ingress.
    nginx.ingress.kubernetes.io/canary: "true"
    # Percentatge del trànsit que va al canari.
    nginx.ingress.kubernetes.io/canary-weight: "5"
    # Capçalera d'escapament: força el canari per a proves internes,
    # independentment del pes.
    nginx.ingress.kubernetes.io/canary-by-header: "X-Rutasnorte-Canari"
    nginx.ingress.kubernetes.io/canary-by-header-value: "sempre"
    # Cookie: un cop assignat, l'usuari es queda a la seva versió.
    nginx.ingress.kubernetes.io/canary-by-cookie: "rutasnorte_canari"
spec:
  ingressClassName: nginx
  tls:
    - hosts: ["api.rutasnorte.example"]
      secretName: api-rutasnorte-tls
  rules:
    - host: api.rutasnorte.example          # ← MATEIX host que el principal
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service: { name: api-reserves-canari, port: { name: http } }

L'ordre de precedència de les anotacions és important i no sempre evident:

  1. canary-by-header amb el valor exacte → sempre al canari (o never → mai).
  2. canary-by-cookie → segons el valor de la cookie.
  3. canary-weight → decisió aleatòria pel percentatge indicat.

La capçalera és el que permet validar en producció sense exposar ningú:

# Validació interna dirigida al canari, amb 0 % de pes
curl -H 'X-Rutasnorte-Canari: sempre' https://api.rutasnorte.example/horaris?linia=BIL-SAN

Progressió manual del pes:

for PES in 5 10 25 50 100; do
  kubectl -n rutas-norte-pro annotate ingress api-reserves-canari \
    nginx.ingress.kubernetes.io/canary-weight="$PES" --overwrite
  echo "Pes al $PES %. Observant 10 minuts..."
  sleep 600
  # aquí algú mira Grafana i decideix si continua
done

I aquest bucle, amb el seu sleep 600 i el seu "aquí algú mira Grafana", és exactament el que cal automatitzar.

  1. Argo Rollouts: automatitzar el canari amb anàlisi

Argo Rollouts substitueix el Deployment per un recurs Rollout que sap progressar per passos, consultar mètriques i decidir per si mateix si continuar o avortar.

sequenceDiagram
  participant G as Git (nou digest)
  participant R as Controlador Rollout
  participant N as ingress-nginx
  participant P as Prometheus
  G->>R: Canvia la imatge del Rollout
  R->>R: Crea ReplicaSet canari
  R->>N: setWeight 5 %
  R->>P: AnalysisRun (taxa d'error, p95)
  P-->>R: 0,04 % errors · p95 210 ms → correcte
  R->>N: setWeight 25 %
  R->>P: AnalysisRun
  P-->>R: 0,9 % errors → FALLADA
  R->>N: setWeight 0 % (avorta)
  R->>R: Escala el canari a zero, l'estable continua intacta

5.1. El recurs Rollout

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: api-reserves
  namespace: rutas-norte-pro
spec:
  # replicas ho continua governant l'HPA, que ara apunta al Rollout.
  revisionHistoryLimit: 5
  selector:
    matchLabels:
      app.kubernetes.io/name: api-reserves
  # 'template' és idèntic al del Deployment d'11-01: mateixes sondes,
  # mateix securityContext, mateixos recursos, mateix topologySpread.
  template:
    metadata:
      labels:
        app.kubernetes.io/name: api-reserves
    spec:
      serviceAccountName: api-reserves
      containers:
        - name: api
          image: registry.rutasnorte.example/rutasnorte/api-reserves@sha256:9a8b7c6d5e4f30291a8b7c6d5e4f30291a8b7c6d5e4f30291a8b7c6d5e4f3029
          # ... resta idèntica a 11-01

  strategy:
    canary:
      canaryService: api-reserves-canari      # Services que el controlador
      stableService: api-reserves-estable     # reetiqueta automàticament
      trafficRouting:
        nginx:
          stableIngress: api-reserves          # crea i gestiona l'Ingress canari
      # Anàlisi que s'executa en paral·lel a TOTA la progressió.
      analysis:
        templates:
          - templateName: analisi-api-reserves
        startingStep: 1        # comença en assolir el primer pes
        args:
          - name: servei-canari
            value: api-reserves-canari
      steps:
        - setWeight: 5
        - pause: { duration: 10m }     # 10 min amb el 5 % del trànsit
        - setWeight: 25
        - pause: { duration: 15m }
        - setWeight: 50
        - pause: { duration: 20m }
        - setWeight: 75
        - pause: { duration: 10m }
        # Sense durada: espera aprovació humana explícita abans del 100 %.
        - pause: {}
      # Finestres de seguretat
      scaleDownDelaySeconds: 600   # la versió anterior continua viva 10 min després de promocionar
      abortScaleDownDelaySeconds: 30
      maxSurge: "25%"
      maxUnavailable: 0

L'últim pause: {} sense durada és una decisió deliberada de Rutas Norte: l'anàlisi automàtica pot portar el canari fins al 75 %, però el salt final al 100 % el confirma una persona. És un equilibri entre automatitzar la vigilància i conservar un punt de control humà.

5.2. L'AnalysisTemplate contra Prometheus

Aquí es decideix de debò. Les consultes són PromQL sobre les mètriques que api-reserves exposa des de 07-03.

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: analisi-api-reserves
  namespace: rutas-norte-pro
spec:
  args:
    - name: servei-canari
  metrics:

    # --- 1. Taxa d'error 5xx ---
    - name: taxa-error
      interval: 1m
      # Tolera 2 mesures dolentes aïllades; 3 de consecutives avorten.
      failureLimit: 2
      consecutiveErrorLimit: 3
      # No jutja durant els primers 2 min: els pods s'estan escalfant.
      initialDelay: 2m
      provider:
        prometheus:
          address: http://prometheus-operated.monitoratge:9090
          query: |
            sum(rate(api_reserves_peticions_total{
              service="{{args.servei-canari}}", codi=~"5.."
            }[2m]))
            /
            sum(rate(api_reserves_peticions_total{
              service="{{args.servei-canari}}"
            }[2m]))
      # Èxit si el resultat és < 0,5 %. NaN (sense trànsit) també s'accepta:
      # sense peticions no hi ha evidència de fallada.
      successCondition: result[0] < 0.005 || isNaN(result[0])

    # --- 2. Percentil 95 de latència ---
    - name: latencia-p95
      interval: 1m
      failureLimit: 2
      initialDelay: 2m
      provider:
        prometheus:
          address: http://prometheus-operated.monitoratge:9090
          query: |
            histogram_quantile(0.95,
              sum by (le) (rate(api_reserves_duracio_segons_bucket{
                service="{{args.servei-canari}}"
              }[2m]))
            )
      successCondition: result[0] < 0.35 || isNaN(result[0])   # 350 ms

    # --- 3. Comparació relativa contra la versió estable ---
    # Un llindar absolut pot passar per alt una regressió si el sistema
    # ja anava lent. Aquesta mètrica exigeix que el canari no sigui més d'un 20 %
    # pitjor que l'estable.
    - name: latencia-relativa
      interval: 2m
      failureLimit: 1
      initialDelay: 5m
      provider:
        prometheus:
          address: http://prometheus-operated.monitoratge:9090
          query: |
            (
              histogram_quantile(0.95, sum by (le) (rate(
                api_reserves_duracio_segons_bucket{service="api-reserves-canari"}[3m])))
              /
              histogram_quantile(0.95, sum by (le) (rate(
                api_reserves_duracio_segons_bucket{service="api-reserves-estable"}[3m])))
            )
      successCondition: result[0] < 1.2 || isNaN(result[0])

    # --- 4. Mètrica de negoci: la que de debò importa ---
    # Una versió pot tenir 0 errors i latència perfecta, i haver trencat
    # el botó de "confirmar reserva". Això ho detecta.
    - name: taxa-conversio
      interval: 5m
      failureLimit: 1
      initialDelay: 10m
      provider:
        prometheus:
          address: http://prometheus-operated.monitoratge:9090
          query: |
            sum(rate(api_reserves_reserves_confirmades_total{
              service="api-reserves-canari"}[5m]))
            /
            sum(rate(api_reserves_reserves_iniciades_total{
              service="api-reserves-canari"}[5m]))
      successCondition: result[0] > 0.55 || isNaN(result[0])

La quarta mètrica és la més valuosa i la que més equips obliden. Un desplegament pot ser impecable en tots els indicadors tècnics i estar perdent la meitat de les vendes.

5.3. Promoció i avortament automàtics

Promoció automàtica: si totes les mètriques compleixen la seva condició durant tots els passos, el Rollout avança sol per l'escala de pesos fins a l'últim pause: {}.

Avortament automàtic: tan bon punt una mètrica supera el seu failureLimit, el controlador posa el pes del canari a 0 immediatament, escala el ReplicaSet canari a zero i deixa intacte l'estable. No cal revertir res, perquè la versió estable mai no va deixar de servir la majoria del trànsit.

kubectl argo rollouts get rollout api-reserves -n rutas-norte-pro --watch
Name:            api-reserves
Namespace:       rutas-norte-pro
Status:          ✖ Degraded
Message:         RolloutAborted: metric "taxa-error" assessed Failed
Strategy:        Canary
  Step:          2/9
  SetWeight:     0
  ActualWeight:  0
Images:          api-reserves@sha256:3f9c1b7e (stable)
                 api-reserves@sha256:9a8b7c6d (canary)
Replicas:
  Desired:       8
  Current:       8
  Updated:       0
  Ready:         8
  Available:     8

NAME                                     KIND         STATUS        AGE   INFO
⟳ api-reserves                           Rollout      ✖ Degraded    41d
├──# revision:18
│  └──⧉ api-reserves-6d9f7b4c8            ReplicaSet   • ScaledDown  14m   canary
│     └──⊞ analisi-api-reserves-18        AnalysisRun  ✖ Failed      12m
│        ├──📊 taxa-error                 Measurement  ✖ Failed            0.021
│        └──📊 latencia-p95               Measurement  ✔ Successful        0.198
└──# revision:17
   └──⧉ api-reserves-7d4b8c9f5            ReplicaSet   ✔ Healthy     14d   stable

Aquesta sortida és diagnòstic complet per si sola: es va avortar al pas 2, per taxa-error al 2,1 % davant del llindar del 0,5 %, amb la latència perfectament bé. El següent lloc on mirar són els logs dels pods canaris abans que desapareguin (scaleDownDelaySeconds els manté una estona justament per això).

Comandes de control manual:

kubectl argo rollouts promote api-reserves -n rutas-norte-pro        # avançar un pas
kubectl argo rollouts promote api-reserves -n rutas-norte-pro --full # saltar al 100 %
kubectl argo rollouts abort api-reserves -n rutas-norte-pro          # avortar ja
kubectl argo rollouts undo api-reserves -n rutas-norte-pro --to-revision=17

5.4. La interfície de seguiment

kubectl argo rollouts dashboard -n rutas-norte-pro

Aixeca una interfície web a localhost:3100 que mostra l'escala de passos, el pes actual, el resultat de cada mesura i els botons de promocionar i avortar. A Rutas Norte es projecta en una pantalla durant els desplegaments de la temporada alta: no és imprescindible, però converteix una operació opaca en una cosa que tot l'equip entén d'un cop d'ull.

5.5. Convivència amb Argo CD

Un Rollout és un CRD, així que Argo CD el sincronitza com qualsevol altre recurs. Dos ajustos necessaris:

# A l'Application d'Argo CD
spec:
  ignoreDifferences:
    - group: argoproj.io
      kind: Rollout
      jsonPointers:
        - /spec/replicas          # ho governa l'HPA
  syncPolicy:
    automated:
      selfHeal: true
      # El controlador de Rollouts modifica els Services durant la
      # progressió; sense això, selfHeal lluitaria contra ell.
    syncOptions:
      - RespectIgnoreDifferences=true

I l'HPA ha d'apuntar al Rollout, no a un Deployment:

spec:
  scaleTargetRef:
    apiVersion: argoproj.io/v1alpha1
    kind: Rollout
    name: api-reserves

  1. Flagger com a alternativa

Flagger resol el mateix problema amb una filosofia diferent: en lloc de substituir el Deployment, l'embolcalla. Es manté el Deployment de sempre i s'afegeix un recurs Canary que el gestiona.

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: api-reserves
  namespace: rutas-norte-pro
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment          # ← el Deployment original, sense tocar
    name: api-reserves
  autoscalerRef:
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    name: api-reserves
  provider: nginx
  service:
    port: 80
    targetPort: 8080
  analysis:
    interval: 1m
    threshold: 5              # mesures fallides abans d'avortar
    maxWeight: 50
    stepWeight: 10
    metrics:
      - name: request-success-rate
        thresholdRange: { min: 99.5 }
        interval: 2m
      - name: request-duration
        thresholdRange: { max: 350 }
        interval: 2m
    webhooks:
      - name: proves-de-carrega
        type: rollout
        url: http://flagger-loadtester.plataforma/
        metadata:
          cmd: "hey -z 2m -q 10 -c 2 http://api-reserves-canary.rutas-norte-pro/horaris"
Aspecte Argo Rollouts Flagger
Recurs de càrrega Substitueix el Deployment per Rollout Conserva el Deployment i l'embolcalla
Migrar des de Deployment Canviar kind i ajustar HPA i Argo CD Afegir un Canary, sense tocar el que ja hi ha
Interfície gràfica Sí, pròpia i molt bona No pròpia; es fa servir Grafana
CLI dedicada kubectl argo rollouts, molt completa kubectl describe canary
Estratègies Canari, blau-verd, amb o sense malla Canari, blau-verd, A/B, mirall de trànsit
Mètriques AnalysisTemplate totalment lliure Mètriques predefinides + personalitzades
Generació de càrrega Externa Integrada (loadtester)
Encaixa millor amb Ecosistema Argo (Argo CD, Workflows) Ecosistema Flux
Control manual fi Molt bo (promote, abort, passos) Més automàtic, menys intervenció

No hi ha una resposta universal. Rutas Norte va triar Argo Rollouts per coherència amb Argo CD (10-05), per la CLI i la interfície, i per la llibertat total de l'AnalysisTemplate, que calia per a la mètrica de conversió. Un equip que faci servir Flux triaria Flagger amb la mateixa lògica.

  1. Banderes de funcionalitat: separar el desplegament de l'activació

Tot l'anterior controla quina versió del codi corre. Les banderes de funcionalitat controlen una cosa diferent: quin comportament té el codi que ja està corrent.

// api-reserves: la funcionalitat viatja desplegada però apagada.
app.post('/reserves', async (req, res) => {
  const usarNouMotor = await banderes.activa('motor-preus-v2', {
    usuariId: req.usuari.id,
    percentatge: 5,                      // desplegament progressiu per usuari
    llistaBlanca: ['empleats-rutasnorte']
  });

  const preu = usarNouMotor
    ? await motorPreusV2.calcular(req.body)
    : await motorPreusV1.calcular(req.body);

  // Mètrica etiquetada per bandera: permet comparar tots dos camins
  // a Grafana sense desplegar res diferent.
  metriques.preuCalculat.inc({ motor: usarNouMotor ? 'v2' : 'v1' });
  ...
});
Aspecte Canari Bandera de funcionalitat
Unitat de control La versió completa de l'artefacte Una funcionalitat concreta
Granularitat del públic Percentatge de peticions, per capçalera o cookie Per usuari, pla, regió, o qualsevol atribut
Velocitat d'activació Minuts (progressió de pesos) Segons (canvi de configuració)
Velocitat de desactivació Segons (avortar) Segons, i sense tocar el clúster
Qui la pot accionar Plataforma o desenvolupament Producte, suport, negoci
Cost Doble capacitat temporal Complexitat al codi
Deute que genera Cap Branques mortes si no es netegen

Quan la bandera és millor que el canari:

  • La funcionalitat és de negoci, no tècnica: qui decideix activar-la és producte, no enginyeria.
  • Cal activar per a un segment concret (els clients empresa, una regió, els empleats interns), no per a un percentatge aleatori.
  • El canvi ha de poder apagar-se en segons per algú de suport a les tres de la matinada, sense desplegar.
  • Es vol fer una prova A/B i mesurar conversió durant setmanes.
  • El canvi és gran i es vol integrar a main per parts sense publicar res.

Quan el canari és millor:

  • El canvi és transversal: nova versió d'una biblioteca, canvi de la imatge base, refactorització interna, actualització del runtime. No hi ha cap "si" per posar.
  • El risc és de rendiment o de consum de recursos, no de comportament funcional.
  • No vols codi mort convivint en producció.

Es combinen molt bé: canari per publicar l'artefacte amb seguretat, banderes per activar la funcionalitat després, amb el públic que decideixi producte.

Un advertiment sobre el deute: cada bandera duplica un camí de codi i per tant duplica el que cal provar. La regla de Rutas Norte és que tota bandera neix amb data de caducitat anotada al codi, i hi ha una revisió trimestral que elimina les que ja han complert la seva funció.

  1. El pla de Rutas Norte per al pont de maig

Situació real: api-reserves 2.8.0 inclou el nou motor de preus dinàmics, que és la funcionalitat amb la qual l'empresa espera augmentar ingressos durant la temporada alta. Cal publicar-la la setmana anterior al pont de maig, el pitjor moment possible per equivocar-se.

8.1. Restriccions

Restricció Implicació
El pont comença el divendres 1 de maig Congelació de canvis des del dimecres 29 a les 18:00
El trànsit es multiplica per deu durant tres dies No es pot duplicar capacitat: el blau-verd queda descartat
El motor de preus afecta la conversió Cal una mètrica de negoci, no només tècnica
Hi ha migració d'esquema (taula regles_preu) Ha de ser expandir i contraure, i compatible amb 2.7.0
Una reversió ha de ser immediata Descartat qualsevol canvi irreversible

8.2. El calendari

Moment Acció Criteri per continuar
Dilluns 20, 10:00 Desplegament 1: migració d'expansió (taules noves, sense ús) Migració aplicada, api-reserves 2.7.0 sense canvis a les seves mètriques
Dilluns 20, 16:00 Desplegament 2: Rollout de 2.8.0 amb el motor v2 apagat per bandera Anàlisi del canari correcta en tots els passos
Dimarts 21 2.8.0 al 100 %, motor v2 apagat 24 h sense alertes ni regressió de latència
Dimecres 22, 10:00 Bandera activada per a empleats (llista blanca) Validació funcional de producte: preus correctes
Dimecres 22, 16:00 Bandera a l'1 % d'usuaris reals Conversió del segment ≥ 55 %, sense queixes a suport
Dijous 23 Bandera al 10 % Conversió i tiquet mitjà comparables o millors; sense errors 5xx atribuïbles
Divendres 24 Bandera al 50 % Mateix criteri, amb volum més gran
Dilluns 27, 10:00 Bandera al 100 % Decisió conjunta de producte i plataforma
Dimecres 29, 18:00 Congelació: cap canvi fins al dimarts 5 de maig

L'important d'aquest pla és que separa dos riscos diferents: el risc tècnic de la versió nova (canari, dilluns i dimarts) i el risc de negoci del motor de preus (bandera, de dimecres a dilluns). Barrejar-los hauria fet impossible saber quin dels dos causava un problema.

8.3. Criteris d'èxit i llindars d'avortament

# AnalysisTemplate específic per a aquesta publicació, amb llindars més
# estrictes de l'habitual per la proximitat de la temporada alta.
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: analisi-pont-maig
  namespace: rutas-norte-pro
spec:
  metrics:
    - name: taxa-error
      interval: 30s
      failureLimit: 1            # tolerància mínima: una mesura dolenta avorta
      initialDelay: 2m
      provider:
        prometheus:
          address: http://prometheus-operated.monitoratge:9090
          query: |
            sum(rate(api_reserves_peticions_total{service="api-reserves-canari",codi=~"5.."}[2m]))
            / sum(rate(api_reserves_peticions_total{service="api-reserves-canari"}[2m]))
      successCondition: result[0] < 0.003 || isNaN(result[0])      # 0,3 %

    - name: latencia-p95
      interval: 30s
      failureLimit: 1
      initialDelay: 2m
      provider:
        prometheus:
          address: http://prometheus-operated.monitoratge:9090
          query: |
            histogram_quantile(0.95, sum by (le) (rate(
              api_reserves_duracio_segons_bucket{service="api-reserves-canari"}[2m])))
      successCondition: result[0] < 0.30 || isNaN(result[0])        # 300 ms

    - name: errors-passarela-pagaments
      interval: 1m
      failureLimit: 1
      initialDelay: 5m
      provider:
        prometheus:
          address: http://prometheus-operated.monitoratge:9090
          query: |
            sum(rate(api_reserves_pagaments_fallits_total{service="api-reserves-canari"}[5m]))
            / sum(rate(api_reserves_pagaments_intents_total{service="api-reserves-canari"}[5m]))
      successCondition: result[0] < 0.02 || isNaN(result[0])        # 2 %

    - name: conversio
      interval: 5m
      failureLimit: 1
      initialDelay: 15m
      provider:
        prometheus:
          address: http://prometheus-operated.monitoratge:9090
          query: |
            sum(rate(api_reserves_reserves_confirmades_total{service="api-reserves-canari"}[10m]))
            / sum(rate(api_reserves_reserves_iniciades_total{service="api-reserves-canari"}[10m]))
      successCondition: result[0] > 0.55 || isNaN(result[0])
Criteri d'èxit Llindar Llindar d'avortament
Errors 5xx < 0,1 % ≥ 0,3 % en una mesura
Latència p95 < 250 ms ≥ 300 ms en una mesura
Fallades de passarel·la de pagaments < 1 % ≥ 2 %
Conversió de reserva ≥ 60 % < 55 %
Reinicis de pod canari 0 ≥ 1
Alertes noves a Alertmanager 0 Qualsevol de severitat alta

8.4. El pla de reversió

Tres nivells, del més ràpid al més lent:

  1. Bandera apagada (5 segons, sense desplegar): desactiva el motor de preus v2. Cobreix el 80 % dels riscos d'aquesta publicació. Ho pot fer suport sense trucar a ningú.
  2. Avortar el Rollout (10 segons): kubectl argo rollouts abort api-reserves. Retorna tot el trànsit a la versió estable, que mai no va deixar de servir.
  3. Revertir a Git (4 minuts): git revert del commit de promoció a overlays/pro i sincronització d'Argo CD. És el que deixa el sistema coherent i el que es fa sempre després del nivell 1 o 2.

La migració d'expansió no es reverteix: les taules noves queden allà, sense usar, sense molestar. La seva contracció està programada per al juny, passada la temporada alta.

8.5. Què va passar realment

Al segon pas del canari (pes 25 %), l'anàlisi va avortar per latencia-p95 en 340 ms. La causa: el motor de preus v2 consultava regles_preu sense índex sobre (linia, franja_horaria). Es va detectar en onze minuts, va afectar el 25 % del trànsit durant menys de dos minuts i no va generar cap incidència de cara al client. Es va afegir l'índex amb CREATE INDEX CONCURRENTLY, es va repetir el canari aquella mateixa tarda i va passar net.

Aquest és exactament el valor de tot l'anterior: un problema que amb RollingUpdate hauria estat un incident de severitat 2 en ple pont de maig es va resoldre com una tasca d'una tarda.

  1. Comparativa de les quatre estratègies

Criteri Rodant Blau-verd Canari Banderes
Risc d'exposició Alt: arriba al 100 % sense validar Mitjà: tot o res en commutar Baix: percentatge petit primer Molt baix: segment triat
Cost en recursos Baix (+25 % temporal) Alt (×2 durant la finestra) Mitjà (+10-25 %) Cap
Complexitat d'implantació Nul·la, ve de sèrie Baixa: dos Deployments i un selector Mitjana-alta: controlador i anàlisi Mitjana: servei de banderes i disciplina
Velocitat de reversió Lenta: minuts Ràpida: segons Immediata: avortar Immediata: apagar
Validació amb trànsit real abans de comprometre's No Només sintètica Sí, segmentada
Automatització de la decisió No Difícil Sí, amb mètriques Manual, o per experiment
Convivència de versions Sí, descontrolada No (salt net) Sí, controlada Sí, al mateix procés
Exigència sobre migracions Compatibles Compatibles Compatibles Compatibles
Deute que deixa Cap Manifests duplicats Configuració d'anàlisi Codi mort si no es neteja
Quan fer-la servir Canvis petits i rutinaris Canvis grans fora de temporada alta Publicacions de risc amb mètriques fiables Funcionalitats de negoci i proves A/B

Elecció pràctica a Rutas Norte:

  • Rodant per a botiga-web i per a canvis de configuració: baix risc, no compensa la complexitat.
  • Canari amb Argo Rollouts per a tota publicació d'api-reserves: és el component crític i té mètriques de qualitat.
  • Blau-verd per a migracions d'infraestructura grans (com el canvi de versió major de PostgreSQL d'11-02), i només fora de temporada alta.
  • Banderes per a tota funcionalitat visible per a l'usuari, sempre, sobre qualsevol de les anteriors.

Errors Comuns i Consells

  • Fer blau-verd amb una migració d'esquema no compatible. La reversió, que era l'argument sencer de l'estratègia, deixa de ser possible en l'instant en què s'aplica la migració. Expandir i contraure, sempre.
  • Llindars d'anàlisi absoluts i res més. Si el sistema ja va lent, un p95 de 340 ms pot passar el llindar de 350 ms sent una regressió del 70 %. Afegeix sempre una mètrica relativa contra la versió estable.
  • Oblidar isNaN(result[0]) a les condicions. Amb pes al 5 % i poc trànsit, una consulta pot retornar NaN i l'anàlisi fallar sense que hi hagi cap problema real.
  • Canari sense mètrica de negoci. Tots els indicadors tècnics perfectes i la conversió pels terres és un escenari real i freqüent. La mètrica de negoci és la que justifica el canari.
  • Analitzar des del primer segon. Els pods acabats d'arrencar tenen la memòria cau freda i el JIT sense escalfar. Sense initialDelay, s'avorta per falsos positius sistemàticament.
  • Pesos per nombre de rèpliques amb HPA actiu. L'autoescalat canvia el percentatge sense que ningú ho decideixi. Si hi ha HPA, fes servir repartiment per pes a l'Ingress.
  • Banderes eternes. Cada bandera sense caducitat duplica camins de codi per sempre. Data de caducitat en crear-la i revisió trimestral.
  • Consell: assaja el canari amb una versió idèntica a l'actual. Desplegar el mateix digest com a canari valida tota la maquinària sense cap risc, i descobreix llindars mal calibrats abans que importin.
  • Consell: deixa la versió anterior viva una estona després de promocionar (scaleDownDelaySeconds). Els problemes que apareixen als cinc minuts són més freqüents que els dels cinc primers segons.

Exercicis

Exercici 1: triar estratègia i justificar-la

Per a cadascun d'aquests canvis a Rutas Norte, tria l'estratègia més adequada i justifica-la en dues o tres frases:

  1. Actualitzar la imatge base d'api-reserves de Node 22.4 a 22.9 per un pedaç de seguretat, sense canvis funcionals.
  2. Canviar el disseny de la pàgina de selecció de seient de botiga-web, sobre la qual producte vol mesurar conversió durant tres setmanes.
  3. Substituir el motor de cerca de rutes per un de nou, amb el mateix contracte d'API però un algorisme intern completament diferent.
  4. Corregir una errada en un text de la SPA.

Exercici 2: detectar la fallada en un AnalysisTemplate

metrics:
  - name: taxa-error
    interval: 10s
    failureLimit: 0
    provider:
      prometheus:
        address: http://prometheus-operated.monitoratge:9090
        query: |
          sum(rate(api_reserves_peticions_total{codi=~"5.."}[30s]))
          / sum(rate(api_reserves_peticions_total[30s]))
    successCondition: result[0] < 0.001

Aquesta anàlisi avorta pràcticament tots els canaris, fins i tot els correctes. Identifica quatre problemes i proposa el manifest corregit.

Exercici 3: dissenyar la publicació completa

api-reserves incorporarà la possibilitat de cancel·lar una reserva des del web. Requereix: una columna nova estat a la taula reserves (valors activa i cancelada), un endpoint nou DELETE /reserves/{id}, un canvi a botiga-web per mostrar el botó, i notificació per correu mitjançant worker-notificacions. La publicació és a l'octubre, fora de temporada alta. Dissenya la seqüència completa: quants desplegaments, quina estratègia a cadascun, en quin ordre, i què permet revertir a cada punt.

Solucions

Solució 1.

  1. Canari. No hi ha funcionalitat per activar ni condicional per escriure, així que la bandera no s'hi aplica. El risc és tècnic (rendiment, compatibilitat de dependències natives) i precisament això és el que l'anàlisi de mètriques detecta. El blau-verd seria innecessàriament car.
  2. Bandera de funcionalitat, complementada amb el desplegament rodant habitual de botiga-web. Producte necessita controlar el segment i mesurar conversió durant setmanes: això és un experiment A/B, no una publicació. El canari dura minuts, no tres setmanes.
  3. Canari amb anàlisi reforçada, incloent-hi mètriques de negoci (qualitat dels resultats de cerca mesurada per clics a la primera opció) i latència relativa contra l'estable. Com que el contracte d'API no canvia, no cal tocar la SPA ni l'esquema; el risc és de comportament i rendiment, exactament el que el canari valida. Complementàriament, una bandera permetria tornar al motor antic sense desplegar.
  4. Rodant. Risc pràcticament nul. Muntar un canari per a una errada és sobreenginyeria que a més retarda la correcció.

Solució 2. Problemes:

# Problema Efecte
1 Sense initialDelay Jutja els primers segons, amb els pods escalfant-se i la memòria cau freda: falsos positius sistemàtics
2 failureLimit: 0 Una única mesura dolenta, encara que sigui un pic transitori d'un segon, avorta
3 Sense filtrar per service="...-canari" Mesura l'error de tota l'aplicació, estable inclosa: si l'estable té errors, el canari no pot passar mai
4 Finestra [30s] amb interval: 10s Finestra massa curta: molt poca mostra, molt soroll, i mesures solapades
5 Sense isNaN Amb el 5 % del trànsit pot no haver-hi peticions a la finestra i retornar NaN, que falla la condició

Correcció:

metrics:
  - name: taxa-error
    interval: 1m
    failureLimit: 2
    consecutiveErrorLimit: 3
    initialDelay: 2m
    provider:
      prometheus:
        address: http://prometheus-operated.monitoratge:9090
        query: |
          sum(rate(api_reserves_peticions_total{service="api-reserves-canari",codi=~"5.."}[2m]))
          / sum(rate(api_reserves_peticions_total{service="api-reserves-canari"}[2m]))
    successCondition: result[0] < 0.005 || isNaN(result[0])

Solució 3. Cinc desplegaments:

  1. Migració d'expansió. ALTER TABLE reserves ADD COLUMN estat text DEFAULT 'activa' (anul·lable, amb valor per defecte). Cap versió de codi no la fa servir encara. Reversió: innecessària, la columna és innòcua per a la 2.x actual.
  2. api-reserves amb l'endpoint nou, protegit per bandera apagada. Canari amb Argo Rollouts. L'endpoint DELETE /reserves/{id} existeix però retorna 404 amb la bandera apagada. Reversió: avortar el canari, o apagar la bandera (ja està apagada).
  3. worker-notificacions amb la plantilla de correu de cancel·lació. Rodant: és un consumidor de cua, sense trànsit d'usuaris. S'ha de desplegar abans que es pugui cancel·lar, perquè no hi hagi cancel·lacions sense notificació. Reversió: rollout undo, sense impacte.
  4. botiga-web amb el botó, condicionat per la mateixa bandera. Rodant. El botó no apareix mentre la bandera estigui apagada. Reversió: rodant inversa, o simplement deixar el botó ocult.
  5. Activació progressiva de la bandera: empleats → 5 % → 25 % → 100 %, vigilant la taxa de cancel·lació (una taxa anormalment alta indicaria que el botó està mal ubicat o que es cancel·la per error) i els errors de l'endpoint. Reversió: apagar la bandera, cinc segons, sense desplegar res.
  6. Contracció, al novembre: ALTER COLUMN estat SET NOT NULL un cop confirmat que totes les files tenen valor i que cap versió antiga no continua viva.

L'ordre clau és que la capacitat (endpoint i worker) es desplega abans que la interfície (botó), i que totes dues queden inertes fins que la bandera s'activa. Així, en tot moment anterior al pas 5 el sistema és funcionalment idèntic a l'actual, i qualsevol desplegament es pot revertir sense conseqüències.

Conclusió

Hem vist quatre maneres de reduir el risc de publicar. El RollingUpdate és còmode i suficient per al que és rutinari, però avança guiant-se per la sonda de preparació, que només sap si el procés respon, no si la versió funciona bé. El blau-verd compra una reversió instantània a canvi de duplicar la capacitat i de commutar-ho tot de cop. El canari exposa la versió nova a una fracció petita d'usuaris i permet decidir amb evidència real; amb Argo Rollouts aquesta decisió s'automatitza consultant Prometheus, amb promoció i avortament automàtics, i amb Flagger s'aconsegueix el mateix amb una altra filosofia. Les banderes de funcionalitat operen en una altra dimensió: separen el desplegament del codi de l'activació del comportament, i posen l'interruptor a mans de producte i de suport.

I per sota de totes elles hi ha una condició que no es pot saltar: les migracions de base de dades han de ser compatibles amb la versió anterior i la següent. Sense expandir i contraure, cap de les quatre estratègies no pot revertir de debò.

El cas del pont de maig resumeix la lliçó: separant el risc tècnic (canari) del risc de negoci (bandera), un problema de rendiment causat per un índex absent es va detectar en onze minuts, va afectar una fracció del trànsit durant menys de dos, i es va resoldre com una tasca d'una tarda en lloc de com un incident al cap de setmana de més vendes de l'any.

Fins aquí hem treballat sempre sobre un clúster. A la lliçó següent, Gestió Multi-Clúster, veurem què canvia quan la plataforma deixa de cabre en un de sol: per què les empreses acaben amb uns quants, com es treballa cada dia sense aplicar mai a l'equivocat, com Argo CD desplega en tota una flota, i el problema que no té solució fàcil quan cal recuperar-se d'un desastre, que és la dada.

Curs de Kubernetes

Mòdul 1: Introducció a Kubernetes

Mòdul 2: Components Principals de Kubernetes

Mòdul 3: Gestió de Configuració i Secrets

Mòdul 4: Xarxes a Kubernetes

Mòdul 5: Emmagatzematge a Kubernetes

Mòdul 6: Conceptes Avançats de Kubernetes

Mòdul 7: Monitoratge i Registre

Mòdul 8: Seguretat a Kubernetes

Mòdul 9: Escalat i Rendiment

Mòdul 10: Ecosistema i Eines de Kubernetes

Mòdul 11: Estudis de Cas i Aplicacions del Món Real

Mòdul 12: Preparació per a la Certificació de Kubernetes

© Copyright 2026. Tots els drets reservats