Build Push Deploy

Sous ce titre, l’idée est de présenter un workflow de construction d’une image docker, sa publication et son déploiement depuis un simple git push grâce à Drone. Pour cela je vais utiliser un vieux projet en php toujours en vie : phpsysinfo

Contexte

Lorsqu’on souhaite utiliser Docker plusieurs étapes sont nécessaires avant d’arriver à la publication finale.

  1. Ecrire un Dockerfile
  2. Construire une image
  3. La publier sur un registre (le plus souvent le hub docker)
  4. Ecrire un docker-compose pour l’instancier sur son serveur.

L’étape 1 peut être longue selon la complexité du projet, mais comme ce n’est pas le sujet ici j’ai pris un projet basique.
L’étape 2 peut être faite sur un PC/VM Linux sauf si l’architure cible n’est pas du x86. Dans ce cas il faudra construire l’image sur un raspberry PI (si la cible est de l’ARMv7) ou un serveur ARM64v8 chez scaleway.
L’étape 3 devra être faite depuis la machine où l’on a construit l’image.
L’étape 4 sur son serveur Docker ou un des managers du Docker swarm.

Faire tout ceci sur le serveur cible n’est pas vraiment dans les canons du devops. L’objectif est de présenter une solution qui permettra d’écrire le Dockerfile et le docker-compose sur son PC personnel, commiter les modifications et les pusher vers un serveur git qui déclenchera un webhook vers Drone qui exécutera toutes les étapes.

Action

La première tâche est de créer un dépôt git (gitea, github, gitlab, …) et d’avoir configuré une application vers son serveur drone avec les tokens qui vont bien. Mon dépôt se trouve ici : dockerfile_phpsysinfo, on y trouve 3 fichiers nécessaire au workflow :

1. Dockerfile.arm64v8 : les étapes de construction de l’image

FROM arm64v8/php:7.3.5-apache
MAINTAINER Frederic Logier <fredix@protonmail.com>

ENV PHPSYSINFO_VERSION 3.2.10

RUN curl -SL https://github.com/phpsysinfo/phpsysinfo/archive/v${PHPSYSINFO_VERSION}.tar.gz | tar -xzC /tmp/ \
&& mv /tmp/phpsysinfo-${PHPSYSINFO_VERSION}/* /var/www/html/ \
	&& rm -rf /tmp/phpsysinfo-${PHPSYSINFO_VERSION}
RUN cat /var/www/html/phpsysinfo.ini.new | sed 's/^LOAD_BAR=false/LOAD_BAR=true/' >/var/www/html/phpsysinfo.ini

La première ligne permet d’avoir une image avec Apache/PHP clé en main. La 3ème crée une variable qui sera utilisée ensuite pour télécharger le tarball de la version (pour l’exemple l’avant dernière). L’image lance automatiquement Apache qui va lire son répertoire par defaut /var/www/html dans lequel on y a décompressé le projet. Par défaut Apache écoutera sur le port 80 dans le conteneur. Si j’avais utilisé une image basique Debian/Ubuntu j’aurais du installer Apache et PHP dans le conteneur puis lancer Apache.

2. phpsysinfo-arm64v8.yml : le fichier docker-compose

version: "3.7"
services:
  phpsysinfo:
    image: fredix/arm64v8-phpsysinfo:3.2.10
    restart: always
    ports:
      - 80
    networks:
      - traefik-net
    deploy:
      replicas: 2
      placement:
        constraints:
#          - node.labels.location == cloud-arm64
          - node.role == manager
      labels:
        - "traefik.port=80"
        - "traefik.docker.network=traefik-net"
        - "traefik.frontend.rule=Host:phpsysinfo.fredix.xyz"

networks:
  traefik-net:
    external: true

3. .drone.yml : toutes les actions que drone devra effectuer à ma place

Une des forces de drone est de proposer des plugins qui étendent ses possibilités (la liste complète se trouve sur le marketplace). J’utilise les plugins :

  • docker afin qu’il construise l’image et la pousse sur le hub.docker.com.
  • drone-scp (que j’ai buildé et publié pour arm64v8) qui me permet d’envoyer le fichier docker-compose sur le serveur docker.
  • drone-ssh (que j’ai buildé et publié pour arm64v8) qui va se connecter sur le serveur docker et lancer la commande pour mettre à jour l’image de phpsysinfo à partir du fichier docker-compose phpsysinfo-arm64v8.yml.
  • telegram qui va me notifier du résultat du déploiement.

    kind: pipeline
    name: default
    
    platform:
    os: linux
    arch: arm64
    
    clone:
    depth: 50
    
    steps:
    #- name: clone
    #  image: plugins/git:linux-arm64
    
    - name: docker
    image: plugins/docker:linux-arm64
    settings:
    repo: fredix/arm64v8-phpsysinfo
    tags: 3.2.10
    dockerfile: Dockerfile.arm64v8
    username:
      from_secret: docker_username
    password:
      from_secret: docker_password
    
    - name:  transfer-compose
    image: fredix/arm64v8-alpine-drone-scp
    volumes:
    - name: key
    path: /root/ssh/drone.key
    settings:
    host: 192.168.254.1
    username: drone
    key_path: /root/ssh/drone.key
    target: /tmp/phpsysinfo/
    source: phpsysinfo-arm64v8.yml
    rm: true
    when:
    branch: [master]
    event: [push]
    
    - name: ssh
    image: fredix/arm64v8-alpine-drone-ssh
    volumes:
    - name: key
    path: /root/ssh/drone.key
    settings:
    host: 192.168.254.1
    port: 22
    username: drone
    key_path: /root/ssh/drone.key
    script:
      - "sudo docker stack deploy --compose-file=/tmp/phpsysinfo/phpsysinfo-arm64v8.yml phpsysinfo-arm64"
    when:
    status: success
    
    - name: telegram
    image: fredix/arm64v8-alpine-drone-telegram
    settings:
    token:
      from_secret: plugin_token
    to:
      from_secret: plugin_to
    message: >
      {{#success build.status}}
        build {{build.number}} succeeded on {{repo.name}}. Good job {{build.author}}  {{build.link}}
      {{else}}
        build {{build.number}} failed on {{repo.name}}. Fix me please {{build.author}}  {{build.link}}
      {{/success}}
    when:
    status: [ success, failure ]
    
    volumes:
    - name: key
    host:
    path: /docker_volumes/drone_agent/drone.key
    

Avant de pusher ces fichiers vers le serveur git, il faudra côté drone cliquer sur Sync pour voir ce nouveau dépôt. Ensuite l’activer puis le paramétrer en cochant Trusted (nécessaire pour le plugin drone-ssh) et créer les 4 secrets : docker_username docker_password (pour que drone puisse publier sur le hub docker), plugin_to plugin_token (pour que drone puis me notifier sur télégram via un bot, voir l’article telegram-plugin-drone)

dockerfile_phpsysinfo_1.png

Le dépôt est prêt, il suffit de commit et de pusher. Drone a créé le build 5 du pipeline visible ici : https://drone.fredix.xyz/fredix/dockerfile_phpsysinfo/5

dockerfile_phpsysinfo2.png

J’ai bien reçu la notification telegram :

dockerfile_phpsysinfo_5.png

L’image docker a bien été publié : https://hub.docker.com/r/fredix/arm64v8-phpsysinfo/tags

dockerfile_phpsysinfo_3.png

Et le site accessible ici : https://phpsysinfo.fredix.xyz/index.php?disp=bootstrap

dockerfile_phpsysinfo_4.png

Maintenant passons à la dernière version 3.3.0. Pour cela on modifie les 3 fichiers :

  1. Dockerfile.arm64v8 : ENV PHPSYSINFO_VERSION 3.3.0
  2. .drone.yml : tags: 3.3.0
  3. phpsysinfo-arm64v8.yml : image: fredix/arm64v8-phpsysinfo:3.3.0

On commit, push.

pipeline 6 créé : https://drone.fredix.xyz/fredix/dockerfile_phpsysinfo/6

image docker publiée

dockerfile_phpsysinfo_6.png

La nouvelle version est déployée

dockerfile_phpsysinfo_7.png

A noter que la directive replicas: 2 dans le fichier phpsysinfo-arm64v8.yml lance 2 instances de l’image ce qui empèche une interruption de service pendant la mise à jour.

Un exemple de configuration : using-drone-ci-to-build-a-jekyll-site-and-deploy-to-docker-swarm, mais le .drone.yml devra être mise à jour avec le nouveau format de drone.