fix(ci): condicion de carrera en el chequeo de promocion GitOps
Build and Push Medusa / Escaneo de Secretos (Gitleaks) (push) Successful in 22s
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 26s
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (push) Successful in 28s
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 17m19s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 8m23s
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Successful in 6m18s
Build and Push Medusa / Escaneo de Secretos (Gitleaks) (push) Successful in 22s
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 26s
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (push) Successful in 28s
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 17m19s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 8m23s
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Successful in 6m18s
Con el runner corriendo 1 job a la vez (capacity: 1), cuando 2+ pipelines comparten el mismo commit disparador, el primero en terminar deja su propio commit de GitOps en main -- los siguientes veian 'main ya no es igual a mi commit' y se saltaban su propia promocion, aunque era seguro promocionar. Visto en vivo: Frontend construyo, escaneo y firmo v1.0.119 pero el manifiesto seguia en v1.0.104 (Promocion GitOps: false). Fix en los 3 workflows: git merge-base --is-ancestor en vez de comparacion exacta de SHA. Bump manual de frontend a v1.0.119 (la version que ya estaba lista, sin desplegar). Documentado el limite conocido de este fix en el playbook de la migracion. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_011FqYP3Wf1W63Qmh7qgXAAT
This commit is contained in:
1 parent
788505a1bb
commit
29021bff70
5 files changed
+83
-4
No files matched your search
@@ -344,6 +344,10 @@ jobs:
|
|||||||
--insecure-ignore-tlog=true \
|
--insecure-ignore-tlog=true \
|
||||||
"${IMAGE_NAME}@${{ steps.push.outputs.digest }}"
|
"${IMAGE_NAME}@${{ steps.push.outputs.digest }}"
|
||||||
|
|
||||||
|
# merge-base --is-ancestor, no comparación exacta -- ver el
|
||||||
|
# comentario largo en build.yaml sobre por qué (condición de
|
||||||
|
# carrera real con 2+ pipelines compartiendo un commit, visto en
|
||||||
|
# vivo 2026-08-17).
|
||||||
- name: Verificar promoción segura
|
- name: Verificar promoción segura
|
||||||
id: promotion
|
id: promotion
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -355,7 +359,7 @@ jobs:
|
|||||||
CURRENT_SHA="${{ github.sha }}"
|
CURRENT_SHA="${{ github.sha }}"
|
||||||
REMOTE_SHA="$(git rev-parse origin/main)"
|
REMOTE_SHA="$(git rev-parse origin/main)"
|
||||||
|
|
||||||
if [ "${CURRENT_SHA}" = "${REMOTE_SHA}" ]; then
|
if git merge-base --is-ancestor "${CURRENT_SHA}" origin/main; then
|
||||||
echo "promote=true" >> "$GITHUB_OUTPUT"
|
echo "promote=true" >> "$GITHUB_OUTPUT"
|
||||||
else
|
else
|
||||||
echo "promote=false" >> "$GITHUB_OUTPUT"
|
echo "promote=false" >> "$GITHUB_OUTPUT"
|
||||||
|
|||||||
@@ -489,6 +489,17 @@ jobs:
|
|||||||
|
|
||||||
# Evita que una ejecución antigua actualice frontend.yaml después de que
|
# Evita que una ejecución antigua actualice frontend.yaml después de que
|
||||||
# ya exista un commit más reciente en main.
|
# ya exista un commit más reciente en main.
|
||||||
|
#
|
||||||
|
# merge-base --is-ancestor, no comparación exacta de SHA: cuando 2+
|
||||||
|
# pipelines comparten el mismo commit disparador y el runner los
|
||||||
|
# corre en serie (capacity: 1), el primero en terminar ya dejó su
|
||||||
|
# propio commit de GitOps en main -- con comparación exacta, los
|
||||||
|
# demás ven "main ya no es igual a mi commit" y se saltan la
|
||||||
|
# promoción sin necesidad (visto en vivo 2026-08-17, ver
|
||||||
|
# docs/playbooks/migracion-platform-templates-2026-08.md). Con
|
||||||
|
# is-ancestor, mientras el commit que disparó ESTE pipeline siga
|
||||||
|
# siendo ancestro de main, promociona igual -- solo bloquea si de
|
||||||
|
# verdad hubo un rebase/force-push que lo descartó.
|
||||||
- name: Verificar promoción segura
|
- name: Verificar promoción segura
|
||||||
id: promotion
|
id: promotion
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -503,7 +514,7 @@ jobs:
|
|||||||
echo "Commit del pipeline: ${CURRENT_SHA}"
|
echo "Commit del pipeline: ${CURRENT_SHA}"
|
||||||
echo "Último commit remoto: ${REMOTE_SHA}"
|
echo "Último commit remoto: ${REMOTE_SHA}"
|
||||||
|
|
||||||
if [ "${CURRENT_SHA}" = "${REMOTE_SHA}" ]; then
|
if git merge-base --is-ancestor "${CURRENT_SHA}" origin/main; then
|
||||||
echo "promote=true" >> "$GITHUB_OUTPUT"
|
echo "promote=true" >> "$GITHUB_OUTPUT"
|
||||||
echo "La imagen puede promocionarse."
|
echo "La imagen puede promocionarse."
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -335,6 +335,10 @@ jobs:
|
|||||||
--insecure-ignore-tlog=true \
|
--insecure-ignore-tlog=true \
|
||||||
"${IMAGE_NAME}@${{ steps.push.outputs.digest }}"
|
"${IMAGE_NAME}@${{ steps.push.outputs.digest }}"
|
||||||
|
|
||||||
|
# merge-base --is-ancestor, no comparación exacta -- ver el
|
||||||
|
# comentario largo en build.yaml sobre por qué (condición de
|
||||||
|
# carrera real con 2+ pipelines compartiendo un commit, visto en
|
||||||
|
# vivo 2026-08-17).
|
||||||
- name: Verificar promoción segura
|
- name: Verificar promoción segura
|
||||||
id: promotion
|
id: promotion
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -346,7 +350,7 @@ jobs:
|
|||||||
CURRENT_SHA="${{ github.sha }}"
|
CURRENT_SHA="${{ github.sha }}"
|
||||||
REMOTE_SHA="$(git rev-parse origin/main)"
|
REMOTE_SHA="$(git rev-parse origin/main)"
|
||||||
|
|
||||||
if [ "${CURRENT_SHA}" = "${REMOTE_SHA}" ]; then
|
if git merge-base --is-ancestor "${CURRENT_SHA}" origin/main; then
|
||||||
echo "promote=true" >> "$GITHUB_OUTPUT"
|
echo "promote=true" >> "$GITHUB_OUTPUT"
|
||||||
else
|
else
|
||||||
echo "promote=false" >> "$GITHUB_OUTPUT"
|
echo "promote=false" >> "$GITHUB_OUTPUT"
|
||||||
|
|||||||
@@ -110,3 +110,63 @@ público correspondiente después del rollout:
|
|||||||
|
|
||||||
Y con el estado del pod nuevo (`kubectl get pods`, sin reinicios,
|
Y con el estado del pod nuevo (`kubectl get pods`, sin reinicios,
|
||||||
`1/1 Ready`) antes de dar cada migración por cerrada.
|
`1/1 Ready`) antes de dar cada migración por cerrada.
|
||||||
|
|
||||||
|
## Actualización (mismo día): 2 bugs más, esta vez en CI, no en K8s
|
||||||
|
|
||||||
|
El primer push real después de migrar las 3 apps (justo el commit que
|
||||||
|
agregó las secciones de arriba a este playbook) expuso dos problemas
|
||||||
|
más — ninguno de los dos en Kubernetes esta vez, los dos en los propios
|
||||||
|
pipelines de Gitea Actions.
|
||||||
|
|
||||||
|
### 4. `MANIFEST_FILE` apuntando a una ruta que ya no existía
|
||||||
|
|
||||||
|
Mover cada `deployment.yaml` suelto a `.../patches/deployment.yaml`
|
||||||
|
(necesario para el patrón base+overlay) rompió en silencio el paso de
|
||||||
|
auto-actualización GitOps de los 3 pipelines (`build.yaml`,
|
||||||
|
`build-medusa.yaml`, `deploy-docs.yaml`) — cada uno tiene su propio
|
||||||
|
`MANIFEST_FILE` hardcodeado como variable de entorno, y los 3 seguían
|
||||||
|
apuntando a las rutas viejas. No se notó hasta el primer build real
|
||||||
|
post-migración: la imagen se construyó, escaneó y firmó bien, pero el
|
||||||
|
último paso falló con `sed: can't read ...: No such file or directory`,
|
||||||
|
dejando una imagen firmada y verificada sin desplegar. Fix: actualizar
|
||||||
|
las 3 rutas de `MANIFEST_FILE`.
|
||||||
|
|
||||||
|
**Para la próxima vez que se mueva un manifiesto:** `grep -rn
|
||||||
|
MANIFEST_FILE .gitea/workflows/` antes de asumir que un `git mv` dentro
|
||||||
|
de `workloads/` es solo un problema del propio manifiesto — los
|
||||||
|
pipelines de CI referencian esas rutas exactas en un archivo aparte.
|
||||||
|
|
||||||
|
### 5. Condición de carrera en el chequeo de "promoción segura"
|
||||||
|
|
||||||
|
El runner de Gitea de este lab corre **un solo job a la vez**
|
||||||
|
(`capacity: 1` en su config). Cuando el fix del punto 4 disparó los 3
|
||||||
|
pipelines a la vez para el mismo commit, se ejecutaron en serie. El
|
||||||
|
chequeo de "promoción segura" de cada uno compara el commit que lo
|
||||||
|
disparó contra el HEAD actual de `main` (`if [ "$CURRENT_SHA" =
|
||||||
|
"$REMOTE_SHA" ]`) para evitar que una corrida vieja pise un manifiesto
|
||||||
|
más nuevo. Problema real: el primer pipeline en terminar (Medusa) dejó
|
||||||
|
su propio commit automático en `main` — para cuando les tocó el turno
|
||||||
|
a Frontend y Docs Portal, `main` ya no coincidía con el commit que los
|
||||||
|
había disparado, así que ambos se saltaron la actualización del
|
||||||
|
manifiesto (`Promoción GitOps: false`) aunque era perfectamente seguro
|
||||||
|
promocionar. Frontend quedó con una imagen nueva construida, escaneada
|
||||||
|
y firmada (`v1.0.119`) pero sin desplegar — el manifiesto seguía en
|
||||||
|
`v1.0.104`.
|
||||||
|
|
||||||
|
Fix aplicado en los 3 workflows: cambiar la comparación exacta de SHA
|
||||||
|
por `git merge-base --is-ancestor "$CURRENT_SHA" origin/main` — permite
|
||||||
|
promocionar mientras el commit disparador siga siendo ancestro de
|
||||||
|
`main` (tolera que otro pipeline haya commiteado en el medio), y solo
|
||||||
|
bloquea si de verdad hubo un rebase/force-push que lo descartó.
|
||||||
|
|
||||||
|
!!! warning "Límite conocido de este fix, aceptado a propósito"
|
||||||
|
`is-ancestor` es más permisivo que la comparación exacta en un
|
||||||
|
caso borde distinto: si 2 commits al **mismo** app quedaran en cola
|
||||||
|
y el más viejo terminara *después* del más nuevo, ahora sí
|
||||||
|
promocionaría igual — pisando la versión más nueva con la más
|
||||||
|
vieja. Con un solo mantenedor en este lab, 2 commits casi
|
||||||
|
simultáneos al mismo app es muy poco probable; se aceptó el
|
||||||
|
trade-off en vez de una solución más compleja (ignorar commits
|
||||||
|
`[skip ci]` del propio bot al calcular "el último commit real").
|
||||||
|
Revisar si esto deja de ser cierto (más de una persona commiteando,
|
||||||
|
o automatización que dispare builds más seguido).
|
||||||
@@ -25,7 +25,7 @@ spec:
|
|||||||
runAsUser: 1001
|
runAsUser: 1001
|
||||||
containers:
|
containers:
|
||||||
- name: app
|
- name: app
|
||||||
image: gitea.cruzcloud.net/devops/ecommerce-frontend:v1.0.104
|
image: gitea.cruzcloud.net/devops/ecommerce-frontend:v1.0.119
|
||||||
env:
|
env:
|
||||||
- name: HEADLESS_PROVIDER
|
- name: HEADLESS_PROVIDER
|
||||||
value: medusa
|
value: medusa
|
||||||
|
|||||||
Reference in new issue
Block a user