Les services Docker dans GitHub Actions n'auront plus de secrets pour vous
J'explique plus en détail comment une action est structurée et comment utiliser les services Docker dans un article, mais ici je vais me concentrer davantage sur les services.
Eh oui, la bonne nouvelle, c'est qu'on peut utiliser des conteneurs Docker comme services dans GitHub Actions. 🎉
Comment fait-on ?
C'est très simple, c'est similaire à la définition d'un service dans un docker-compose.yml, mais avec beaucoup moins de paramètres.
On utilise le mot-clé services avec :
- la définition de l'image Docker à utiliser
- la liste des ports du service à exposer
- une liste de variables d'environnement
- une liste de volumes
Tous ces éléments ne sont pas obligatoires, mais c'est bon à savoir.
Concrètement, ça ressemble à ceci, pour un service Postgres :
services: image: postgres env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_BD: postgres ports: - 5432/tcp options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
Exemple réalisé par Chris Patterson et Mike Coutermarsh pour PostgreSQL. Vous pouvez trouver l'exemple complet avec node juste ici.
Il nous faut l'image Docker à lancer, le port à exposer et le nom du service. Il est possible de transmettre des variables d'environnement ou des options Docker, comme dans l'exemple ci-dessus. Les valeurs sensibles peuvent être définies avec une clé secrète.
Exemple complet
Par exemple, on veut créer une action qui lance les tests de notre application Django à chaque événement push.
Le workflow suivant est mis en place :
name: Test Workflow on: push jobs: tests: runs-on: ubuntu-latest services: image: postgres env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_BD: postgres ports: - 5432:5432 options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v1 - name: Set up Python 3.5.7 - uses: actions/setup-python@v1 with: python-version: 3.5.7 - name: Install dependencies run: pip install -r requirements.txt - name: Run tests run: python manage.py test
Ici, le job tests consiste à :
- installer Python 3.5.7 sur l'environnement Ubuntu
- installer les dépendances
- lancer les tests avec la base de données Postgres
Dans cet exemple, il faut quand même surcharger les valeurs du service dans le settings.py de Django pour la connexion à la base de données PostgreSQL, comme ceci :
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'postgres', 'USER': 'postgres', 'HOST': 'localhost', 'PORT': 5432, } }
Si vous avez plusieurs configurations de base de données, vous pouvez utiliser une variable d'environnement os.environ.get('HOST_NAME') ou une configuration conditionnelle avec if os.environ.get('GITHUB_WORKFLOW') par exemple.
Quelques remarques
Il est parfois nécessaire d'attendre un retour sur l'état du service pour établir une connexion. On définit donc un élément qui vérifie l'état de santé du service pour savoir quand il est opérationnel (on parle aussi de health check).
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
Celui-ci est pour Postgres, mais vous en trouverez pour plein d'autres, comme Elasticsearch, MySQL, etc. Si vous n'avez pas de health check disponible, on met en pause l'exécution avec la commande sleep. Oui, ce n'est pas terrible, je vous l'accorde...
Pour relier le service au job du workflow, il faut l'hôte. Si votre workflow s'exécute :
dans la machine virtuelle, ce sera localhost
dans un conteneur, ce sera le nom du service
N'oubliez pas, vous ne pouvez utiliser les services Docker qu'avec une distribution Linux.
Pour le port, voici comment y accéder dans votre ou vos jobs :
${{ job.services.postgres.ports[5432] }}
Dans le premier exemple, un port libre de la machine est attribué aléatoirement au port 5432 et c'est par lui qu'on y accède.
Néanmoins, on peut aussi l'attribuer de manière fixe :
ports: - 5432:5432
Ici, le port 5432 du service est relié au port 5432 de la machine définie dans l'action.
Et voilà, vous êtes prêt·e à utiliser des services dans votre workflow ! 💪