Loading search data...

Utiliser des containers docker pour générer des builds multi-environnement

Un pattern devops très souvent utilisé et qui complète la formation Ansible: l’utilisation de Docker.

Lors des builds d’applications ils m’arrivent parfois d’utiliser docker pour lancer plusieurs compilations en parallèle. Mais à chaque fois je cherche comment bien paramétrer le module docker_container pour qu’ils lancent bien les containers et qu'Ansible attendent la fin du traitement pour passer à la suite.

Quel est le besoin ?

J’ai besoin de pouvoir lancer la compilation d’une même application pour différents clients et différents environnement. Chacun de ses cas possèdent son propre paramétrage et sa propre version à compiler.

Dans mon explication je n’utiliserai pas de cas concret mais je vous expose simplement la solution que j’ai retenu. Donc tout est fictif, mais je l’ai déjà mis en oeuvre à plusieurs reprises.

Solution retenue

Je vais utiliser Ansible pour embarquer les paramétrages client et des environnements dans les inventaires. L'image du container doit prendre en entrée des arguments et partager un volume pour y déposer les artefacts.

Construction du container de build Docker

Il faut que ce container accepte en entrée plusieurs qui seront utilisé pour la compilation du programme. Il suffit d’ajouter des ARG comme ceci :

FROM oraclelinux:8
ARG VERSION
ARG CLONE_TOKEN
ENV VOTRE_PARAMETRE=tot
RUN dnf install -y tar git python3 && mkdir /artefact
RUN git clone --branch ${VERSION} https://gitlab+deploy-token-n:${CLONE_TOKEN}@https://gitlab.com/Bob74/rundeck.git
WORKDIR /src

Vous avez remarqué :

  1. je n’indique pas de CMD car je vais le définir dans le playbook Ansible.
  2. derrière le git clone j’utilise en paramètre –branch la version à compiler.
  3. la clé de déploiement est passé en argument car elle sera stocké dans une variable masquée du ci-cd gitlab.
  4. je créé le répertoire /artefact pour y déposer le résultat de la compilation. Ce répertoire sera monté via un volume

Construction de l’inventaire Ansible

Je reprends la structure que je vous ai expliqué dans un précédent billet.

inventories
└── dev
    ├── group_vars
    │   ├── all
    │   │   └── vars.yml
    │   ├── client1
    │   │   └── vars.yml
    │   └── client2
    │       └── vars.yaml
    └── hosts
  • Dans le groupe de variables all je stocke les paramètres communs comme CLONE_TOKEN.
  • Dans les autres groupes les valeurs propres à chaque client par exemple:
    • CLIENT: client1
    • VERSION: v0.0.1
    • PARAM1: toto
  • Dans hosts j’indique les machines cibles d’installation. Pour le développement j’utilise Vagrant pour simuler mon environnement décrit ci-dessous.
[all:children]
client1
client2

[client1]
host1
[client2]
host2

Ecriture du playbook

Le playbook :

---
- name: Build une application
  gather_facts: yes
  # serial: 1

    - name: Build
      docker_image:
        build:
          dockerfile: ./Dockerfile
          path: ./
          nocache: true
          args:
            VERSION: "{{ VERSION }}"
            CLONE_TOKEN: "{{ CLONE_TOKEN }}"
        name: build
        tag: "{{ VERSION }}"
        force_source: true
        source: build
      delegate_to: 127.0.0.1

    - name: Launch compilation
      remote_user: root
      docker_container:
        name: "container{{ ansible_hostname }}"
        image: build:{{ VERSION }}
        command: "/bin/sh -c 'python3 build.py && tar cvfz /ext/${CLIENT}-${VERSION}.tar.gz result'"
        privileged: yes
        recreate: yes
        state: started
        detach: no
        volumes:
          - ./ext:/ext
        env:
          VERSION: "{{ VERSION }}"
          CLIENT: "{{ CLIENT }}"
          PARAM1: "{{ PARAM1 }}"
      delegate_to: 127.0.0.1
      register: docker_container_output
  • J’utilise les modules mis à disposition par la communauté Ansible docker_image et docker_container
  • Pour lancer les commandes en local j’utilise le delegate_to. Docker étant installé sur mon node Ansible.
  • L’étape Build utilise args pour injecter les paramètres pour récupérer le bon repository avec la bonne version.
  • L’étape Launch utilise :
    • image: build:{{ VERSION }} pour indiquer l’image avec la bonne version
    • volumes: le point de montage pour y déposer les artefacts
    • command: la commande de compilation avec la création de l’artefact dans le volume
    • env: les paramètres de compilation
    • register: pour des besoins de debug
    • Les paramètres super important :
      • recreate: yes on détruit une précédente execution
      • state: started on indique bien started et pas juste present sinon la commande n’est pas lancée.
      • detach: no on indique à Ansible d’attendre la fin de l’exécution.
      • privileged: yes on peut en avoir besoin dans certains cas.

Lancement du tout

Très simple une simple commande ansible-playbook et on compile n versions en peu de temps. Attention cela peut être très consommateur de ressources et c’est pour cela que j’ai serial en paramètre du playbook pour limiter le nombre de compilations en parallèle.

Remarquez l’utilisation de l’indication du user vagrant pour lancer la compilation de votre environnement virtualisé avec vagrant. Dans votre Ci Gitlab vous pourrez l’enlever ou le mettre en paramètre.

ansible-playbook -i inventories/dev build.yml -u vagrant

Voila il s’agit ici d’un cas simple mais avec Ansible on peut vite trouver une solution pour gagner du temps sur le déploiement d’une application.

La suite de la formation Ansible dans de prochains billets.


Alimenter un blog comme celui-ci est aussi passionnant que chronophage. En passant votre prochaine commande (n'importe quel autre article) via ce lien, je receverai une petite commission sans que cela ne vous coûte plus cher. Cela ne me permet pas de gagner ma vie, mais de couvrir les frais inhérents au fonctionnement du site. Merci donc à vous!

Mots clés :

devops, ansible, tutorials,

Autres Articles