Configuration de l'intégration continue et du déploiement continu avec Jenkins

La vie quotidienne d'un développeur est remplie de tâches monotones et répétitives. Heureusement, nous vivons à une époque d'intelligence pré-artificielle, ce qui signifie que les ordinateurs sont parfaits pour gérer des tâches ennuyeuses et qu'ils déjà se plaindre à ce sujet! Alors mettons en place une automatisation pour rendre notre quotidien un peu moins grindy.

Les tests et le déploiement sont deux éléments essentiels du développement Web. Avec une certaine automatisation, elles deviennent des solutions communément appelées "intégration continue" (CI) et "déploiement continu" (CD). L'aspect "continu" de ces solutions signifie que vos projets seront automatiquement testés et déployés, ce qui vous permettra de vous concentrer davantage sur l'écriture de code et moins sur son suivi sur des serveurs..

Dans ce didacticiel, nous allons configurer un serveur d’intégration continue bien connu, Jenkins, et le synchroniser avec GitHub afin qu’il exécute des tests chaque fois que du nouveau code est envoyé. Après cela, nous créerons une solution pour envoyer automatiquement ce code sur notre serveur d'applications, éliminant ainsi le besoin de déployer manuellement..

Nous utiliserons DigitalOcean pour créer rapidement et facilement des serveurs privés virtuels (VPS) basés sur le cloud pour héberger notre application et Jenkins..

Remarque: Ce didacticiel suppose que vous maîtrisez les bases de la ligne de commande et que votre ordinateur dispose de Git et de Node.js..

Notre superbe exemple d'application

Avant de pouvoir tester ou déployer quoi que ce soit, nous avons besoin quelque chose pour tester et déployer. Permettez-moi de vous présenter notre sympathique application de test de tutoriel, appelée à juste titre "hello-jenkins".

Nous allons écrire une simple application Node.js pour répondre à nos besoins. Cela ne fera pas beaucoup plus que d'afficher une ligne de texte dans le navigateur, mais c'est juste assez de fonctionnalités pour garantir que nous avons correctement configuré l'intégration et le déploiement continus..

Git Up sur GitHub

Puisque nous allons stocker notre projet sur GitHub, commençons par là. Connectez-vous à (ou créez) votre compte GitHub et créez un nouveau référentiel. Nommez-le "hello-jenkins" et donnez-lui la description suivante:

Mon super exemple d'application pour tester Jenkins.

Pour plus de simplicité, gardons le dépôt Publique. Allez-y et vérifiez la Initialiser ce référentiel avec un fichier README option et sélectionnez le Nœud option du Ajouter .gitignore la liste déroulante.

Clique le Créer un référentiel bouton, et notre repo sera prêt.

Clonons maintenant notre nouveau référentiel sur notre machine locale et parcourons-le:

git clone [email protected]:/hello-jenkins.git cd bonjour-jenkins

Notre application de nœud

Voici quelle sera la structure finale de notre application:

├── .gitignore ├── app.js package.json README.md script │ déploiement │ │ test └── test └── test.js

Allons-y un à un. La première étape pour créer une application Node.js consiste à créer un package.json fichier. Voici les nôtres:

"name": "hello-jenkins", "description": "hello jenkins test app", "version": "0.0.1", "private": true, "dépendances": "express": "3.12. 0 "," devDependencies ": " mocha ":" 1.20.1 "," supertest ":" 0.13.0 "

Sous les dépendances nous avons ajouté Express, que nous utiliserons pour créer notre application Node.js. Sous devDependencies nous avons ajouté moka et supertest, ce qui nous aidera à écrire nos tests.

Maintenant que notre package.json est défini, installez nos dépendances d'application en lançant:

npm installer

Il est temps d'écrire notre code d'application. Créer un fichier nommé app.js et ajoutez ce qui suit:

var express = require ('express'); var app = express (); app.get ('/', fonction (req, res) res.send ('hello world');); app.listen (process.env.PORT || 5000); module.exports = app;

Décomposons notre application simple Node.js:

  • Tout d'abord, nous importons le Express lib nous avons spécifié dans notre package.json.
  • Nous utilisons Express créer un nouveau app.
  • Nous disons notre app pour répondre à toutes les demandes adressées à la racine de notre site (/) avec le texte "hello world".
  • Ensuite, nous racontons notre app sur quel port écouter les requêtes (process.env.PORT fait référence à la variable d’environnement appelée "PORT", et si elle n’existe pas, on utilise par défaut le port 5000).
  • Enfin, nous faisons notre app disponible pour les autres modules Node.js via module.exports (cela nous sera utile plus tard lorsque nous ajouterons des tests).

C'est tout! Notre application est prête - exécutons-la:

noeud app.js

Ouvrez votre navigateur préféré et accédez à http: // localhost: 5000, et vous devriez voir Bonjour le monde assis dans toute sa glorieuse simplicité.

Ce n'est pas l'application de test la plus excitante, mais ça marche! Allez-y et fermez notre application Node.js avec Ctrl-C, et passons.

Certains tests sont en ordre

Il est temps d'écrire un test pour notre application. Après tout, si nous n'avons rien à tester, Jenkins n'aura rien à faire.!

Créez un dossier appelé tester, et créer un fichier nommé test.js. Ajoutez le code suivant à test / test.js:

var request = require ('supertest'); var app = require ('… /app.js'); decrire ('GET /', function () it ('répondre avec hello world', fonction (done) request (app) .get ('/'). expect ('hello world', done);); );

Comment fonctionne notre test? Premièrement, nous importons les deux supertest lib et notre app. Ensuite, nous ajoutons un seul test, décrivant ce qui devrait se passer quand un OBTENIR demande frappe la racine de notre site. Nous disons à notre test de s’attendre à ce que la réponse soit "bonjour le monde", et si c’est le cas, le test réussit..

Pour exécuter le test, nous allons utiliser la bibliothèque Mocha. Nous avons installé Mocha dans le cadre de notre devDependencies, Nous allons donc simplement exécuter une commande qui transmet notre fichier de test à Mocha et Mocha exécutera nos tests:

./node_modules/.bin/mocha ./test/test.js

Lorsque vous avez terminé, vous devriez voir un point vert accompagné d'informations indiquant qu'un test est réussi. Cela signifie que notre test a réussi! Mais taper cette commande encore et encore produira bientôt des crampes aux doigts et des contractions oculaires, alors créons un script d'aide pour le faire pour nous (souvenez-vous que les ordinateurs ne s'ennuient pas!).

Faire un nouveau répertoire appelé scénario, et créer un fichier nommé tester (notez qu'il n'y a pas d'extension). Ajouter ce qui suit à script / test:

#! / bin / sh ./node_modules/.bin/mocha ./test/test.js

Nous avons maintenant un script shell pour exécuter cette ligne épineuse pour nous. Mais avant de pouvoir l'utiliser, nous devons lui accorder des autorisations d'exécution:

chmod + x script / test

Testons-le! Courir:

./ script / test

… Et vous devriez voir le même test de réussite qu'auparavant.

Il est temps de pousser

Bon, nous avons une application et un test qui fonctionnent, alors poussons notre nouveau code vers GitHub:

git add. git commit -m 'Ajouter une application de nœud' Maître d'origine git push

Et c'est tout - notre application est terminée et sur GitHub!

Notre application est servie

Nous avons une application captivante et captivante ("hello world" a une sorte de poésie, tu ne conviens pas?), Mais personne ne peut la voir! Changeons cela et faisons fonctionner notre application sur un serveur.

Pour nos besoins en hébergement, nous allons nous tourner vers DigitalOcean. DigitalOcean offre un moyen simple et rapide de mettre en place des instances cloud VPS, ce qui en fait l'hôte idéal pour notre espace de jeu CI / CD..

La première goutte

Connectez-vous à (ou inscrivez-vous à) DigitalOcean et cliquez sur le bouton Créer une gouttelette bouton. Pour le nom d'hôte, appelez-le "hello-jenkins". L'instance de taille la plus basse (512 Mo / 1/20 Go) répondra à nos besoins et sélectionnera la région géographique la plus proche de chez vous. Ensuite, nous devons choisir l'image utilisée pour créer le droplet. DigitalOcean propose une large sélection de systèmes d'exploitation, mais ce qui est bien, c'est qu'ils fournissent également des images spécialement adaptées à certains types d'applications..

Clique le Applications onglet, et sélectionnez le node-v0.10.29 sur Ubuntu 14.04 option - cela créera un serveur bien amorcé pour notre application Node.js.

Maintenant, cliquez Créer une gouttelette, et DigitalOcean va commencer à initialiser notre serveur.

Configurez le serveur

Dans une minute, notre nouveau serveur devrait être prêt et vous devriez avoir reçu un courrier électronique avec les informations d'identification racine de votre serveur. Utilisons cette information pour vous connecter:

ssh [email protected]

Le mot de passe fourni dans le courrier électronique vous sera demandé, puis immédiatement forcé de créer un nouveau mot de passe (créez un mot de passe très fort et stockez-le dans un emplacement sécurisé, comme une base de données KeePass)..

En ce moment nous sommes connectés en tant que racine, qui est le demi-dieu tout puissant de Linux-land. Mais lourde est la tête qui porte la couronne, et opérant comme racine est généralement une mauvaise idée. La première chose à faire est donc de créer un nouvel utilisateur - appelons-le "app":

application adduser

Vous devrez fournir un mot de passe (un différentmot de passe fort, stocké en toute sécurité), puis il va poser une série de questions facultatives.

Nous voulons passer à notre app utilisateur, mais avant de nous déconnecter, nous devons accorder à notre nouvel utilisateur sudo privilèges afin qu'il puisse effectuer des actions administratives:

application usermod -a -G sudo

Maintenant fermez la connexion avec sortie, puis connectez-vous en tant que app:

ssh [email protected]

Vous serez invité pour le app mot de passe de l'utilisateur, et alors vous devriez être connecté et bon aller.

Installer notre application

Mettons notre application sur la machine. Grâce aux images d'application de DigitalOcean, notre machine est livrée avec Node.js et NPM préinstallés, mais nous devons toujours installer Git:

sudo apt-get install git

On vous demandera votre mot de passe (puisque vous utilisez sudo), et vous devrez confirmer l'installation avec Y. Une fois que Git est installé, nous pouvons l’utiliser pour obtenir notre application à partir de GitHub..

Copiez l'URL de clone HTTPS à partir de la page GitHub du projet, puis clonez le référentiel dans votre dossier personnel sur le serveur:

cd git clone https://github.com//hello-jenkins.git

Maintenant, notre application est sur notre serveur, dans un dossier appelé "hello-jenkins". Naviguons dans cela:

cd bonjour-jenkins

La première chose à faire est d’installer les dépendances de l’application:

npm install --production

Une fois que cela est fait, nous pouvons exécuter notre application! Faites-le tourner avec:

noeud app.js

… Et accédez à l'adresse IP de votre serveur dans votre navigateur.

Mais attendez, ça ne marche pas! Quel est le problème?

Eh bien, rappelons cette ligne de code dans notre app.js:

app.listen (process.env.PORT || 5000);

Pour l'instant, nous n'avons pas de PORT variable d’environnement définie, notre application utilise par défaut le port 5000 et vous devez ajouter le port à l’adresse IP du navigateur (http: //YOUR.SERVER.IP.ADDRESS: 5000).

Alors, comment pouvons-nous obtenir que notre application fonctionne comme prévu, sans avoir à spécifier le port? Eh bien, lorsqu'un navigateur émet une requête HTTP, il utilise par défaut le port 80. Il suffit donc de définir notre PORT variable d'environnement à 80.

Nous allons définir nos variables d'environnement dans le / etc / environment fichier sur le serveur - ce fichier est chargé lors de la connexion et le jeu de variables sera disponible globalement pour toutes les applications. Ouvrez le fichier:

sudo nano / etc / environment

Vous verrez que maintenant le CHEMIN est défini dans ce fichier. Ajoutez la ligne suivante après celle-ci:

PORT = 80

Puis tapez Ctrl-X, Y, et Entrer pour sauvegarder et quitter. Déconnexion du serveur (sortie) et SSH dans (cela chargera la nouvelle variable d’environnement).

Une dernière petite tâche - exécuter une application sur le port 80 nécessite des privilèges root, mais exécuter noeud sudo app.js ne préservera pas les variables d’environnement que nous avons définies. Pour résoudre ce problème, nous activerons nœud avoir la capacité de fonctionner sur le port 80 sans sudo:

sudo setcap cap_net_bind_service = + ep / usr / local / bin / node

Ça devrait le faire. Maintenant, lancez:

noeud app.js

Aller vers http: //YOUR.SERVER.IP.ADDRESS, et vous verrez Bonjour le monde!

Gardez-le en cours d'exécution

Actuellement, notre application ne s'exécute que pendant l'exécution du processus. Si nous la fermons, notre site n'est plus disponible. Ce dont nous avons besoin, c'est d'un moyen de garder notre application Node.js en marche en arrière-plan. Pour cela, nous utiliserons pour toujours. La première étape consiste à l'installer globalement:

sudo npm install -g pour toujours

Maintenant, au lieu de démarrer notre application avec noeud app.js, nous allons utiliser:

pour toujours démarrer app.js

Notez que, au lieu du processus suspendu à l'exécution, il se termine immédiatement et vous redonne le contrôle. En effet, le serveur Node.js s'exécute en arrière-plan. Maintenant, nous n'avons plus à nous soucier de la fermeture de notre serveur lorsque nous nous déconnectons du serveur.. pour toujours va même automatiquement redémarrer notre application s'il se produit un crash!

Pour arrêter notre application, nous pouvons exécuter:

arrêt pour toujours

Pour l'instant, continuons, et passons à Jenkins.

Un temps pour tester

Nous hébergerons notre serveur Jenkins sur un droplet DigitalOcean séparé. Tournons ça maintenant.

La deuxième goutte

Créez un nouveau droplet avec le nom d’hôte "jenkins-box". Choisir 512 Mo / 1/20 Go encore une fois, avec le même emplacement et le même type d’application (node-v0.10.29 sur Ubuntu 14.04) comme avec la gouttelette précédente.

Cliquez sur Créer une gouttelette et une fois terminé, utilisez les informations d'identification qui vous ont été envoyées pour vous connecter via SSH (vous devrez définir un nouveau mot de passe, comme avant).

Comme auparavant, nous devrions créer un nouvel utilisateur avant de faire autre chose. Cette fois, appelons ça admin:

adduser admin usermod -a -G administrateur sudo

Déconnectez-vous en tant que racine et vous connecter en tant que nouvellement créé admin.

Comme Jenkins a pour objectif de récupérer notre projet et d'exécuter ses tests, notre machine doit disposer de toutes les dépendances du projet. Nous avons créé cette instance avec l'application Node.js de DigitalOcean. Node.js et npm sont donc déjà installés. Mais il faut encore installer Git:

sudo apt-get install git

Louez le majordome

La prochaine étape est Jenkins. Installer Jenkins est assez simple - nous aurons apt-get faire tous les efforts lourds. Le seul problème est que nous devons ajouter un nouveau apte référentiel avant de commencer l'installation:

sudo wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add - sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary /> /etc/apt/sources.list.d/jenkins.list' sudo apt-get update

Maintenant nous pouvons installer Jenkins:

sudo apt-get install jenkins

Une fois terminé, Jenkins fonctionnera et sera disponible sur le port 8080. Accédez à votre navigateur. Jenkins-Box Adresse IP sur le port 8080 et vous verrez la page de destination Jenkins.

Clique le Gérer Jenkins lien, puis le Gérer les plugins lien. Basculer vers le Disponible onglet et recherchez le Plugin GitHub. Clique le Installer case à cocher, puis le Téléchargez maintenant et installez après le redémarrage bouton.

Cela initiera la séquence d'installation. Le plugin GitHub a plusieurs dépendances, donc plusieurs plugins seront installés. Au bas de la page, cochez la case Redémarrez Jenkins lorsque l'installation est terminée et qu'aucun travail n'est en cours d'exécution. - cela incitera Jenkins à redémarrer une fois les installations terminées.

Une fois que Jenkins a redémarré, il est temps d'ajouter notre projet. Clique le Nouvel article bouton. Utilisez "hello-jenkins" pour le nom de l'élément, sélectionnez Construire un projet de logiciel libre, et cliquez sur le bouton intitulé D'accord.

Une fois le projet configuré, vous vous retrouverez sur la page des paramètres du projet. Ajoutez l'URL GitHub de notre projet au Projet GitHub boîte:

https://github.com// bonjour-jenkins

Ensuite, sélectionnez le Git option sous Gestion du code source. Dans les champs nouvellement apparus, ajoutez l’URL du dépôt de notre projet GitHub au URL du référentiel champ:

https://github.com//hello-jenkins.git

Faites défiler un peu plus bas et cliquez sur la case pour activer Construire quand un changement est poussé vers GitHub. Avec cette option cochée, notre projet se construira chaque fois que nous pousserons vers notre dépôt GitHub. Bien entendu, Jenkins doit savoir quoi faire lorsqu'il exécute une construction. Clique le Ajouter une étape de construction liste déroulante et sélectionnez Exécuter shell. Cela fera un Commander dialogue disponible, et ce que nous mettons dans ce dialogue sera exécuté quand une construction commencera. Ajoutez ce qui suit:

npm install ./script/test

Notre construction se compose de deux étapes. Tout d'abord, il installe nos dépendances d'application. Puis il exécute ./ script / test exécuter nos tests.

Cliquez sur "sauvegarder".

Pour terminer la configuration de l’intégration, rendez-vous sur le dépôt GitHub, puis cliquez sur Réglages. Clique le Webhooks et services onglet, puis le Ajouter un service menu déroulant. Sélectionnez le Jenkins (plugin GitHub) un service.

Ajouter ce qui suit comme Jenkins hook url:

http: //JENKINS.SERVER.IP.ADDRESS: 8080 / github-webhook /

Cliquez sur Ajouter un service. Notre projet est maintenant prêt pour son premier test d'intégration continue!

Donnons-lui quelque chose à tester. S'ouvrir app.js localement et changez cette ligne:

res.send ('bonjour le monde');

… pour ça:

res.send ('bonjour jenkins');

Enregistrez le changement et validez-le:

git add. git commit -m 'Passez à bonjour Jenkins'

Maintenant, gardez un oeil sur Jenkins pendant que vous appliquez vos modifications à GitHub:

maître d'origine git push

Après une seconde ou deux, vous devriez voir qu'un nouveau travail a été lancé pour notre bonjour-jenkins projet à Jenkins - nos travaux d'intégration continue!

Le flux d'intégration continue

Mais… le travail échoue! Pourquoi?

Eh bien, rappelez-vous que notre test s'attend à ce que l'appel racine retourne "hello world", mais nous l'avons changé en "hello jenkins". Alors changeons les attentes de notre test. Échangez cette ligne:

request (app) .get ('/'). expect ('hello world', terminé);

… Avec cette ligne:

request (app) .get ('/'). expect ('hello jenkins', c'est fait);

Sauvegarder, valider et pousser à nouveau:

git add. git commit -m 'Basculez le test sur hello jenkins' git push origin master

Regardez Jenkins - une fois encore, vous verrez une compilation automatiquement démarrée et cette fois, elle réussit!

C'est le flux de l'intégration continue. Le serveur de test teste en permanence tout nouveau code que vous envoyez afin que vous soyez rapidement informé de tout test ayant échoué..

Obtenez-le déployé

Bon, nous testons automatiquement nos modifications, mais qu'en est-il du déploiement de ces modifications? aucun problème!

Si vous avez surveillé de près, vous avez sans doute remarqué qu'il nous manque quelque chose dans notre projet jusqu'à présent. Dans la structure du projet au début du tutoriel, il existe une script / déployer fichier, mais nous n’avons pas encore créé de fichier de ce type. Eh bien, maintenant nous allons!

La clé de l'authentification

Mais d'abord, discutons du fonctionnement du déploiement. Notre script (exécuté par l'étape de génération de Jenkin) va se connecter au serveur d'applications via SSH, accéder à notre dossier d'applications, mettre à jour l'application, puis redémarrer le serveur. Avant d'écrire notre script de déploiement, nous devons gérer la manière dont notre serveur Jenkins utilisera SSH dans notre serveur d'applications..

Jusqu'à présent, nous avons accédé à nos serveurs en saisissant manuellement les mots de passe, mais cette approche ne fonctionnera pas pour les scripts automatisés. A la place, nous allons créer une clé SSH que le serveur Jenkins utilisera pour s’authentifier auprès du serveur d’applications..

Lorsque Jenkins installe, il crée un nouvel utilisateur appelé Jenkins. Jenkins exécute toutes les commandes avec cet utilisateur, nous devons donc générer notre clé avec le Jenkins utilisateur pour qu'il y ait un accès approprié.

Bien connecté en tant que admin sur le Jenkins-Box, exécuter ce qui suit:

sudo su

Fournir votre admin mot de passe, et ça va vous passer à la racine utilisateur. Puis exécutez:

su Jenkins

Maintenant, vous agissez en tant que Jenkins utilisateur. Générez une clé SSH:

ssh-keygen -t rsa

Enregistrez le fichier à l’emplacement par défaut (/var/lib/jenkins/.ssh/id_rsa), et assurez-vous de ne pas utiliser de phrase secrète (sinon, l'accès SSH nécessitera un mot de passe et ne fonctionnera pas s'il est automatisé).

Ensuite, nous devons copier la clé publique créée. Lance ça:

cat ~ / .ssh / id_rsa.pub

… Et copiez le résultat. Ce devrait être une longue chaîne commençant par "ssh-rsa" et se terminant par "jenkins @ jenkins-box".

Déconnectez-vous de Jenkins-Box et reconnectez-vous à notre serveur d'applications (bonjour-jenkins) comme app utilisateur. Nous devons créer un fichier nommé clés_autorisées dans notre app utilisateurs.ssh dossier:

mkdir ~ / .ssh nano ~ / .ssh / registered_keys

Collez la clé publique que vous avez copiée, puis Ctrl-X/Y/Entrer pour sauvegarder et quitter. Pour que ce fichier fonctionne correctement, il doit disposer d'autorisations strictes:

chmod 700 ~ / .ssh chmod 600 ~ / .ssh / *

Retournez au Jenkins boîte, passer à la Jenkins utilisateur et vérifiez que vous pouvez vous connecter à notre serveur d'applications sans entrer de mot de passe:

ssh [email protected]

Vous devez vous connecter avec succès au serveur d'applications sans avoir à entrer le mot de passe. Une fois cela établi, nous pouvons maintenant nous tourner vers le déploiement.

Expédier automatiquement

Créer un fichier dans le scénario dossier nommé déployer (notez qu'il n'y a pas d'extension). Ajouter ce qui suit à script / déployer:

#! / bin / sh ssh [email protected] <

Passons en revue ceci:

  • Tout d'abord, nous nous connectons au serveur d'applications en tant que app utilisateur.
  • Ensuite, nous naviguons dans notre dossier d'applications et mettons à jour la dernière version de GitHub..
  • Après cela, nous installons nos dépendances.
  • Enfin, une fois notre code d’application mis à jour, nous redémarrons notre serveur avec recommencer à jamais.

Rendre notre nouveau fichier script exécutable:

chmod + x script / deploy

Ajoutez ce nouveau fichier et validez-le:

git add. git commit -m 'Ajouter un script de déploiement'

Mais ne poussons pas tout à fait encore. Tout d’abord, revenez à la configuration de notre projet dans Jenkins et faites défiler jusqu’à la commande build. Ajoutez cette nouvelle ligne à la fin de celle-ci:

./ script / deploy

Sauvez le projet Jenkins.

Maintenant, allez de l'avant et appuyez sur GitHub, et regardez comment Jenkins se construit automatiquement. Une fois la construction terminée (elle devrait réussir), naviguez sur votre navigateur jusqu'à l'adresse IP de notre serveur d'applications. Presto! Notre passionnant "hello world" a été remplacé par un "hello jenkins" exaltant!

Notre application est maintenant déployée en permanence!

Tout va bien qui s'automatise bien

Phew. C'était tout le trajet!

Au final, nous avons réussi à mettre en place une intégration continue et déploiement continu, ce qui offre un très bon niveau d'automatisation dans nos vies de développeurs quotidiennes. N'oubliez pas que les ordinateurs ne s'ennuient pas. Par conséquent, même s'ils gèrent les tests et les déploiements, vous êtes libre de faire des choses importantes, comme vous faire un sandwich. Alors va faire ce sandwich et mange-le comme un champion de l'automatisation!