Journal Mettre en place des build automatiques avec jenkins et docker

Posté par . Licence CC by-sa.
Tags :
20
10
fév.
2019

Sommaire

Mettre en place des build automatiques avec jenkins et docker

L'intégration continue, c'est vachement bien, mais parfois, c'est un peu compliqué à mettre en place.

Ce journal explique comment mettre en place un serveur de build automatiques maison.

L'intérêt est d'avoir une solution locale qui permet de compiler sur un réseau local (en entreprise par exemple où l'accès à Internet est parfois compliqué et où on a rarement envie d'utiliser des services externes)

Ici je vais détailler commente compiler régulièrement des projets utilisant gcc et automake.

Outils

Pour réaliser tout ça, on a utilisé :

  • Ubuntu 14.04
  • docker 1.6.2
  • jenkins 2.150.2
  • alpine 3.7

installation de docker

On commence par installer docker, pour ça pas de mystère, on tape :

$sudo apt-get install docker.io 

Une fois docker installé, on permet à l'utilisateur lambda de l'utiliser :

$sudo addgroup docker
$sudo usermod -aG docker $USER

On se déconnecte/reconnecte et on peut tester que tout fonctionne :

docker run hello-world

installation de jenkins

On lance une image jenkins :

$docker run --name jenkins-master -d -p 8080:8080 -p 50000:50000 -v /var/jenkins_home jenkins/jenkins:lts

Explication de la commande :

  • docker run : on lance une image
  • --name jenkins-master : on lui donne un nom
  • -d : en arrière plan
  • -p x:y : le port y de la machine virtuelle est mappée sur le port x de l'hote
  • -v chemin : on crée un volume pour garder les données de jenkins
  • jenkins/jenkins:lts : nom de l'image à utiliser (prise depuis hub.docker.com)

Une fois la machine lancée, on peut lancer un navigateur web et se connecter sur 127.0.0.1:8080.

Après quelque temps, jenkins est prêt à être configuré. La première chose qu'il demande, est le mot de passe initial, pour cela, on demande à docker de nous récupérer un fichier dans la machine jenkins :

$docker cp jenkins-master:/var/jenkins_home/secrets/initialAdminPassword .
Il faut alors copier le contenu du fichier initialAdminPassword dans la page web qui la demandait.

Il est alors demandé de sélectionner les plugins à installer, on peut garder les réglages par défaut.


On entre les informations de l'administrateur, et surtout, on clique sur "save & continue".

On définit enfin à quelle adresse sera accessible le serveur.

Jenkins est prêt à être utilisé.

Création d'un agent SSH

Maintenant, on va créer une seconde machine docker qui sera en charge de compiler notre projet.

création d'un esclave ssh

Identification des besoins

Dans un projet, on identifie ce dont on a besoin, ici je prends un vieux projet perso : txt2snd

Pour la construction, on aura besoin de :

  • gcc et une lib-c
  • make, automake et autoconf
  • libsndfile

Fort de ces informations, on peut créer un fichier Dockerfile qui pourra compiler le projet et interagir avec le maitre jenkins

    # on part d'une image alpine 
    FROM alpine:3.7

    # on ajoute openssh pour la connexion ssh
    # et openjdk qui est requis par jenkins
    RUN apk add openssh openjdk8-jre-base

    # on ajoute git pour accéder au repo
    RUN apk add git

    # gcc et make 
    RUN apk add gcc make

    # et enfin les bibliothèques dont le projet a besoin
    RUN apk add libc-dev libsndfile-dev

    # un peu de configuration
    # un script pour générer des clefs ssh 
    COPY ssh-slave-entrypoint.sh /usr/bin/

    # en le rendant executable (est-ce bien nécessaire ?)
    RUN chmod +x /usr/bin/ssh-slave-entrypoint.sh

    # on efface d'éventuels anciennes clefs (même remarque)
    RUN rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key

    # on crée un utilisateur
    RUN adduser -D jenkins

    # auquel on ajoute un mot de passe
    RUN echo "jenkins:jenkins" | chpasswd

    # et on crée un répertoire pour ranger le bazard jenkins
    RUN mkdir /home/jenkins/jenkins_slave

    # que l'on donne à l'utilisateur
    RUN chown jenkins /home/jenkins/jenkins_slave

    # on ouvre le port 22 pour ssh
    EXPOSE 22

    # on définit le script copié plutôt comme le point d'entrée
    ENTRYPOINT ["ssh-slave-entrypoint.sh"]

    # et on lance le serveur ssh au démarrage de la machine
    CMD ["/usr/sbin/sshd", "-D"]

Le fichier ssh-slave-entrypoint.sh contient lui

    #!/bin/sh

    if [ ! -f "/etc/ssh/ssh_host_rsa_key" ] ; then
        ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa
    fi


    if [ ! -f "/etc/ssh/ssh_host_dsa_key" ] ; then
        ssh-keygen -f /etc/ssh/ssh_host_dsa_key -N '' -t dsa
    fi 

    if [ ! -d "/var/run/sshd" ]; then
        mkdir -p /var/run/sshd
    fi

    exec "$@"

Ce script là, je l'ai pris du dépot alpine-sshd.

On construit l'image :

$docker build -t gcc.slave .
Avec :

  • docker build : on crée une nouvelle image
  • -t gcc.slave : qu'on appelle 'gcc.slave'
  • . : on prend de Dockerfile du dossier courant

Et on lance cette image, en redirigeant le port 22 sur le 2222 :

$docker run -d --name gcc.slave -p 2222:22 gcc.slave
On peut maintenant dire à jenkins d'utiliser cette image.

ajout de l'esclave à jenkins

On se rend à la page 127.0.0.1:8080/computer/new pour créer un nouveau noeud.

Une fois dans la page http://127.0.0.1:8080/computer/createItem, on configure :

  • le nom de l'agent, ici gcc.slave
  • le nom du répertoire de travail (Remote root directory), ici /home/jenkins/jenkins_slave
  • l'adresse de l'agent (qu'on récupère avec ifconfig)
  • les droits d'accès (ici jenkins/jenkins)
  • la stratégie de vérification, ici on vérifie rien
  • le port ssh (dans le menu avancé), ici 2222




On enregistre le tout et sur la page 127.0.0.1:8080/computer/gcc.slave/, on lance l'agent.

L'agent est lancé ? Alors on peut configurer le projet.

configuration du projet à construire

Sur la page 127.0.0.1:8080/newJob, on créé le projet txt2snd de type Freestyle project

Puis on le configure :

  • Dans "General"
    • On sélectionne "Restrict where this project can be run" et indiquer le nom de l'agent ssh à utiliser si on a plusieurs projets et plusieurs agents
  • Dans "Source Code Management", on sélectionne "Git"
    • On indique l'URL du dépot : https://framagit.org/mabu/txt2snd.git
  • Dans "Build Triggers"
    • Des build périodique
    • Qu'on programme tous les jours à midi : H 12 * * *
  • Dans "Build"
    • On ajoute "execute shell", avec pour code : #!/bin/sh autoreconf --install ./configure make


On enregistre.

Et on tente de lancer le build: 127.0.0.1:8080/job/txt2snd/build?delay=0sec (il y a un bouton pour ça).

Et finalement, le programme est compilé. On peut aller chercher les fichiers construits dans 127.0.0.1:8080/job/txt2snd/ws/

Et après

Dans cet article, je suis passé un peu vite sur la sécurisation des agents, dans le cadre d'un réseau isolé, c'est pas bien grave, mais il faut garder à l'esprit que j'ai un peu bâclé cette partie.

Après, on peut aller plus loin, on peut imaginer avoir un agent sur une machine réelle qui puisse exécuter d'autres outils de compilation ou même des systèmes de tests maisons.

On peut aussi changer de SCM, envoyer des mails en cas d'échec, déployer…

Les possibilités semblent illimitées.

  • # drone.io

    Posté par . Évalué à 4.

    Hello,
    Quelqu'un a-t-il déjà essayé drone?

    • [^] # Re: drone.io

      Posté par (page perso) . Évalué à 7. Dernière modification le 10/02/19 à 18:20.

      Salut,

      J'ai testé drone. C'est vraiment pas mal et surtout super léger. Au final je suis passé sur GitLab CI avec mon propre runner pour build et push mes images Docker. Je trouve GitLab CI plus flexible et je préfère la syntaxe.

      • [^] # Re: drone.io

        Posté par . Évalué à 4. Dernière modification le 10/02/19 à 20:01.

        Ça donne quoi Gitlab CI en termes de RAM ? Parce que Gitlab tout court prend déjà 2 Go de RAM de base et donc c'est déjà du gâchis de ressources pour une petite install.

        J'suis aussi en quête d'un outil de meilleure qualité que Jenkins (le Eclipse de l'intégration continue) et au moins aussi léger. Puis avec une intégration Docker de meilleure qualité. J'arrive toujours pas à comprendre l'absence de client docker dans les images officielles du master ; j'ai du bricoler ça moi même.

        • [^] # Re: drone.io

          Posté par . Évalué à 1.

          Les runners de gitlab ci sont écrits en Go. Donc, j'imagine que ça ne doit pas prendre beaucoup de RAM.

        • [^] # Re: drone.io

          Posté par (page perso) . Évalué à 2.

          En perso j'utilise le couple gîtes + drone.
          C'est très léger et ça fonctionne bien.

        • [^] # Re: drone.io

          Posté par . Évalué à 4.

          Bonjour,

          ici nous utilisons gitlab depuis 4ans. Oui ça prend un peu de ram. 3go pour une instance avec une douzaine de projet actif et autant de développeur/datascientist. Un peu de disque. (Surtout quand on me commit tout anaconda ….). Les mises à jour sont régulières via un dépôt apt et elles sont fiables. Je n'ai eu en 4ans qu'un seul problème de mise à jour.

          Depuis quelques mois nous utilisons aussi gitlab ci avec un kubernetes auto hébergé. Et bien ça change la vie ! Je crée une branche et j'ai de suite un environnement qui tourne sur cette branche avec un snapshot des données de la prod (merci ceph !) et une url dédié. Je fait ma modif. La QA la valide. La branche est merge et tout passe en prod tout seul. Plus de script de mise en production, plus de "jour de mise en prod". Bref on a plongé dans le grand bain du devops, cloud, container etc.

          A titre personnel j'étais plus que réticent. Je regarde ces technos du coin de l’œil depuis des années avec scepticisme et finalement j'en suis très content.

          Cependant il y a un soucis de cache avec le gitlab runner et le build d'image docker qui est très long. Vu que chaque stage est dans un environnement docker tout neuf (dind) il n'y a pas de mise en cache des différentes étapes de build. Je dois donc maintenir une image de base avec tout ce qui est nécessaire. Image que j'utilise ensuite juste pour copier le code de l'application et la conf.

          Pour vous donner une idée il faut environ deux minutes pour démarrer 6 pod qui contiennent un minimum de deux container (j'utilise istio) et jusqu’à 4 container. Pour un total d'environ 15 container. Il y a aussi le snapshot de la base postgres et son démarrage.

      • [^] # Re: drone.io

        Posté par . Évalué à 3.

        gitlab CI est disponible en service ou faut-il le gérer soi-même à la main ?

        "La première sécurité est la liberté"

    • [^] # Re: drone.io

      Posté par . Évalué à 3.

      C’est ce que j’utilise. S’intègre bien avec gitea.

      Il y a aussi : https://sourcehut.org/

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.