Training DevOps
Hands on

07/01/2019 - 08/01/2019

Qui sommes-nous ?

Gautier DARCHEN <gdarchen@takima.fr>

Jonathan LE BLOAS <jlebloas@takima.fr>

  • eBusiness Information fondée en 2000
  • Séparation en 2009 d’une société partenaire
  • Gérée par François-Pierre CHALOPIN et Olivier DUVOID
  • Changement de nom en mai 2018 pour Takima
  • Incubateur de 2 startups
  • Technologies Java, Javascript, etc.
  • Activités devops
  • Agilité
  • Bagneux (Hauts-de-Seine)

Qu'allons-nous faire durant cette formation ?

  • Voir ce qu'est une application testée
  • Voir comment lancer une BD dans un conteneur
  • Voir comment exécuter les tests dans un autre conteneur
  • Comprendre comment utiliser un gestionnaire de build
  • Configurer toute une pipeline de CI
  • Analyser la qualité d'un code
  • Automatiser le déploiement d'une application
  • [BONUS] : lancer une VM
  • [BONUS] : ajouter des badges sur le README.md

Introduction aux technologies utilisées dans cette formation

  • Apache Maven : outil de gestion et d'automatisation de production des projets Java / JavaEE
  • Produire un artéfact à partir de sources en optimisant les tâches effectuées à ces fins
  • Permettre au développeur d'appréhender un projet plus rapidement

    La documentation dit : 

    Making the build process easy

         Providing a uniform build system

         Providing quality project information

         Providing guidelines for best practices development

         Allowing transparent migration to new features

1/2

  • Paradigme Project Object Model (POM)
  • Fichier central : pom.xml
  • Permet d'indiquer les dépendances, les plugins...
  • Liste des fonctionnalités de Maven ici
  • Lifecycle

  

2/2

Travis CI

  • Logiciel libre d'intégration continue (CI)
  • Permet de compiler, tester, déployer...
  • PaaS (Platform as a Service)
  • Intégration facilitée avec GitHub
  • Configuration de la pipeline en langage YAML

     
  • Outils similaires :
    • Jenkins (à héberger soi-même)
    • Gitlab CI (surtout si on utilise Gitlab)

1/2

Travis CI Lifecycle  

2/2

Analyse de la qualité du code

  • Outil en PaaS ​: SonarCloud
     
  • Version Cloud de SonarQube
     
  • Définition de règles propres au langage (ici Java)
     
  • Définition d'une Quality Gate
    • Contraintes à respecter si on veut que le build passe
    • Lié à des métriques
    • Utilisation de la Quality Gate par défaut pour la formation

Exemple pour notre projet

  • Environnement de virtualisation
  • Concept identique aux VM, mais beaucoup plus léger
  • Un conteneur docker peut porter un service
    • Or, lancer une VM complète pour un seul service, c'est overkill
  • Une VM nécessite la réquisition d'une partie des ressources physiques de la machine hôte (RAM, CPU...)
  • Docker se base sur l'OS de la machine hôte, il n'y a pas nécessité de lui allouer des ressources
  • Sur une machine où on ne pourrait lancer qu'une VM, on pourrait théoriquement lancer des dizaines de conteneurs

Introduction

Introduction

  • Les images s'exécutent dans un simple process et ne prennent donc pas plus de ressources qu'une exécutable, ce qui est bien plus léger qu'une VM
  • Une VM lance complètement un OS "guest" avec des accès virtuels aux ressources de la machine hôte (hypervisor)

Conteneurs

  • Flexibles : tout type d'application peut être conteneurisée
  • Légers : les conteneurs exploitent et partagent le kernel hôte
  • Interchangeables : on peut déployer des mises à jour et des mises à niveau à la volée
  • Portables : on peut les créer localement, les déployer sur le cloud et les exécuter n'importe où
  • Scalables : on peut créer plusieurs conteneurs à partir d'une image
  • Stackables : on peut lancer des conteneurs de différentes images
  • Une image docker est pensée pour faire tourner un seul service (ex. : un serveur web)
  • On peut créer une seconde image pour lancer un autre process (ex. : une base de données)
  • Ces images docker sont cloisonnées et n'ont pas d'intéraction avec la machine hôte
  • Une image docker, c'est un ensemble d'instructions (écrites dans un Dockerfile) permettant de construire l'environnement cible
  • Une image docker peut alors être build puis run
  • Une instance d'une image Docker est appelée un container

Vocabulaire

Exemple d'image docker

FROM ubuntu:15.04
COPY . /app
RUN make /app
CMD python /app/app.py
Dockerfile
  1. Utilise une image de base : Ubuntu (image taguée 15.04)
  2. Copie le contenu du répertoire courant dans le /app du conteneur
  3. Construis l'application avec la commande "make"
  4. Spécifie la commande à exécuter dans le conteneur

Commandes de base

docker build -t image_test .
  • Construction de l'image
  • Exécution de l'image (pour lancer un container)
     
  • Voir les containers sur la machine (lancés ou stoppés)
     
  • Voir les images installées sur la machine

     
  • Supprimer un conteneur
     
  • Supprimer une image
docker run image_test
docker ps
docker image ls
# ou
docker images
docker rm <CONTAINER_ID>
docker rmi <IMAGE_ID>

Pratique

Créer un repository Git pour l'application

L'application Maven (sources et tests) est hébergée sur un repository Github

 

  1. Rendez-vous sur
    https://github.com/takima-training/sample-application-students
  2. Connectez-vous
  3. Forkez le projet pour en créer votre propre copie :


     
  4. Clonez votre fork du projet :
# via SSH
$ git clone git@github.com:<login-github>/sample-application-students.git

# ou via https
$ git clone https://github.com/<login-github>/sample-application-students.git

Configuration Maven
(sur les postes INSA)

export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-amd64

# Run Unit Tests
export MAVEN_OPTS="-Dhttp.proxyHost=proxy.insa-rouen.fr -Dhttp.proxyPort=3128 -Dhttps.proxyHost=proxy.insa-rouen.fr -Dhttps.proxyPort=3128"
<settings>
  <localRepository>/tmp/maven2</localRepository> 
  <proxies>
   <proxy>
      <active>true</active>
      <protocol>http</protocol>
      <host>proxy.insa-rouen.fr</host>
      <port>3128</port>
    </proxy>
  </proxies>
</settings>

Configuration du proxy et localRepository

Avec le wrapper (évite d'avoir à installer mvn en local)

~/.m2/settings.xml

Lancement des tests unitaires

# Run Unit Tests

# Avec le wrapper
./mvnw clean test


# Sans si mvn est déjà installé
mvn clean test

Lancement d'une VM pour utiliser Docker
(uniquement les postes INSA)

  • Créer et lancer la machine virtuelle




     
  • Charger les variables d'environnement de la docker-machine
     
  • Testez votre environnement docker
docker-machine create \
    --engine-env HTTP_PROXY=http://proxy.insa-rouen.fr:3128 \
    --engine-env HTTPS_PROXY=http://proxy.insa-rouen.fr:3128 \
    --engine-env NO_PROXY=registry.insa-rouen.fr \
    -d virtualbox \
    --virtualbox-boot2docker-url file:///opt/iso/boot2docker.iso \
    --virtualbox-cpu-count 2 \
    --virtualbox-hostonly-cidr 10.0.0.1/24 \
    default
eval $(docker-machine env default)
docker version

Développement en local

  • Pull l'image Docker de la base de données
docker pull takimatraining/devops-training-db
  • Lancer les tests en local (unitaires/intégration)
mvn verify \
    -Dspring.datasource.url=jdbc:mysql://10.0.0.100:3306/SchoolOrganisation
  • Lancer l'application en local
java -jar ./target/*.jar \
    --spring.datasource.url=jdbc:mysql://10.0.0.100:3306/SchoolOrganisation
  • Lancer l'image Docker de la base de données
docker run -d -p 3306:3306 takimatraining/devops-training-db

Détail de l'API

  • Students
    • Get by ID
    • Delete by ID
    • Save new student
    • Update existing student
  • Departments
    • Get students in a department by ID
    • Get department by name
    • Get number of students in a department by name

Documentation ici

Objectifs de la pipeline de CI

Test

Quality

Registry

Deploy

Automatiser les tests unitaires et d'intégration

Analyse de la qualité du code

Hébergement de l'application conteneurisée sur un registry

Déploiement de l'application en production

Binding GitHub / Travis CI

  1. Connectez vous à Travis CI avec vos identifiants GitHub


  2. Autorisez Travis CI à accéder à vos repositories GitHub

  3. Choisir le repository du projet pour permettre à Travis CI d'y accéder

Création de la pipeline

GitHub

Hook on commit

Travis CI

  • A la racine du projet, créer un fichier ".travis.yml"
  • Configuration du langage et du JDK
language: java
jdk: oraclejdk8
.travis.yml

Avant tout, lancer la BD

Travis CI

takimatraining/devops-training-db

Pull l'image de la BD

Lancement de la BD en tâche de fond

Docker Hub

takimatraining/devops-training-db
# Define the services to use
services:
  - docker

before_install:
  - sudo service mysql stop
  - docker pull takimatraining/devops-training-db
  - docker run -d -p 127.0.0.1:3306:3306 takimatraining/devops-training-db
.travis.yml

Lancement des tests

  • Corps de votre pipeline : section script
  • Lancement des tests
    • Maven build lifecycle
# Run Unit Test and Integration Tests
script:
  - mvn verify
.travis.yml

Lancer votre premier build

# Create your branch
$ git checkout -b ci_config

# Add the pipeline script to git
$ git add .travis.yml

# Commit
$ git commit -m "ci: first version of the pipeline to automate unit and integration tests"

# Push
$ git push --set-upstream origin ci_config

Rendez-vous sur https://travis-ci.org/ dans la page de votre projet et vérifiez que le build se fait sans erreur

Optimisation

  • Maven télécharge beaucoup de dépendances et les stocke dans ~/.m2/repository

  • A chaque nouveau build, Travis CI perd par défaut le contexte
    • L'environnement est donc complètement nouveau
  • Pour éviter de retélécharger les dépendances à chaque fois, on peut utiliser du cache
# Cache the .m2 folder to prevent redownloading dependencies on each build
cache:
  directories:
  - "$HOME/.m2/repository"
.travis.yml

Avancez au maximum
(fin demain après-midi)

Configuration de SonarCloud 1/2

  • Accéder à SonarCloud

  • Aller dans My Account > Security

  • Générer un nouveau token et le copier précieusement

  • Chiffrer ce token :


     

  • Ajouter ce token sécurisé à votre .travis.yml en variable d'environnement

     

# travis encrypt should be installed
# else : 
# $ gem install travis
$ travis encrypt SONAR_TOKEN=<TOKEN>
# Environment variables are strings (double quotes)
# Example:
# - secure: "DpR1th9rZvLMX0......"
env:
  global:
    - secure: <ENCRYPTED_TOKEN>
.travis.yml

Configuration de SonarCloud 2/2

  • Modifiez votre script pour rajouter l'analyse SonarCloud à la pipeline





     
  • Testez votre configuration en faisant un nouveau commit et en consultant SonarCloud en vous rendant sur la page du projet
# The pipe (|) is useful to create multiline scripts
script:
  - |
    mvn clean install sonar:sonar \
    -Dsonar.projectKey=<SONAR_PROJECT_KEY> \
    -Dsonar.organization=<SONAR_ORGANISATION_KEY> \
    -Dsonar.host.url=https://sonarcloud.io \
    -Dsonar.login=$SONAR_TOKEN
.travis.yml

Utilisation de SonarCloud

  • Allez consulter la dette technique
  • Déclarez l'erreur en tant que faux positif
    • Règle déclenchée malgré la conformité du code

Configuration de SonarCloud
[FACULTATIF]

Pour ceux qui sont en avance, essayez de configurer une Quality Gate avec 95% de couverture de test, puis commentez un test pour vérifier que votre build est bien en échec

Notifications en cas d'échec

  • Réception d'une notification en cas d'échec du build

  • On peut configurer des notifications vers une multitude de plateformes :

    • Mail

    • Slack

    • ...

  • On veut ici qu'un mail soit envoyé à la personne qui vient de commit en cas d'échec du build

# Send an email to the commiter if the pipeline failed at some point
notifications:
  email:
    on_failure: always
.travis.yml

Conteneurisation

  • Dockerfile à la racine du projet
FROM openjdk:8-jre

COPY target/*.jar /app.jar

EXPOSE 8080

CMD ["java", "-jar", "app.jar", "--spring.datasource.url=jdbc:mysql://db:3306/SchoolOrganisation"]
Dockerfile
docker build -t java-app-image .

 

  • Build de l'image

Lancer en local

  • Creation du network

 

  • Lancement du conteneur db

 

  • Lancement du conteneur à partir de l'image buildée

 

  • Votre application tourne en local
docker run --network net -p 80:8080 --name app java-app-image
docker run -d -p 3306:3306 --network net --name db takimatraining/devops-training-db
docker network create net

Pousser l'image sur Docker Hub 1/2

  • La pousser sur un registry : Docker Hub

  • Se connecter à Docker Hub

  • Créer un repository sur Docker Hub

    • exemple : <login>/sample-application

  • Chiffrer votre login et mot de passe Docker Hub
     

$ travis encrypt DOCKER_USER=<docker_user>
$ travis encrypt DOCKER_PASS=<docker_pass>

Pousser l'image sur Docker Hub 2/2

# Build an image containing the .jar and push it to the Docker Hub
script:
...
  # Login to Docker hub
  - docker login -u $DOCKER_USER -p $DOCKER_PASS
  # Tag text according to the branch
  - export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH; fi`
  # Image name
  - export IMAGE_NAME=<login>/sample-application-students
  # Build the image (see Dockerfile) and tag it with the commit ID
  - docker build -t $IMAGE_NAME:$TRAVIS_COMMIT .
  # Retag the image with the previously choosen tag
  - docker tag $IMAGE_NAME:$TRAVIS_COMMIT $IMAGE_NAME:$TAG
  # Push the tagged image to Docker Hub
  - docker push $IMAGE_NAME:$TAG
.travis.yml
  • Ajouter ces credentials chiffrés au .travis.yml


     
  • Configurer la pipeline
env:
  global:
    # [...] other tokens
    - secure: <encrypted Docker Username>
    - secure: <encrypted Docker Password>
.travis.yml

Liste des serveurs

achille-lacoin.takima.io
ali-bellamlihmamou.takima.io
alice-giraud.takima.io
allan-milhomme.takima.io
ana-calin.takima.io
andres-morenosolano.takima.io
antoine-questel.takima.io
arnaud-quillent.takima.io
aurelien-toutain.takima.io
benjamin-peltier.takima.io
corentin-poriel.takima.io
corentin-potron.takima.io
damien-toomey.takima.io
darya-orel.takima.io
emma-bonhomme.takima.io
flavien-cocu.takima.io
flavien-disson.takima.io
francisco-nobrefilho.takima.io
gabriel-alencarmedeiros.takima.io
gauthier-wiemann.takima.io
guillaume-dron.takima.io
haitam-zouhair.takima.io
handi-zhang.takima.io
imane-lafnoune.takima.io
jeanfrancois-robin.takima.io
leopold-masson.takima.io
louis-ulmer.takima.io
manon-ferchaud.takima.io
matthias-sesboue.takima.io
matthieu-pavageau.takima.io
maxime-bourgeois.takima.io
mehdi-abouzaid.takima.io
michel-livney.takima.io
monica-salama.takima.io
nicolas-kempf.takima.io
paul-cadorel.takima.io
pierre-bernard.takima.io
pierrefrancois-giraud.takima.io
quentin-enjalbert.takima.io
quentin-lautridou.takima.io
sean-manzambi.takima.io
tanya-angelova.takima.io
theo-couppey.takima.io
thibault-sauron.takima.io
thibaut-emion.takima.io
thomas-constum.takima.io
thomas-digregorio.takima.io
timothee-guiraud.takima.io
vitor-martinbordini.takima.io
victoria-daura.takima.io
weihao-zhou.takima.io
yannis-pages.takima.io

Gestion de clés ssh

  • Récupération de la clé privée envoyée par mail
  • Enregistrez la (ex :  ~/.ssh/id_rsa_insa_training)
    • Nous utiliserons cette clé uniquement pour provisionnner la machine
  • Générer une clé ssh sans passphrase que travis utilisera pour déployer

 

ssh-keygen -t rsa -b 4096 -C 'build@travis-ci.org' -f ./travis_deploy_rsa

Connexion à votre serveur

  • Connexion SSH :

 

  • Créer le network

 

  • Lancer le conteneur de bd dans le network

 

 

  • Ajouter la clé travis dans les authorized keys du user training à la main ou via ssh-copy-id
ssh -i /path/to/private_key training@<login>.takima.io
docker run --name=db --restart=always --volume mysql-data:/var/lib/mysql \
    --network net -d takimatraining/devops-training-db
sudo docker network create net
  • Chiffrer la clé privée avec Travis (ref et ref)
travis login --org
travis encrypt-file path/to/private/key --add

Déploiement 1/2

  • Ajouter 2 variables d'environnement DEPLOY_USER et SERVER_IP_ADDRESS
  • Chiffrage via client travis ou défini dans l'interface Travis
before_install:
...
# Prepare deploy
  - openssl aes-256-cbc -K $encrypted_xxxxxxx_key -iv $encrypted_xxxxxxxxxxx_iv
    -in travis_deploy_rsa.enc -out /tmp/travis_deploy_rsa -d  # Généré par travis encrypt-file
  - chmod 600 /tmp/travis_deploy_rsa
  - eval "$(ssh-agent -s)"
  - ssh-add /tmp/travis_deploy_rsa
  - echo -e "Host $SERVER_HOST\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config

...

# Deploy updated container over ssh
deploy:
  provider: script
  script: ssh -i /tmp/travis_deploy_rsa $DEPLOY_USER@$SERVER_HOST "sudo docker pull $IMAGE_NAME:$TAG && sudo docker rm -f app || true && sudo docker run -d --network net -p 80:8080 --name app $IMAGE_NAME:$TAG"
  on:
    branch: master
.travis.yml

Déploiement 2/2

Votre application est en prod!

http://<YOUR-hostname>.takima.io/departments/ASI/students

[Bonus] - Badges dans le README.md   1/3

  • Il est courant d'ajouter des "badges" dans le fichier README.md
  • But des badges : indiquer l'état de la pipeline pour le dernier commit
    • Badge de l'état de la CI
    • Badge de l'analyse de la qualité du code
    • etc...

[Bonus] - Badges dans le README.md   2/3

  • Sur Travis CI, cliquer sur le badge : 
  • Sélectionner le langage Markdown et copier le texte généré

[Bonus] - Badges dans le README.md   3/3

  • Ajoutez le au README.md de votre projet
  • Pour le badge de coverage, sur SonarCloud, cliquer sur "Get project badges", puis sélectionner "coverage"
  • Ajouter le lien au README.md en le formattant comme suit : 
[![SonarCloud Coverage](https://sonarcloud...)](https://sonarcloud...)
Made with Slides.com