Skip to main content
CI/CD8 min read

Résolution des erreurs de connexion Docker Compose dans CI/CD

J'ai passé 4 heures à déboguer des erreurs 'Connexion refusée' dans Jenkins. Voici ce que j'ai appris sur le réseau Docker dans les pipelines CI.

Part ofCloud & Infrastructure->
By Jason TeixeiraJanuary 5, 2024
DockerJenkinsCI/CDTroubleshooting
Share:
On this page

Imaginez : votre configuration Docker Compose fonctionne parfaitement sur votre machine locale. Vous poussez vers l'IC, et soudainement tous les tests d'intégration échouent avec Connection refused.

Le conteneur de base de données est « en cours d'exécution ». Le conteneur API est « sain ». Le processus de test démarre. Puis il ne parvient pas à se connecter au service dont il a besoin.

Cet échec semble aléatoire jusqu'à ce que vous vous rappeliez une chose : le réseau Docker local et le réseau Docker de l'IC ne sont pas le même environnement.

La configuration locale vous ment

Sur votre machine, vous pouvez vous connecter à Postgres via localhost:5432.

À l'intérieur d'un réseau Compose, un autre conteneur doit généralement se connecter à postgres:5432, où postgres est le nom du service.

Dans l'IC, l'exécuteur de tests peut être :

  • à l'intérieur du réseau Compose
  • à l'extérieur du réseau Compose sur l'hôte
  • à l'intérieur d'un conteneur de service IC
  • à l'intérieur d'un exécuteur Docker imbriqué

Ces quatre cas utilisent des noms d'hôte différents.

C'est pourquoi une chaîne de connexion peut être « correcte » localement et erronée dans le pipeline.

D'abord, identifiez où s'exécute le processus de test

Avant de modifier les ports, posez une question :

La commande de test s'exécute-t-elle à l'intérieur d'un service Compose ou sur l'hôte IC ?

Si les tests s'exécutent dans Compose :

code panelTXT
DATABASE_URL=postgres://user:pass@postgres:5432/app

Si les tests s'exécutent sur l'hôte IC et que Compose a publié le port :

code panelTXT
DATABASE_URL=postgres://user:pass@127.0.0.1:5432/app

Si les tests s'exécutent dans un conteneur IC séparé, ni l'un ni l'autre ne fonctionnera tant que la mise en réseau des services de la plateforme IC n'est pas configurée.

Décision de mise en réseau ICcompose -> tests
Service ComposeRéseauExécuteur de testsBase de données

Le bon nom d'hôte dépend de l'endroit où se trouve l'exécuteur de tests. Les noms de service fonctionnent à l'intérieur du réseau Compose. Les ports localhost publiés fonctionnent depuis l'hôte.

Ne faites pas confiance à depends_on comme indicateur de disponibilité

depends_on peut contrôler l'ordre de démarrage. Il ne garantit pas que Postgres, Redis ou votre application est prête à accepter des connexions.

La version erronée courante :

code panelYAML
services:
  api:
    depends_on:
      - postgres

Cela signifie seulement que le conteneur postgres démarre avant api. Cela ne signifie pas que les migrations ont été exécutées. Cela ne signifie pas que TCP est prêt. Cela ne signifie pas que la base de données a accepté l'authentification.

Utilisez des health checks ou un script d'attente explicite.

code panelYAML
services:
  postgres:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      timeout: 5s
      retries: 12

  api:
    depends_on:
      postgres:
        condition: service_healthy

Cela ne résout pas tous les problèmes de plateforme IC, mais cela élimine la course la plus courante.

Vérifiez les quatre classes d'échec

Quand je vois Connection refused, je parcours cet ordre.

La vérification TCP est banale mais utile :

code panelBASH
node -e "require('net').connect(5432, process.env.DB_HOST).on('connect', () => { console.log('ok'); process.exit(0) }).on('error', e => { console.error(e.message); process.exit(1) })"

Si cela échoue, votre suite de tests d'application n'est pas encore ce qu'il faut déboguer.

Utilisez différentes chaînes de connexion pour différentes limites

Un modèle propre consiste à rendre la limite explicite :

code panelENV
DATABASE_URL_INTERNAL=postgres://app:app@postgres:5432/app
DATABASE_URL_HOST=postgres://app:app@127.0.0.1:5432/app

Ensuite, votre tâche IC choisit la bonne en fonction de l'endroit où la commande s'exécute.

C'est moins magique que d'essayer de faire fonctionner une seule URL partout.

Gardez les migrations séparées de la disponibilité

Une base de données peut être saine avant que le schéma ne soit prêt.

Si votre application a besoin de migrations, faites-en une étape explicite du pipeline :

code panelBASH
docker compose up -d postgres
docker compose run --rm migrate
docker compose run --rm test

Ou exécutez les tests à l'intérieur d'un service qui attend les deux :

  • santé de la base de données
  • migrations terminées
  • données de seed chargées

Sinon, vous obtenez une classe d'échec pire : des erreurs de test intermittentes qui ressemblent à des bugs d'application mais qui sont en réalité des courses de configuration.

La sortie de débogage que je veux dans chaque échec IC

Ne divulguez pas les secrets. Affichez la forme de l'environnement.

Sortie utile :

  • Services Docker Compose et leur état
  • journaux du conteneur pour la dépendance
  • hôte et port résolus, avec mot de passe masqué
  • noms de réseau
  • état du health check
  • état de la migration

Exemple :

code panelBASH
docker compose ps
docker compose logs --tail=80 postgres
docker network ls

L'objectif est de rendre le prochain échec diagnostiquable en un seul passage.

La leçon pour la production

La douleur de la mise en réseau IC est un aperçu de la douleur de l'intégration en production.

Si vos tests dépendent de l'espoir, vos déploiements aussi probablement. Rendez les limites de service explicites. Ajoutez des health checks. Séparez la disponibilité des migrations. Enregistrez les bonnes informations.

C'est ainsi que vous transformez « ça marche sur ma machine » en quelque chose qu'un pipeline peut prouver.

Reader route

article -> proof -> offer

ReadClusterProofScope

cluster

Cloud & Infrastructure

intent

CI/CD

route

next step

What to do with this

Turn the note into a build path.

If this topic maps to a real business problem, keep reading the cluster, study the academy path, or route the work into a scoped engagement.

Jason Teixeira
Written by
Jason Teixeira
Founder, Sage Ideas Studio · Principal Engineer
livebuild 5d6c8652026-08-05 06:00Z
// solo studio// no analytics resold// every commit human-reviewed