fix(deploy): 404 de rétention sur les images OCI index (buildx)
CI / build-and-test (push) Successful in 14m0s
CI / build-and-test (push) Successful in 14m0s
Le push réussissait puis le script sortait en 22 :
curl: (22) The requested URL returned error: 404
Write-Error: ... code d'erreur: 22
Deux causes cumulées, visibles seulement une fois MAX_VERSIONS dépassé.
1. Accept trop restrictif
`docker build` via buildx produit un OCI image index
(application/vnd.oci.image.index.v1+json), pas un manifest v2 plat.
delete_by_tag demandait le digest avec
`Accept: application/vnd.docker.distribution.manifest.v2+json` : le registre
répond 404 — et non 406 — quand l'Accept ne couvre pas le type stocké.
Le HEAD échouait donc sur TOUS les tags, y compris celui venait d'être
poussé. On liste maintenant les quatre media types possibles.
2. La rétention pouvait tuer un déploiement réussi
Sous `set -euo pipefail`, le curl de delete_by_tag n'était protégé par
aucun `|| true` : son code de sortie 22 se propageait et tuait le script,
transformant un push réussi en échec. Le ménage des anciennes versions est
du best-effort et ne doit jamais faire échouer le push.
Symptôme d'origine : la rétention ne s'est jamais déclenchée tant que le
nombre de tags semver est resté <= MAX_VERSIONS (5). Au 7e tag, elle a
commencé à tourner et a fait échouer le script.
Vérifié : deploy-img.ps1 publie 1.0.20, `latest` aligné sur le digest de
l'image locale (sha256:25555d9ee4bf…), rétention purgée sans erreur.
This commit is contained in:
+18
-5
@@ -27,7 +27,14 @@ CURL="curl -fsSL"
|
||||
JQ_BIN="${JQ_BIN:-jq}" # possibilité de surcharger via env
|
||||
|
||||
# Headers pour obtenir le digest (manifest v2)
|
||||
ACCEPT_MANIFEST='application/vnd.docker.distribution.manifest.v2+json'
|
||||
# L'Accept doit lister TOUS les media types possibles : `docker build` via
|
||||
# buildx produit un OCI image index (application/vnd.oci.image.index.v1+json),
|
||||
# pas un manifest v2 plat. Un registre répond 404 — pas 406 — quand l'Accept
|
||||
# ne couvre pas le type stocké, ce qui faisait échouer la rétention.
|
||||
ACCEPT_MANIFEST='application/vnd.oci.image.index.v1+json'
|
||||
ACCEPT_MANIFEST="${ACCEPT_MANIFEST},application/vnd.docker.distribution.manifest.list.v2+json"
|
||||
ACCEPT_MANIFEST="${ACCEPT_MANIFEST},application/vnd.oci.image.manifest.v1+json"
|
||||
ACCEPT_MANIFEST="${ACCEPT_MANIFEST},application/vnd.docker.distribution.manifest.v2+json"
|
||||
|
||||
# Auth du registre. Ordre de priorité :
|
||||
# 1. variables déjà exports (DOCKER_USERNAME / DOCKER_PASSWORD)
|
||||
@@ -235,19 +242,25 @@ delete_by_tag() {
|
||||
# Supprime un manifest par son tag en récupérant le digest via HEAD
|
||||
local tag="$1"
|
||||
local digest
|
||||
# On demande le digest via HEAD + Accept manifest v2
|
||||
digest="$(curl -fsSI ${AUTH_ARGS[@]+"${AUTH_ARGS[@]}"} -H "Accept: ${ACCEPT_MANIFEST}" "http://${REGISTRY}/v2/${IMAGE_NAME}/manifests/${tag}" \
|
||||
# La rétention est du ménage best-effort : elle ne doit JAMAIS faire échouer
|
||||
# un push qui a réussi. D'où les `|| true` (et le `set +e` local) — sans eux,
|
||||
# le moindre curl en erreur (404 sur un tag déjà purgé, registre momentanément
|
||||
# indisponible) faisait sortir le script avec le code curl sous `set -e`.
|
||||
# On demande le digest via HEAD + Accept (index OCI + manifest v2).
|
||||
set +e
|
||||
digest="$(curl -fsSI ${AUTH_ARGS[@]+"${AUTH_ARGS[@]}"} -H "Accept: ${ACCEPT_MANIFEST}" "http://${REGISTRY}/v2/${IMAGE_NAME}/manifests/${tag}" 2>/dev/null \
|
||||
| tr -d '\r' \
|
||||
| awk -F': ' 'tolower($1)=="docker-content-digest"{print $2}' \
|
||||
| tail -n1)"
|
||||
set -e
|
||||
if [[ -z "${digest}" ]]; then
|
||||
warn "Digest introuvable pour ${tag} (manifest v2 absent ?). Skip."
|
||||
warn "Digest introuvable pour ${tag} (manifest absent ?). Skip."
|
||||
return 0
|
||||
fi
|
||||
|
||||
info "Suppression manifest ${tag} (digest: ${digest})…"
|
||||
# La delete API ne renvoie rien en cas de succès (204)
|
||||
if ! curl -fsS ${AUTH_ARGS[@]+"${AUTH_ARGS[@]}"} -X DELETE "http://${REGISTRY}/v2/${IMAGE_NAME}/manifests/${digest}" >/dev/null; then
|
||||
if ! curl -fsS ${AUTH_ARGS[@]+"${AUTH_ARGS[@]}"} -X DELETE "http://${REGISTRY}/v2/${IMAGE_NAME}/manifests/${digest}" >/dev/null 2>&1; then
|
||||
warn "Échec suppression manifest pour ${tag} (digest: ${digest})."
|
||||
fi
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user