ANSIBLE : BUILDER, POUSSER ET DEPLOYER DES CONTENEURS DOCKER

Contexte et Objectifs

La mise à disposition d’applications sous forme de conteneur Docker passe par plusieurs étapes, allant de l’écriture des Dockerfile à la mise à disposition des images Docker sur un registre d’images. En environnement de production, exécuter toutes ces actions manuellement serait source d’erreurs et de perte de temps, d’où l’intérêt d’automatiser toute la chaîne pour gagner en efficacité.
Notre objectif dans ce tutoriel est de vous présenter comment automatiser le déploiement d’une application entièrement conteneurisée, à l’aide d’Ansible. Notre exemple portera sur le jeux battleboat, qui utilise une base de données mysql pour stocker ses data.

Durée de la mise en place : 30 min

Description de la manipulation et des différentes étapes

Prérequis : Il est nécessaire d’avoir des bases solides sur l’environnement Linux, ainsi que sur les technologies Ansible et docker

Pour ce tutoriel, nous utiliserons 3 machines virtuelles hébergées sur Amazon. Nous considérons que la première machine hébergeant Ansible, est notre serveur de management. Elle permettra de manager les deux autres serveurs. L’un de ces serveurs sera notre  serveur de préproduction, et le second notre serveur de production. Chaque serveur sera un docker Standalone, faisant tourner deux conteneurs dockers, à savoir l’application battleboat et sa base de données mysql. Les principales étapes de la manipulation sont les suivantes  :

  1. Connexion au manager ansible et établissement de la communication ssh inter-serveurs
  2. Téléchargement du repos git de l’article depuis le manager :
  3. Customisation de l’inventaire Ansible
  4. Déploiement de l’application
  5. Check des artéfacts buildés (images dockers)
  6. Check du fonctionnement de l’application

Environnement

Hébergement

La stack technique repose sur le Cloud Amazon. Nous avons automatisé le provisionning de cette stack via l’écriture de scripts CloudFormation. Vous les retrouverez dans le repos git de l’article.

Système d’exploitation et caractéristiques des serveurs


HostnameAdresses publiquesTypesEnvironnementsOS
ansibleec2-52-87-163-38.compute-1.amazonaws.comt2.microManagementCentos7.7
productionec2-52-87-163-38.compute-1.amazonaws.comt2.mediumProductionCentos7.7
stagingec2-52-87-163-38.compute-1.amazonaws.comt2.mediumStagingCentos7.7

AMI utilisé pour les 3 serveurs : centos7-minimal-v20190919.0.0 – ami-0083662ba17882949

Middleware et services

  • Registre public Docker : Pour stocker nos artifacts
  • Github/Gitlab : Notre gestionnaire de code source
  • Docker version 19.03.8 : Installé sur les serveurs managé par Ansible (Production et Staging)
  • Ansible version 2.9.6 : Installé sur le serveur de management
  • Mysql version 5.7 : Installé sous forme de conteneur docker sur les serveurs managé

Stack applicative 

  • Golang : langage go de google. L’application battleboat est développée en go et mise à disposition sous forme de Dockerfile
  • Python version 2.7.5 : Nécessaire sur toutes les machines, car Ansible se base sur des appels pythons pour son fonctionnement
  • Git version 1.8.3.1 : Utilisé pour la gestion de notre repos github/gitlab

Il n’est pas question pour nous de faire un cour sur ces outils et de montrer comment les installer. C’est un prérequis dans le cadre de cet article. Si vous avez des difficultés à les installer, veuillez vous référer aux documentations officielles de chacun de ces outils. Dans notre cas, l’installation est automatisée à l’aide de nos manifestes CloudFormation.

Caractéristiques de l’application et sa base de données

L’application battleboat:

  • Code source de l’application : https://github.com/alexandrevilain/fake-backend
  • Nom : battleIDBOOSTER
  • Image docker :  fake-backend
  • Liée au service base de données
  • Un volume pour ses fichiers statiques
  • Disponible sur le port 8181
  • Une politique de restart mise à always
  • Variables d’environnement :
    DATABASE_HOST: dbIDBOOSTER
    DATABASE_PORT: 3306
    DATABASE_USER: battleuser
    DATABASE_PASSWORD: battlepass
    DATABASE_NAME: battleboat

La base de données

  • Nom : dbIDBOOSTER
  • Image Docker :  mysql5.7
  • Volume qui contiendra le  /var/lib/mysql
  • Une politique de restart mise à always
  • Variables d’environnement :
    MYSQL_ROOT_PASSWORD: rootpwdIDBOOSTER
    MYSQL_DATABASE: battleboat
    MYSQL_USER: battleuser
    MYSQL_PASSWORD: battlepass

PS :  Vous pourrez remplacer IDBOOSTER par ce que vous voulez.

Schéma d’architecture

Déploiement

Vérification de la communication ssh entre les serveurs et le manager ansible

Chacun de vos serveurs doit être accessible via le protocole ssh. Nous allons vérifier que le serveur Ansible puisse joindre les deux autres serveurs. Copiez votre clés privées ssh dans  le fichier /home/centos/.ssh/id_rsa. Si le fichier n’existe pas, le créer et restreindre les droits uniquement à l’utilisateur centos en tapant les commandes : chown centos: /home/centos/.ssh/id_rsa && chmod 700 /home/centos/.ssh/id_rsa
Ensuite, depuis le serveur Ansible, se connecter en ssh sur chaque serveur en tapant la commande ssh <serveur_managé> et en validant le warning s’il s’agit d’une première connexion, votre prompt devrait changer :

Exemple sur le serveur de Production:

[centos@ansible ~]$ ssh ec2-3-81-91-213.compute-1.amazonaws.com
The authenticity of host 'ec2-3-81-91-213.compute-1.amazonaws.com (172.31.39.17)' can't be established.
ECDSA key fingerprint is SHA256:BIDksE2jv5wSQiwhhqpVNTAjqUJxUaBVbX1+m1T5xB0.
ECDSA key fingerprint is MD5:0c:26:ce:a9:f5:9d:c3:42:c7:f0:ae:84:db:21:0b:dc.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'ec2-3-81-91-213.compute-1.amazonaws.com,172.31.39.17' (ECDSA) to the list of known hosts.
Last login: Mon Apr 6 19:40:20 2020 from 93.29.38.89
[centos@production~]$

Téléchargement du repos git de l’article

Depuis le serveur ansible, clonez les sources depuis le repo git, puis naviguez dans le dossier eazytraining/article_1_Ansible_and_Docker/

[centos@ansible ~]$ git clone https://github.com/choco1992/eazytraining.git
Cloning into 'eazytraining'…
remote: Enumerating objects: 59, done.
remote: Counting objects: 100% (59/59), done.
remote: Compressing objects: 100% (42/42), done.
remote: Total 59 (delta 13), reused 54 (delta 11), pack-reused 0
Unpacking objects: 100% (59/59), done.
[centos@ansible ~]$

Ce répertoire contient trois sous répertoires et notre fichier de configuration d’ansible (ansible.cfg)

  • CloudFormation : contient le templates de nos serveurs sur Amazon
  • Inventory : Contient notre inventaire ansible
  • Playbooks : Contient notre playbook de déploiement

[centos@ansible ~]$ cd eazytraining/article_1_Ansible_and_Docker/
[centos@ansible article_1_Ansible_and_Docker]$ ls -l
total 4
-rw-rw-r--. 1 centos centos 191 Apr 6 19:51 ansible.cfg
drwxrwxr-x. 2 centos centos 55 Apr 6 19:51 CloudFormation
drwxrwxr-x. 3 centos centos 37 Apr 6 19:51 inventory
drwxrwxr-x. 3 centos centos 48 Apr 6 19:51 playbooks
[centos@ansible article_1_Ansible_and_Docker]$

Customisation de l’inventaire Ansible

Il faudrait remplacer les variables {SERVEUR_DE_STAGING} et {SERVEUR_DE_PRODUCTION} par les noms ou ip publiques de vos serveurs..
Dans notre cas, ec2-3-81-91-213.compute-1.amazonaws.com et ec2-3-87-37-125.compute-1.amazonaws.com , pour respectivement les serveurs de production et de staging. Cette configuration se fait en éditant (avec votre éditeur préféré) le fichier d’inventaires inventory/hosts. Cela permettra au manager ansible de pouvoir gérer vos serveurs

[centos@ansible article_1_Ansible_and_Docker]$ cat inventory/hosts
[STAGING]
{SERVEUR_DE_STAGING} # remplacer par votre serveurs
[PROD]
{SERVEUR_DE_PRODUCTION} # remplacer par votre serveurs
[centos@ansible article_1_Ansible_and_Docker]$

Par soucis de simplicité et pour ne pas faire un cour sur Ansible, toutes les variables et caractéristiques de l’application sont renseignées dans un seul fichier de variables (inventory/group_vars/all) , sans distinction de la production et de la staging. 3 Principales sections sont à prendre en compte :

  • Variables de l’application : Contenant les variables liées à l’application
  • Variables de la base de données : Contenant les variables liées à la base de données
  • Variables de d’authentification au dockerhub : Elles sont cryptées via ansible_vault, et contiennent les variables pour se connecter au registre publique de Docker, car l’architecture utilise ce registre pour stocker les images buildées.

Ci dessous le contenu du fichier de variables, il faudrait l’adapter à votre environnement.
[centos@ansible article_1_Ansible_and_Docker]$ cat inventory/group_vars/all
ansible_user: "centos"
home: "/home/centos"
project_name: "battleboat"

#### Variables de l'application ####
MYSQL_ROOT_PASSWORD: "rootpwdCHOCO"
MYSQL_DATABASE: "battleboat"
MYSQL_USER: "battleuser"
MYSQL_PASSWORD: "battlepass"
fake_backend_git_url: "https://github.com/alexandrevilain/fake-backend.git"
fake_backend_image_tag: "1.0"
battleboat_network: "battleboat"
fake_backend_container_name: "battleboatCHOCO"
fake_backend_container_hostname: "battleboatCHOCO"
battleboat_port: "8181"

#### riables de la base de données ####
DATABASE_HOST: "dbCHOCO"
DATABASE_NAME: "battleboat"
DATABASE_USER: "battleuser"
DATABASE_PASSWORD: "battlepass"
DATABASE_PORT: "3306"
database_mysql_container_name: "dbCHOCO"
database_mysql_container_hostname: "dbCHOCO"
database_image: "mysql:5.7"

#### Variables de d'authentification au dockerhub (Elles sont cryptées via ansible_vault) ####
docker_hub_login: !vault |
$ANSIBLE_VAULT;1.1;AES256
37323465303065643834383630653765386430656333663035363537313161613630613833623362
3963633064326238656466643766343661323966353730350a353438303763303938343536633334
64313432323834643137353731343164303131363864396666636266333265613039313563383061
6532303637396233390a353637303338346136316631333261613766336665623263646265346134
3863
docker_hub_email: !vault |
$ANSIBLE_VAULT;1.1;AES256
61633063323234646539333230663836373965656361303230393339303334313534373830623039
3264303230333638346462613964666638646466363666660a653738383163333238646264316664
39373862343263653137646164323264356664346262346131396639653765323238373334396438
3263313835326464620a383461343137343539363062303036626664313065323365316637623264
39626239363765616264343939313239356234376665323931303565613535643436
docker_hub_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
65396337316339623564323064333532363333323062366332623966336237343663323738383730
6166316338353035643661633735336466393862626338630a336334663235336134313936316430
37663535326664653964646138626138653831306337396565393536613737656638333733326633
6463343832303162340a383436313539623636313432366461636338626633613237636564396630
3634

Playbook de déploiement

Le playbook de déploiement est le fichier https://github.com/choco1992/eazytraining/blob/master/article_1_Ansible_and_Docker/playbooks/deploy_battleboat.yml. L’avantage qu’offre le code ansible est que le code est très explicite. En lui même il peut faire office de documentation. Je me suis tout de même arrangé à vous mettre quelques commentaires explicatifs.

Déploiement de l’application

Lancez le playbook, le mot de passe d’encryption vous sera demandé avant son exécution :

PS : Pour crypter vos variables via ansible-vault, je vous recommande de lire la documentation officielle : https://docs.ansible.com/ansible/latest/user_guide/vault.html#use-encrypt-string-to-create-encrypted-variables-to-embed-in-yaml

[centos@ansible article_1_Ansible_and_Docker]$ ansible-playbook playbooks/deploy_battleboat.yml --ask-vault-pass
Vault password:

A la fin de son exécution, le playbook devrait vous générer un rapport similaire à la capture ci dessous. Si vous avez des erreurs, veuillez revérifier toutes les étapes précédentes et relancez le playbook .

Rapport d’exécution du playbook

A ce stade, l’infrastructure est toute prête, les images docker sont présentes sur le dockerhub, les serveurs de production et de staging font tourner l’application et sa base de données.

Check des artéfacts buildés (images dockers)

Vérifiez les images docker sur chaque serveur avec la commande :
[centos@ansible article_1_Ansible_and_Docker]$ ansible all -a "docker images"
Vous devriez avoir la sortie suivante :

En visitant votre registre docker (https://hub.docker.com/ dans mon cas, compte choco1992), vous devriez voir apparaître la nouvelle image nouvellement buildée:

Check du fonctionnement de l’application

Depuis le serveur Ansible, la commande ansible all -a “docker ps -a ” vous renseigne les conteneurs présents sur les serveurs, ainsi que le binding de port et les images de base.

Conteneurs running sur les deux serveurs

Afin de valider le fonctionnement de l’application, rendez-vous dans votre navigateur préféré. Vous devrez attaquer vos serveurs sur le port 8181. Rassurez-vous des ouvertures de ports su vous êtes derrière un proxy. Dans mon cas, http://ec2-3-81-91-213.compute-1.amazonaws.com:8181/ et http://ec2-3-87-37-125.compute-1.amazonaws.com:8181/ pour respectivement la production et la staging.

L’application en Production

En résumé

Nous voici au terme de cette manipulation. Il était question pour nous de vous démontrer la richesse de l’infrastructure as code dans la conteneurisation d’application. Nous avons pu déployer l’application battleboat et sa base de données à l’aide de l’outil ansible. Ce procédé rend notre copiable et transférable, nous pouvons la dupliquer autant de fois que nous le souhaitons.
Espérant que l’article vous a plus, rendez pour d’autres tickets !

Références

Ulrich MONJI
Consultant IT
linkedin.com/in/ulrich-monji-41bb99b4 

5 réflexions sur “ANSIBLE : BUILDER, POUSSER ET DEPLOYER DES CONTENEURS DOCKER”

  1. Avatar

    Bonjour Ulrich,
    je viens de suivre ce tuto cependant je rencontre le problème suivant

    La connexion ssh depuis le serveur ansible vers les 2 serveurs de stage et de prod ne fonctionne que si je fourni la clé (ex : ssh -i “AWS.pem” centos@ec2-52-90-202-235.compute-1.amazonaws.com) et non en direct comme tu l’indiques dans le tuto ([centos@ansible ~]$ ssh ec2-3-81-91-213.compute-1.amazonaws.com).
    Du coup lors de l’éxécution du playbook, le déploiement ne fonctionne pas

    Friday 26 June 2020 14:44:55 +0000 (0:00:00.045) 0:00:00.045 ***********
    fatal: [ec2-54-198-130-70.compute-1.amazonaws.com]: UNREACHABLE! => {“changed”: false, “msg”: “Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).”, “unreachable”: true}

    PLAY RECAP ***************************************************************************************************************************************************************
    ec2-54-198-130-70.compute-1.amazonaws.com : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0

    Friday 26 June 2020 14:44:55 +0000 (0:00:00.106) 0:00:00.151 ***********
    ===============================================================================

    Ai-je loupé quelque chose ?

    1. Avatar
      Dirane Willy TAFEN

      @thibaud où se trouve ta clé ? car ansible a besoin de cette dernière, trois cas de figure:
      1- soit tu copie ta clé privée sur ta vm ansible et tu la met dans ~/.ssh/id_rsa, id_rsa étant le le nom que tu vas lui donner, et ainsi ansible l’utilisera
      2- soit alors tu modifies l’ansible.cfg ou les variable ansible afin de donner le chemin vers la clé privée (clé privée que tu devras avoir sur ta vm ansible)
      3- soit dans ta commande ansible-playbook tu utilises le paramètre –private-key pour spécifier la clé privée

      quelques pistes : https://www.cyberciti.biz/faq/define-ssh-key-per-host-using-ansible_ssh_private_key_file/

      1. Avatar

        Merci dirane, je viens de tester la solution 1, cela fonctionne bien !
        Du coup il serait peut-être intéressant de modifier le tuto en rajoutant ces informations.

  2. Avatar

    Bonjour @thibaud,
    Merci de ton retour, ça permets d’améliorer la doc 🙂

    Comme dit @Dirane,, tu dispose de ces solutions qu’il te propose.
    La plus simple pour toi (et c’est ce que j’avais fait), c’est la première.
    En le faisant, rassure toi que tu sois le seul à avoir accès en lecture/écriture à ta clés en tapant la commande suivante :
    chown centos: ~/.ssh/id_rsa && chmod 700 ~/.ssh/id_rsa

    N’hésite pas à me dire si c’est ok pour toi, comme ça je mettrais la DOC à jour
    Ulrich

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *