Files
Imago/docker/deploy-img.sh
T
bruno a4a38cda14
CI / Lint & Format (push) Failing after 8s
CI / Tests (push) Has been skipped
CI / Security Scan (push) Failing after 9s
CI / Docker Build (push) Has been skipped
Update registry hostname to docker-registry.dev.home:5000
2026-06-22 20:20:34 -04:00

181 lines
5.5 KiB
Bash

#!/usr/bin/env bash
# Script: deploy-img.sh
# Description: Pousse l'image Docker Imago vers le registre HTTP local,
# gère le versioning semver et la rétention.
# Adapté de: homelab-automation-api/docker/deploy-img.sh
set -euo pipefail
#####################################
# CONFIG #
#####################################
IMAGE_NAME="imago-backend"
REGISTRY_HOST="docker-registry.dev.home"
REGISTRY_PORT="5000"
MAX_VERSIONS=5
LOCAL_TAG="latest"
PUSH_LATEST="yes"
#####################################
# DÉDUCTIONS #
#####################################
REGISTRY="${REGISTRY_HOST}:${REGISTRY_PORT}"
REMOTE_REPO="${REGISTRY}/${IMAGE_NAME}"
LOCAL_IMAGE="${IMAGE_NAME}:${LOCAL_TAG}"
TEMP_DIR="/tmp/imago-deploy-$(date +%s)"
CURL="curl -fsSL"
JQ_BIN="${JQ_BIN:-jq}"
ACCEPT_MANIFEST='application/vnd.docker.distribution.manifest.v2+json'
#####################################
# UTILITAIRES #
#####################################
info() { echo -e "\033[1;34m[INFO]\033[0m $*"; }
warn() { echo -e "\033[1;33m[AVERT]\033[0m $*"; }
error() { echo -e "\033[1;31m[ERREUR]\033[0m $*" >&2; }
success() { echo -e "\033[1;32m[SUCCÈS]\033[0m $*"; }
cleanup() {
set +e
[[ -d "$TEMP_DIR" ]] && rm -rf "$TEMP_DIR"
}
trap cleanup EXIT
require_cmd() {
command -v "$1" >/dev/null 2>&1 || { error "Commande requise manquante: $1"; exit 1; }
}
#####################################
# PRÉ-VÉRIFICATIONS #
#####################################
require_cmd docker
require_cmd curl
require_cmd sed
require_cmd grep
require_cmd awk
require_cmd sort
info "Vérification de l'image locale '${LOCAL_IMAGE}'…"
if ! docker image inspect "${LOCAL_IMAGE}" >/dev/null 2>&1; then
error "L'image locale ${LOCAL_IMAGE} n'existe pas. Lance build-img.ps1 d'abord."
exit 1
fi
info "Vérification du registre (http://${REGISTRY}/v2/)…"
if ! ${CURL} "http://${REGISTRY}/v2/" >/dev/null 2>&1; then
error "Registre injoignable à http://${REGISTRY}/v2/"
exit 1
fi
mkdir -p "${TEMP_DIR}"
#####################################
# RÉCUPÉRATION DES TAGS #
#####################################
get_all_tags() {
local tags_json
if ! tags_json="$(${CURL} "http://${REGISTRY}/v2/${IMAGE_NAME}/tags/list" 2>/dev/null)"; then
return 0
fi
if command -v "${JQ_BIN}" >/dev/null 2>&1; then
echo "${tags_json}" | ${JQ_BIN} -r '.tags[]?' 2>/dev/null || true
else
echo "${tags_json}" \
| tr -d '\n' \
| sed -n 's/.*"tags":[[]\([^]]*\)[]].*/\1/p' \
| tr -d '"' \
| tr ',' '\n' \
| sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
fi
}
filter_semver() {
grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' || true
}
increment_patch() {
local tag="$1"
local major minor patch
IFS='.' read -r major minor patch <<< "${tag}"
echo "${major}.${minor}.$((patch+1))"
}
info "Récupération des tags existants…"
ALL_TAGS="$(get_all_tags || true)"
SEMVER_TAGS="$(printf '%s\n' "${ALL_TAGS}" | filter_semver | sort -V || true)"
if [[ -z "${SEMVER_TAGS}" ]]; then
NEW_TAG="2.0.0"
else
LATEST_TAG="$(printf '%s\n' "${SEMVER_TAGS}" | tail -n1)"
NEW_TAG="$(increment_patch "${LATEST_TAG}")"
fi
info "Tag retenu : ${NEW_TAG}"
#####################################
# TAG + PUSH #
#####################################
info "Taggage ${LOCAL_IMAGE} → ${REMOTE_REPO}:${NEW_TAG}"
docker tag "${LOCAL_IMAGE}" "${REMOTE_REPO}:${NEW_TAG}"
if [[ "${PUSH_LATEST}" == "yes" ]]; then
info "Taggage ${LOCAL_IMAGE} → ${REMOTE_REPO}:latest"
docker tag "${LOCAL_IMAGE}" "${REMOTE_REPO}:latest"
fi
info "Push ${REMOTE_REPO}:${NEW_TAG}…"
docker push --disable-content-trust "${REMOTE_REPO}:${NEW_TAG}"
if [[ "${PUSH_LATEST}" == "yes" ]]; then
info "Push ${REMOTE_REPO}:latest…"
docker push --disable-content-trust "${REMOTE_REPO}:latest"
fi
#####################################
# RÉTENTION #
#####################################
delete_by_tag() {
local tag="$1"
local digest
digest="$(curl -fsSI -H "Accept: ${ACCEPT_MANIFEST}" "http://${REGISTRY}/v2/${IMAGE_NAME}/manifests/${tag}" \
| tr -d '\r' \
| awk -F': ' 'tolower($1)=="docker-content-digest"{print $2}' \
| tail -n1)"
if [[ -z "${digest}" ]]; then
warn "Digest introuvable pour ${tag}. Skip."
return 0
fi
info "Suppression ${tag} (digest: ${digest})…"
curl -fsS -X DELETE "http://${REGISTRY}/v2/${IMAGE_NAME}/manifests/${digest}" >/dev/null || true
}
ALL_TAGS="$(get_all_tags || true)"
SEMVER_TAGS="$(printf '%s\n' "${ALL_TAGS}" | filter_semver | sort -V || true)"
if [[ -n "${SEMVER_TAGS}" ]]; then
COUNT="$(printf '%s\n' "${SEMVER_TAGS}" | wc -l | awk '{print $1}')"
if (( COUNT > MAX_VERSIONS )); then
TO_DELETE_COUNT=$(( COUNT - MAX_VERSIONS ))
OLDEST="$(printf '%s\n' "${SEMVER_TAGS}" | head -n "${TO_DELETE_COUNT}")"
while IFS= read -r old_tag; do
[[ -z "${old_tag}" ]] && continue
[[ "${old_tag}" == "${NEW_TAG}" ]] && continue
delete_by_tag "${old_tag}"
done <<< "${OLDEST}"
fi
fi
#####################################
# NETTOYAGE LOCAL #
#####################################
info "Nettoyage tags locaux temporaires…"
set +e
docker rmi "${REMOTE_REPO}:${NEW_TAG}" >/dev/null 2>&1
[[ "${PUSH_LATEST}" == "yes" ]] && docker rmi "${REMOTE_REPO}:latest" >/dev/null 2>&1
set -e
success "Déploiement terminé. Version publiée : ${NEW_TAG}"
success "Image disponible : ${REMOTE_REPO}:${NEW_TAG}"
success " : ${REMOTE_REPO}:latest"
exit 0