Déploiement avec Deployer et Gitlab CI

Chez Opéra Energie, la société dans laquelle je travaille, nous développons nos outils en PHP et utilisons Deployer pour le déploiement de nos différents projets. Notre code est hébergé sur une instance Gitlab et c'est tout naturellement que nous utilisons Gitlab CI pour notre intégration continue et le déploiement de nos applications.

Si déployer du code depuis les instances de nos runners Gitlab CI ne posent pas de problème particulier (il est facile d'y déposer une clé SSH autorisant la connexion à nos serveurs de productions et de tests), nous utilisons également les instances des runners Gitlab. Avec ces derniers, il est alors impossible d'y déposer une clé SSH permettant de se connecter à nos serveurs.

Les runners Gitlab que nous utilisons fonctionnent exclusivement sur Docker. Pour le déploiement, nous installons Deployer dans une image php:7-alpine des plus classiques (à laquelle nous avons néanmoins ajouté le nécessaire pour démarrer une connexion SSH, à savoir le paquet openssh-client dans le cas d'une distribution Alpine). Afin de pouvoir s'assurer que nos conteneurs Docker puissent se connecter sur les serveurs qui hébergeront nos applications, nous avons commencé par créer des clés SSH par serveurs (afin de pouvoir avoir une gestion fine d'une éventuelle révocation de ces dernières). Nos clés SSH seront ensuite injectées dans le conteneur qui effectuera le déploiement lors de son démarrage.

Il convient tout d'abord d'ajouter les clés publiques sur chacun des serveurs concernés. Ensuite, dans Gitlab, nous créons des variables Gitlab CI qui contiendront les clés privées que nous avons précédemment générées. Ces dernières sont automatiquement transmises aux runners lors de leurs exécutions.

Une fois Gitlab correctement configuré, il est maintenant possible d'éditer le fichier .gitlab-ci.yml décrivant les actions qui seront réalisées par notre intégration continue. C'est dans ce dernier, que nous allons récupérer le contenu de nos variables d'environnement et ajouter dynamiquement nos clés SSH à l'agent pour ensuite effectuer le déploiement de notre projet :

image: php:7-cli-alpine

stages:
  - deploy

before_script:
    - apk add --update git openssh-client
    - mkdir -p ~/.ssh && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
    - eval $(ssh-agent -s)
    - echo "$SERVER_TEST1_KEY" | ssh-add -
    - echo "$SERVER_TEST2_KEY" | ssh-add -
    - echo "$SERVER_PROD1_KEY" | ssh-add -

deploy:app:
    stage: deploy
    script:
        - curl --show-error --silent https://getcomposer.org/installer | php
        - php composer.phar install
        - vendor/bin/dep deploy
    when: manual
    only:
        - master
    environment:
        name: prod
        url: https://my-app.domain.com

Vous remarquerez que le déploiement s'effectuant dans un conteneur Docker et ne pouvant prévoir le serveur sur lequel la tâche sera lancée, nous désactivons un contrôle de la clé SSH via l'option StrictHostKeyChecking no. Cette action n'est à effectuer qu'au sein d'un conteneur Docker et peut-être potentiellement dangereux, car elle permet à des attaques de type man-in-the-middle de pouvoir être effectué.

Et c'est ainsi, en injectant dynamiquement des clés SSH au sein d'un conteneur Docker, qu'il est possible de déployer une application PHP avec Deployer (au n'importe quel autre outil de déploiement en réalité) via des runners Gitlab.