Retour à l'accueil

DNS Docker dans GitLab CI : correction des notifications MAX

Cas de débogage des notifications MAX depuis GitLab CI : symptômes proto.payload ont masqué le problème DNS dans Docker. Correction via config.toml du runner, modèle de script fonctionnel avec diagnostics.

GitLab CI + MAX : DNS a cassé les notifications de déploiement
Advertisement 728x90

# Problème DNS Docker casse les notifications GitLab CI vers MAX : Diagnostic et correction

Un job GitLab CI censé envoyer une notification à MAX Messenger après un déploiement s’est transformé en cauchemar de débogage d’une semaine. Les requêtes partaient, mais les réponses revenaient avec {"code":"proto.payload","message":"Can't deserialize body"}. Les logs pointaient un souci de corps de requête, on s’est donc concentré sur la construction du payload JSON.

Même après simplification, rien n’y faisait. Les variables d’environnement MAX_BOT_TOKEN et MAX_NOTIFY_CHAT_ID étaient bien définies, et curl était présent dans l’image. Mais les messages n’arrivaient jamais.

Tentatives de payload infructueuses

L’équipe a passé en revue plusieurs itérations :

Google AdInline article slot
  • printf vers fichier : printf '{"text":"%s"}' "$MSG" > /tmp/payload.json; curl ... -d @/tmp/payload.json. Réponse : Can't deserialize body.
  • jq dans Alpine : Passage à alpine:3.20 avec apk add jq. jq -nc --arg t "$MSG" '{text:$t}' > /tmp/payload.json. Même réponse.
  • jq vers variable : PAYLOAD=$(jq ...); curl ... --data "${PAYLOAD}". Désormais Empty request body, et en plus apk add échouait avec le code de sortie 2 à cause de dépôts inaccessibles.
  • Hardcodé : curl ... -d '{"text":"test ok"}'. Encore Empty request body.

Les progrès étaient minimes : le corps de la requête échouait systématiquement à atteindre le serveur.

Test clé : Hôte vs Conteneur

Une comparaison côte à côte a révélé le coupable :

Depuis l’hôte :

Google AdInline article slot
ssh ... "curl -s -X POST 'https://platform-api.max.ru/messages?chat_id=...' -H 'Authorization: ...' -H 'Content-Type: application/json' -d '{"text":"test from server"}'"

HTTP 200, message délivré.

Depuis Docker :

docker run --rm curlimages/curl:8.7.1 curl -s -X POST 'https://platform-api.max.ru/messages?chat_id=...' -H 'Authorization: ...' -d '{"text":"test from docker"}'

code de sortie 6 : Could not resolve host: platform-api.max.ru.

Google AdInline article slot

Diagnostic : Résolution DNS défaillante dans les conteneurs Docker, alors que l’hôte résolvait parfaitement.

Le test avec --dns 8.8.8.8 l’a confirmé : le message est parti instantanément.

Pourquoi le DNS se masque-t-il en erreur JSON

On s’attendait à une erreur DNS classique comme curl exit code 6 sans réponse HTTP. Au lieu de ça, MAX renvoyait du JSON avec proto.payload. Le problème venait de la configuration DNS personnalisée du runner GitLab pour les conteneurs de jobs. Cela provoquait des connexions instables — les corps de requêtes étaient tronqués ou perdus entièrement. MAX interprétait l’entrée vide comme une erreur de désérialisation.

Correction : DNS dans config.toml du runner

Solution : Ajouter des serveurs DNS dans /etc/gitlab-runner/config.toml :

[[runners]]
  ...
  [runners.docker]
    dns = ["8.8.8.8", "8.8.4.4"]

Redémarrage : sudo gitlab-runner restart.

Alternative au niveau du démon Docker dans /etc/docker/daemon.json :

{
  "dns": ["8.8.8.8", "8.8.4.4"]
}

sudo systemctl restart docker.

Après correction, le payload hardcodé a fonctionné du premier coup.

Modèle de script fonctionnel

Script final avec diagnostics et nettoyage des variables :

if [ -z "$MAX_BOT_TOKEN" ] || [ -z "$MAX_NOTIFY_CHAT_ID" ]; then
  echo "WARN: MAX_BOT_TOKEN or MAX_NOTIFY_CHAT_ID not set"
  exit 0
fi

TOKEN="$(printf '%s' "$MAX_BOT_TOKEN" | tr -d '\r\n')"
CHAT_ID="$(printf '%s' "$MAX_NOTIFY_CHAT_ID" | tr -d '\r\n[:space:]')"
BODY_FILE="$(mktemp)"
RESPONSE_FILE="$(mktemp)"

printf '{"text":"%s"}' "${MSG}" > "${BODY_FILE}"

BODY_SIZE="$(wc -c < "${BODY_FILE}" | tr -d '[:space:]')"
echo "DEBUG: CHAT_ID=${CHAT_ID}"
echo "DEBUG: BODY_SIZE=${BODY_SIZE}"
echo "DEBUG: BODY_TEXT=$(cat "${BODY_FILE}")"

CURL_STATUS=0
HTTP_CODE=$(curl -sS --max-time 15 \
  -o "${RESPONSE_FILE}" \
  -w "%{http_code}" \
  -X POST "https://platform-api.max.ru/messages?chat_id=${CHAT_ID}" \
  -H "Authorization: ${TOKEN}" \
  -H "Content-Type: application/json" \
  --data @"${BODY_FILE}") || CURL_STATUS=$?

RESPONSE="$(cat "${RESPONSE_FILE}" 2>/dev/null || true)"
rm -f "${BODY_FILE}" "${RESPONSE_FILE}"

echo "DEBUG: HTTP_CODE=${HTTP_CODE} CURL_STATUS=${CURL_STATUS}"
echo "DEBUG: Response: ${RESPONSE}"

if [ "${CURL_STATUS}" -ne 0 ] || [ "${HTTP_CODE}" != "200" ]; then
  echo "ERROR: Failed to send. Response: ${RESPONSE}"
  exit 1
fi

Format des notifications et extraction des données

Les notifications puisent dans les variables GitLab CI :

  • CI_PROJECT_NAME — projet
  • CI_COMMIT_BRANCH — branche
  • CI_COMMIT_SHORT_SHA — hash du commit
  • CI_COMMIT_TITLE — message du commit (échappé avec sed 's/\/\\/g; s/\"\"/g')
  • CI_COMMIT_AUTHOR — auteur
  • CI_PIPELINE_URL — lien pipeline

Exemple :

✅ Déploiement DEV réussi

📦 Projet : u.clinic
🌍 Environnement : DEV
🌿 Branche : dev
🔖 Version : f7a249d0
💬 Commit : fix(ci): improve MAX notification handling
👤 Auteur : Anton Kurganskii
⏰ Heure (UTC) : 2026-04-08 21:29:07
⏱️ Durée pipeline : 9 min 52 sec

🔗 Pipeline : https://git.tverdasoft.ru/...

✓ Déploiement terminé avec succès

Choix de l’image et alternatives

curlimages/curl:8.7.1 surpasse alpine + jq : pas besoin de réseau pour les paquets, exécution depuis le cache avec pull_policy: if-not-present. Le apk add d’Alpine échouait à cause de dépôts inaccessibles.

Leçons clés

  • Les pannes DNS Docker dans les runners GitLab imitent les erreurs de payload dues à des connexions instables.
  • Testez d’abord : docker run curl ... platform-api.max.ru sur l’hôte runner — code de sortie 6 signale le DNS.
  • Correction : dns = ["8.8.8.8", "8.8.4.4"] dans [runners.docker] de config.toml.
  • Débogage : Loggez BODY_SIZE, HTTP_CODE, réponse complète.
  • Pour les messages de commit : tr -d '\r\n' + échappement sed.

— Editorial Team

Advertisement 728x90

Lire ensuite