{"id":69351,"date":"2020-02-18T14:44:06","date_gmt":"2020-02-18T11:44:06","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/sozdanie-ci-cd-czepochki-i-avtomatizacziya-raboty-s-docker"},"modified":"2020-03-03T16:15:00","modified_gmt":"2020-03-03T13:15:00","slug":"sozdanie-ci-cd-czepochki-i-avtomatizacziya-raboty-s-docker","status":"publish","type":"post","link":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/sozdanie-ci-cd-czepochki-i-avtomatizacziya-raboty-s-docker","title":{"rendered":"Cr\u00e9ation d'une cha\u00eene CI\/CD et automatisation du travail avec Docker.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>J'ai cr\u00e9\u00e9 mes premiers sites \u00e0 la fin des ann\u00e9es 90. \u00c0 l'\u00e9poque, il \u00e9tait tr\u00e8s simple de les mettre en ligne. Il y avait un serveur Apache sur un h\u00e9bergement partag\u00e9, et on pouvait y acc\u00e9der par FTP en \u00e9crivant dans la barre de navigation quelque chose comme <code>ftp:\/\/ftp.example.com<\/code>. Ensuite, il fallait entrer un nom d'utilisateur et un mot de passe pour t\u00e9l\u00e9charger les fichiers sur le serveur. C'\u00e9taient d'autres temps, tout \u00e9tait alors plus simple qu'aujourd'hui.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/488668\/\"><img decoding=\"async\" alt=\"Cr\u00e9ation d&#039;une cha\u00eene CI\/CD et automatisation du travail avec Docker.\" src=\"\/wp-content\/uploads\/2020\/02\/0861cdd82770ef4695ffac7a09777c52.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p>Au cours des deux derni\u00e8res d\u00e9cennies, beaucoup de choses ont chang\u00e9. Les sites sont devenus plus complexes, et avant de les mettre en production, ils doivent \u00eatre assembl\u00e9s. Un seul serveur est devenu de nombreux serveurs fonctionnant derri\u00e8re des \u00e9quilibrages de charge, et l'utilisation de syst\u00e8mes de contr\u00f4le de version est devenue courante.<\/p>\n<p>Pour mon projet personnel, j'avais une configuration particuli\u00e8re. Et je savais que j'avais besoin de la possibilit\u00e9 de d\u00e9ployer le site en production en effectuant une seule action : \u00e9crire le code dans la branche <code>master<\/code> sur GitHub. De plus, je savais que, pour faire fonctionner ma petite application web, je ne voulais pas m'occuper de la gestion d'un \u00e9norme cluster Kubernetes, ou d'utiliser la technologie Docker Swarm, ou de maintenir un parc de serveurs avec des pods, des agents et d'autres complexit\u00e9s. Pour atteindre mon objectif de simplification maximale, j'ai d\u00fb me familiariser avec le CI\/CD.<\/p>\n<p>Si vous avez un petit projet (dans notre cas, un projet Node.js) et que vous aimeriez savoir comment automatiser le d\u00e9ploiement de ce projet en veillant \u00e0 ce que ce qui est stock\u00e9 dans le d\u00e9p\u00f4t corresponde exactement \u00e0 ce qui fonctionne en production, alors je pense que cet article pourrait vous int\u00e9resser.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Pr\u00e9requis<\/h2>\n<p>\nIl est attendu que le lecteur de cet article ait des connaissances de base en ligne de commande et en \u00e9criture de scripts Bash. De plus, il aura besoin de comptes <noindex><a rel=\"nofollow\" href=\"https:\/\/travis-ci.org\/\">Travis CI<\/a><\/noindex> et <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/\">Docker Hub<\/a><\/noindex>.<\/p>\n<h2>Objectifs<\/h2>\n<p>\nJe ne dirai pas que cet article peut \u00eatre qualifi\u00e9 sans r\u00e9serve de \u00ab guide pratique \u00bb. Il s'agit plut\u00f4t d'un document dans lequel je partage ce que j'ai appris et d\u00e9cris le processus de test et de d\u00e9ploiement de code en production qui me convient, effectu\u00e9 en un seul passage automatis\u00e9.<\/p>\n<p>Voici \u00e0 quoi ressemble au final mon processus de travail.<\/p>\n<p>Pour le code envoy\u00e9 dans n'importe quelle branche du d\u00e9p\u00f4t, \u00e0 l'exception de <code>master<\/code>, les actions suivantes sont effectu\u00e9es :<\/p>\n<ul>\n<li>La construction du projet est lanc\u00e9e sur Travis CI.<\/li>\n<li>Tous les tests unitaires, d'int\u00e9gration et de bout en bout sont ex\u00e9cut\u00e9s.<\/li>\n<\/ul>\n<p>\nUniquement pour le code qui est inclus dans <code>master<\/code>, la proc\u00e9dure suivante est effectu\u00e9e :<\/p>\n<ul>\n<li>Tout ce qui a \u00e9t\u00e9 dit ci-dessus, plus\u2026<\/li>\n<li>Cr\u00e9ation de l'image Docker bas\u00e9e sur le code actuel, les configurations et l'environnement.<\/li>\n<li>Publication de l'image sur Docker Hub.<\/li>\n<li>Connexion au serveur de production.<\/li>\n<li>T\u00e9l\u00e9chargement de l'image depuis Docker Hub sur le serveur.<\/li>\n<li>Arr\u00eat du conteneur actuel et d\u00e9marrage d'un nouveau bas\u00e9 sur la nouvelle image.<\/li>\n<\/ul>\n<p>\nSi vous ne savez absolument rien sur Docker, les images et les conteneurs, ne vous inqui\u00e9tez pas. Je vais tout vous expliquer.<\/p>\n<h2>Qu'est-ce que le CI\/CD ?<\/h2>\n<p>\nL'acronyme CI\/CD signifie \u00ab continuous integration\/continuous deployment \u00bb \u2014 \u00ab int\u00e9gration continue\/deploiement continu \u00bb.<\/p>\n<h3>\u258dInt\u00e9gration continue<\/h3>\n<p>\nL'int\u00e9gration continue est le processus par lequel les d\u00e9veloppeurs effectuent des commits dans le d\u00e9p\u00f4t principal du code source du projet (g\u00e9n\u00e9ralement dans la branche <code>master<\/code>). La qualit\u00e9 du code est assur\u00e9e par des tests automatis\u00e9s.<\/p>\n<h3>\u258dD\u00e9ploiement continu<\/h3>\n<p>\nLe d\u00e9ploiement continu est un d\u00e9ploiement fr\u00e9quent et automatis\u00e9 du code en production. La deuxi\u00e8me partie de l'acronyme CI\/CD est parfois interpr\u00e9t\u00e9e comme \u00ab continuous delivery \u00bb (\u00ab livraison continue \u00bb). C'est, en gros, la m\u00eame chose que le \u00ab d\u00e9ploiement continu \u00bb, mais la \u00ab livraison continue \u00bb implique la n\u00e9cessit\u00e9 d'une validation manuelle des modifications avant de lancer le processus de d\u00e9ploiement du projet.<\/p>\n<h2>Commencer<\/h2>\n<p>\nL'application sur laquelle j'ai appris tout cela s'appelle <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/taniarascia\/takenote\">TakeNote<\/a><\/noindex>. C'est un projet web sur lequel je travaille, destin\u00e9 \u00e0 prendre des notes. Au d\u00e9but, j'ai essay\u00e9 de cr\u00e9er un <noindex><a rel=\"nofollow\" href=\"https:\/\/jamstack.org\/\">projet JAMStack<\/a><\/noindex>- ou une application frontale seule sans serveur, afin de profiter des capacit\u00e9s standard d'h\u00e9bergement et de d\u00e9ploiement de projets offertes par <noindex><a rel=\"nofollow\" href=\"https:\/\/www.netlify.com\/\">Netlify<\/a><\/noindex>. \u00c0 mesure que la complexit\u00e9 de l'application augmentait, j'ai d\u00fb cr\u00e9er sa partie serveur, ce qui signifiait que je devais \u00e9tablir ma propre strat\u00e9gie d'int\u00e9gration et de d\u00e9ploiement automatis\u00e9s du projet.<\/p>\n<p>Dans mon cas, l'application se compose d'un serveur Express fonctionnant dans l'environnement Node.js, servant une application React \u00e0 page unique et supportant une API serveur s\u00e9curis\u00e9e. Cette architecture suit une strat\u00e9gie que l'on peut trouver dans <noindex><a rel=\"nofollow\" href=\"https:\/\/www.taniarascia.com\/full-stack-cookies-localstorage-react-express\/\">ce<\/a><\/noindex> guide sur l'authentification full stack.<\/p>\n<p>J'ai consult\u00e9 <noindex><a rel=\"nofollow\" href=\"http:\/\/qualitytesting.tech\/\">un autre<\/a><\/noindex>, qui est un expert en automatisation, et je lui ai demand\u00e9 ce que je devais faire pour que tout cela fonctionne comme je le souhaite. Il m'a donn\u00e9 une id\u00e9e de la fa\u00e7on dont le flux de travail automatis\u00e9 devrait ressembler, comme d\u00e9crit dans la section \u00ab Objectifs \u00bb de cet article. Le fait que je me sois fix\u00e9 de tels objectifs signifiait que je devais comprendre comment utiliser Docker.<\/p>\n<h2>Docker<\/h2>\n<p>\nDocker est un outil qui, gr\u00e2ce \u00e0 la technologie de conteneurisation, permet de distribuer facilement des applications, ainsi que de les d\u00e9ployer et de les ex\u00e9cuter dans le m\u00eame environnement, m\u00eame si la plateforme Docker elle-m\u00eame fonctionne dans des environnements diff\u00e9rents. Pour commencer, j'avais besoin d'acc\u00e9der aux outils de ligne de commande (CLI) Docker. <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/install\/\">Instructions<\/a><\/noindex> d'installation de Docker ne peuvent pas \u00eatre consid\u00e9r\u00e9es comme tr\u00e8s claires et compr\u00e9hensibles, mais elles permettent de savoir que pour faire le premier pas dans l'installation, il faut t\u00e9l\u00e9charger Docker Desktop (pour Mac ou Windows).<\/p>\n<p>Docker Hub est \u00e0 peu pr\u00e8s la m\u00eame chose que <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/\">GitHub<\/a><\/noindex> pour les d\u00e9p\u00f4ts git, ou un registre <noindex><a rel=\"nofollow\" href=\"https:\/\/www.npmjs.com\/\">npm<\/a><\/noindex> pour les paquets JavaScript. C'est un d\u00e9p\u00f4t en ligne pour les images Docker. C'est \u00e0 lui que se connecte Docker Desktop.<\/p>\n<p>Ainsi, pour commencer \u00e0 travailler avec Docker, vous devez faire deux choses :<\/p>\n<ul>\n<li>Installez <noindex><a rel=\"nofollow\" href=\"https:\/\/www.docker.com\/get-started\">Docker Desktop<\/a><\/noindex>.<\/li>\n<li>Inscrivez-vous sur <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/\">Docker Hub<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>\nApr\u00e8s cela, vous pouvez v\u00e9rifier le bon fonctionnement de Docker CLI en ex\u00e9cutant la commande suivante pour v\u00e9rifier la version de Docker :<\/p>\n<pre><code class=\"plaintext\">docker -v<\/code><\/pre>\n<p>\nEnsuite, connectez-vous \u00e0 Docker Hub en saisissant, lorsque vous y \u00eates invit\u00e9, votre nom d'utilisateur et votre mot de passe :<\/p>\n<pre><code class=\"plaintext\">docker login<\/code><\/pre>\n<p>\nPour utiliser Docker, vous devez comprendre les concepts d'images et de conteneurs.<\/p>\n<h3>\u258dImages<\/h3>\n<p>\nUne image est en quelque sorte un plan contenant des instructions pour construire un conteneur. C'est un instantan\u00e9 immuable du syst\u00e8me de fichiers et des configurations de l'application. Les d\u00e9veloppeurs peuvent facilement \u00e9changer des images.<\/p>\n<pre><code class=\"plaintext\"># \u0412\u044b\u0432\u043e\u0434 \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u043e\u0431\u043e \u0432\u0441\u0435\u0445 \u043e\u0431\u0440\u0430\u0437\u0430\u0445\ndocker images<\/code><\/pre>\n<p>\nCette commande affichera un tableau avec le titre suivant :<\/p>\n<pre><code class=\"plaintext\">REPOSITORY \u00a0 \u00a0 TAG     IMAGE ID \u00a0 \u00a0 CREATED     SIZE\n---<\/code><\/pre>\n<p>\nEnsuite, nous examinerons quelques exemples de commandes dans ce m\u00eame format \u2014 d'abord vient la commande avec un commentaire, puis un exemple de ce qu'elle peut afficher.<\/p>\n<h3>\u258dConteneurs<\/h3>\n<p>\nUn conteneur est un paquet ex\u00e9cutable qui contient tout ce dont une application a besoin pour fonctionner. Avec cette approche, l'application fonctionne toujours de la m\u00eame mani\u00e8re, peu importe l'infrastructure : dans un environnement isol\u00e9 et dans le m\u00eame cadre. Il s'agit de l'ex\u00e9cution d'instances de la m\u00eame image dans diff\u00e9rents environnements.<\/p>\n<pre><code class=\"plaintext\"># \u041f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432\ndocker ps -a\nCONTAINER ID \u00a0 \u00a0 IMAGE     COMMAND \u00a0 \u00a0 CREATED     STATUS     PORTS \u00a0 \u00a0 NAMES\n---<\/code><\/pre>\n<p><\/p>\n<h3>\u258dTags<\/h3>\n<p>\nUne balise est une indication d'une version sp\u00e9cifique de l'image.<\/p>\n<h3>\u258dAper\u00e7u des commandes Docker<\/h3>\n<p>\nVoici un aper\u00e7u de certaines commandes Docker fr\u00e9quemment utilis\u00e9es.<\/p>\n<p>Commande<\/p>\n<p>Contexte<\/p>\n<p>Action<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/build\/\">docker build<\/a><\/noindex><\/p>\n<p>Image<\/p>\n<p>Construction de l'image \u00e0 partir du Dockerfile<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/tag\/\">docker tag<\/a><\/noindex><\/p>\n<p>Image<\/p>\n<p>Taguer l'image<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/images\/\">docker images<\/a><\/noindex><\/p>\n<p>Image<\/p>\n<p>Afficher la liste des images<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/run\/\">docker run<\/a><\/noindex><\/p>\n<p>Conteneur<\/p>\n<p>D\u00e9marrer un conteneur \u00e0 partir de l'image<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/push\/\">docker push<\/a><\/noindex><\/p>\n<p>Image<\/p>\n<p>Pousser l'image dans le registre<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/about:blank\">docker pull<\/a><\/noindex><\/p>\n<p>Image<\/p>\n<p>Tirer l'image du registre<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/ps\/\">docker ps<\/a><\/noindex><\/p>\n<p>Conteneur<\/p>\n<p>Afficher la liste des conteneurs<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/system_prune\/\">docker system prune<\/a><\/noindex><\/p>\n<p>Image\/Conteneur<\/p>\n<p>Supprimer les conteneurs et images inutilis\u00e9s<\/p>\n<h3>\u258dFichier Dockerfile<\/h3>\n<p>\nJe sais comment ex\u00e9cuter une application localement pour la production. J'ai une configuration Webpack con\u00e7ue pour construire une application React pr\u00eate \u00e0 l'emploi. Ensuite, j'ai une commande qui lance un serveur bas\u00e9 sur Node.js sur le port <code>5000<\/code>. Cela ressemble \u00e0 ceci :<\/p>\n<pre><code class=\"plaintext\">npm i \u00a0 \u00a0 \u00a0 \u00a0 # installation des d\u00e9pendances\nnpm run build # construction de l'application React\nnpm run start # d\u00e9marrer le serveur Node<\/code><\/pre>\n<p>\nIl est important de noter que je n'ai pas d'application exemple pour ce mat\u00e9riel. Mais ici, pour faire des exp\u00e9riences, n'importe quelle simple application Node fera l'affaire.<\/p>\n<p>Pour utiliser le conteneur, vous devrez donner des instructions \u00e0 Docker. Cela se fait via un fichier appel\u00e9 <code>Dockerfile<\/code>, situ\u00e9 dans le r\u00e9pertoire racine du projet. Ce fichier peut sembler assez incompr\u00e9hensible au d\u00e9part.<\/p>\n<p>Mais ce qu'il contient ne fait que d\u00e9crire, avec des commandes sp\u00e9cifiques, quelque chose de similaire \u00e0 la configuration d'un environnement de travail. Voici quelques-unes de ces commandes :<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#from\">DE<\/a><\/noindex> \u2014 Cette commande commence le fichier. Elle sp\u00e9cifie l'image de base sur laquelle le conteneur sera construit.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#copy\">COPY<\/a><\/noindex> \u2014 Copier des fichiers d'une source locale dans le conteneur.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#workdir\">WORKDIR<\/a><\/noindex> \u2014 D\u00e9finir le r\u00e9pertoire de travail pour les commandes suivantes.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#run\">RUN<\/a><\/noindex> \u2014 Ex\u00e9cuter des commandes.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#expose\">EXPOSE<\/a><\/noindex> \u2014 Configurer le port.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#entrypoint\">ENTRYPOINT<\/a><\/noindex> \u2014 Sp\u00e9cifier la commande \u00e0 ex\u00e9cuter.<\/li>\n<\/ul>\n<p>\n<code>Dockerfile<\/code> peut ressembler \u00e0 ceci :<\/p>\n<pre><code class=\"plaintext\"># \u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437\nFROM node:12-alpine\n\n# \u0421\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e app\/\nCOPY . app\/\n\n# \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c app\/ \u0432 \u0440\u043e\u043b\u0438 \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438\nWORKDIR app\/\n\n# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 (\u043a\u043e\u043c\u0430\u043d\u0434\u0430 npm ci \u043f\u043e\u0445\u043e\u0436\u0430 npm i, \u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0441\u0431\u043e\u0440\u043e\u043a)\nRUN npm ci --only-production\n\n# \u0421\u043e\u0431\u0440\u0430\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0435 React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d\u0430\nRUN npm run build\n\n# \u041f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0440\u0442\nEXPOSE 5000\n\n# \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c Node-\u0441\u0435\u0440\u0432\u0435\u0440\nENTRYPOINT npm run start<\/code><\/pre>\n<p>\nSelon l'image de base choisie, vous devrez peut-\u00eatre installer des d\u00e9pendances suppl\u00e9mentaires. En effet, certaines images de base (comme Node Alpine Linux) sont con\u00e7ues pour \u00eatre aussi compactes que possible. Par cons\u00e9quent, elles peuvent manquer de certains programmes auxquels vous vous attendez.<\/p>\n<h3>\u258dConstruction, \u00e9tiquetage et lancement d'un conteneur<\/h3>\n<p>\nLa construction et le lancement locaux du conteneur \u2013 c'est, apr\u00e8s avoir obtenu <code>Dockerfile<\/code>, les t\u00e2ches sont assez simples. Avant d'envoyer l'image sur Docker Hub, elle doit \u00eatre test\u00e9e localement.<\/p>\n<h3>\u258dConstruction<\/h3>\n<p>\nTout d'abord, vous devez construire <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/build\/\">image<\/a><\/noindex>, en sp\u00e9cifiant un nom, et, si vous le souhaitez, un tag (si le tag n'est pas sp\u00e9cifi\u00e9, le syst\u00e8me attribuera automatiquement un tag \u00e0 l'image. <code>latest<\/code>).<\/p>\n<pre><code class=\"plaintext\"># \u0421\u0431\u043e\u0440\u043a\u0430 \u043e\u0431\u0440\u0430\u0437\u0430\ndocker build -t &lt;image&gt;:&lt;tag&gt; .<\/code><\/pre>\n<p>\nApr\u00e8s l'ex\u00e9cution de cette commande, vous pouvez observer comment Docker construit l'image.<\/p>\n<pre><code class=\"plaintext\">Envoi du contexte de construction au d\u00e9mon Docker \u00a0 2.88MB\n\u00c9tape 1\/9 : FROM node:12-alpine\n\u00a0---&gt; ...ex\u00e9cution des \u00e9tapes de construction...\nConstruite avec succ\u00e8s 123456789123\n\u00c9tiquet\u00e9e avec succ\u00e8s &lt;image&gt;:&lt;tag&gt;<\/code><\/pre>\n<p>\nLa construction peut prendre quelques minutes \u2013 cela d\u00e9pend des d\u00e9pendances que vous avez. Une fois la construction termin\u00e9e, vous pouvez ex\u00e9cuter la commande <code>docker images<\/code> et voir la description de votre nouvelle image.<\/p>\n<pre><code class=\"plaintext\">R\u00c9PERTOIRE\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 TAG               ID D'IMAGE\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 CR\u00c9\u00c9E              TAILLE\n&lt;image&gt; \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 latest            123456789123\u00a0 \u00a0 \u00a0 \u00a0 Il y a environ une minute   x.xxGB<\/code><\/pre>\n<p><\/p>\n<h3>\u258dLancement<\/h3>\n<p>\nL'image est cr\u00e9\u00e9e. Cela signifie qu'il est possible de lancer un conteneur \u00e0 partir de celle-ci. Comme je veux pouvoir acc\u00e9der \u00e0 l'application qui fonctionne dans le conteneur \u00e0 l'adresse <code>localhost:5000<\/code>, dans la partie gauche de la paire <code>5000:5000<\/code> j'ai d\u00e9fini dans la commande suivante. <code>5000<\/code>. Dans la partie droite se trouve le port du conteneur.<\/p>\n<pre><code class=\"plaintext\"># \u0417\u0430\u043f\u0443\u0441\u043a \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u0442\u0430 5000 \u0438 \u043f\u043e\u0440\u0442\u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 5000\ndocker run -p 5000:5000 &lt;image&gt;:&lt;tag&gt;<\/code><\/pre>\n<p>\nMaintenant que le conteneur est cr\u00e9\u00e9 et lanc\u00e9, vous pouvez utiliser la commande <code>docker ps<\/code> pour voir les informations sur ce conteneur (ou vous pouvez utiliser la commande <code>docker ps -a<\/code>, qui affiche les informations sur tous les conteneurs, et pas seulement ceux qui sont en cours d'ex\u00e9cution).<\/p>\n<pre><code class=\"plaintext\">IDENTIFIANT DE CONTAINER        IMAGE               COMMANDE                     CR\u00c9\u00c9E              \u00c9TAT                   PORTS                     NOMS\n987654321234                           \"\\\/bin\\\/sh -c 'npm run\u2026\"   il y a 6 secondes        En cours depuis 6 secondes             0.0.0.0:5000-&gt;5000\\\/tcp   stoic_darwin<\/code><\/pre>\n<p>\nSi vous allez maintenant \u00e0 l'adresse <code>localhost:5000<\/code> \u2013 vous pouvez voir la page de l'application en cours d'ex\u00e9cution, qui ressemble exactement \u00e0 la page de l'application en production.<\/p>\n<h3>\u258dAttribution de tag et publication<\/h3>\n<p>\nPour utiliser l'une des images cr\u00e9\u00e9es sur le serveur de production, nous devons avoir la possibilit\u00e9 de t\u00e9l\u00e9charger cette image depuis Docker Hub. Cela signifie qu'il faut d'abord cr\u00e9er un d\u00e9p\u00f4t sur Docker Hub pour le projet. Ensuite, nous disposerons d'un endroit o\u00f9 nous pourrons envoyer l'image. L'image doit \u00eatre renomm\u00e9e de mani\u00e8re \u00e0 ce que son nom commence par notre nom d'utilisateur sur Docker Hub. Apr\u00e8s cela, doit suivre le nom du d\u00e9p\u00f4t. \u00c0 la fin du nom, il peut y avoir n'importe quelle \u00e9tiquette. Voici un exemple de nomenclature des images selon ce sch\u00e9ma.<\/p>\n<p>Nous pouvons maintenant construire l'image en lui attribuant un nouveau nom et ex\u00e9cuter la commande <code>docker push<\/code> pour l'envoyer au d\u00e9p\u00f4t Docker Hub.<\/p>\n<pre><code class=\"plaintext\">docker build -t \\\/: .\ndocker tag \\\/: \\\/:latest\ndocker push \\\/:\n\n# En pratique, cela pourrait ressembler \u00e0 cela :\ndocker build -t user\\\/app:v1.0.0 .\ndocker tag user\\\/app:v1.0.0 user\\\/app:latest\ndocker push user\\\/app:v1.0.0<\/code><\/pre>\n<p>\nSi tout se passe bien, l'image sera disponible sur Docker Hub et pourra \u00eatre facilement t\u00e9l\u00e9charg\u00e9e sur le serveur ou transmise \u00e0 d'autres d\u00e9veloppeurs.<\/p>\n<h2>Prochaines \u00e9tapes<\/h2>\n<p>\n\u00c0 ce stade, nous avons confirm\u00e9 que l'application, sous forme de conteneur Docker, fonctionne localement. Nous avons t\u00e9l\u00e9charg\u00e9 le conteneur sur Docker Hub. Tout cela signifie que nous avons d\u00e9j\u00e0 bien progress\u00e9 vers notre objectif. Maintenant, nous devons r\u00e9soudre deux autres questions :<\/p>\n<ul>\n<li>Configuration de l'outil CI pour tester et d\u00e9ployer le code.<\/li>\n<li>Configuration du serveur de production afin qu'il puisse t\u00e9l\u00e9charger et ex\u00e9cuter notre code.<\/li>\n<\/ul>\n<p>\nDans notre cas, nous utilisons comme solution CI\/CD <noindex><a rel=\"nofollow\" href=\"https:\/\/travis-ci.org\/\">Travis CI<\/a><\/noindex>. Comme serveur - <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/\">DigitalOcean<\/a><\/noindex>.<\/p>\n<p>Il convient de noter qu'il est \u00e9galement possible d'utiliser une autre combinaison de services. Par exemple, au lieu de Travis CI, on peut utiliser CircleCI ou Github Actions. Et au lieu de DigitalOcean - AWS ou Linode.<\/p>\n<p>Nous avons d\u00e9cid\u00e9 de travailler avec Travis CI, et pour ce service, j'ai d\u00e9j\u00e0 configur\u00e9 certaines choses. Je vais donc bri\u00e8vement expliquer comment le pr\u00e9parer au travail.<\/p>\n<h2>Travis CI<\/h2>\n<p>\nTravis CI est un outil pour tester et d\u00e9ployer le code. Je ne voudrais pas entrer dans les d\u00e9tails de la configuration de Travis CI, car chaque projet est unique, et cela n'apportera pas de b\u00e9n\u00e9fice particulier. Mais je vais parler des bases qui vous permettront de commencer \u00e0 travailler si vous d\u00e9cidez d'utiliser Travis CI. Quoi que vous choisissiez - Travis CI, CircleCI, Jenkins, ou autre, des m\u00e9thodes de configuration similaires s'appliqueront.<\/p>\n<p>Pour commencer \u00e0 travailler avec Travis CI, rendez-vous sur <noindex><a rel=\"nofollow\" href=\"https:\/\/travis-ci.org\/\">du projet<\/a><\/noindex> et cr\u00e9ez un compte. Ensuite, int\u00e9grez Travis CI avec votre compte GitHub. Au cours de la configuration du syst\u00e8me, vous devrez sp\u00e9cifier le d\u00e9p\u00f4t avec lequel vous souhaitez automatiser le travail et lui donner acc\u00e8s. (J'utilise GitHub, mais je suis s\u00fbre que Travis CI peut \u00e9galement s'int\u00e9grer \u00e0 BitBucket, GitLab, et d'autres services similaires).<\/p>\n<p>Chaque fois que Travis CI commence \u00e0 travailler, un serveur est lanc\u00e9 pour ex\u00e9cuter les commandes sp\u00e9cifi\u00e9es dans le fichier de configuration, y compris le d\u00e9ploiement des branches correspondantes du d\u00e9p\u00f4t.<\/p>\n<h3>\u258dCycle de vie de la t\u00e2che<\/h3>\n<p>\nLe fichier de configuration de Travis CI, appel\u00e9 <code>.travis.yml<\/code> et stock\u00e9 dans le r\u00e9pertoire racine du projet, maintient le concept d'\u00e9v\u00e9nements <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.travis-ci.com\/user\/job-lifecycle\/\">dur\u00e9e de vie<\/a><\/noindex> de t\u00e2che. Voici ces \u00e9v\u00e9nements, pr\u00e9sent\u00e9s dans l'ordre o\u00f9 ils se produisent :<\/p>\n<ul>\n<li><code>apt addons<\/code><\/li>\n<li><code>cache components<\/code><\/li>\n<li><code>before_install<\/code><\/li>\n<li><code>install<\/code><\/li>\n<li><code>before_script<\/code><\/li>\n<li><code>script<\/code><\/li>\n<li><code>before_cache<\/code><\/li>\n<li><code>after_success ou after_failure<\/code><\/li>\n<li><code>before_deploy<\/code><\/li>\n<li><code>deploy<\/code><\/li>\n<li><code>after_deploy<\/code><\/li>\n<li><code>after_script<\/code><\/li>\n<\/ul>\n<p><\/p>\n<h3>\u258dTests<\/h3>\n<p>\nDans le fichier de configuration, je vais configurer un serveur local Travis CI. J'ai choisi le langage Node 12 et j'ai indiqu\u00e9 au syst\u00e8me d'installer les d\u00e9pendances n\u00e9cessaires pour utiliser Docker.<\/p>\n<p>Tout ce qui est \u00e9num\u00e9r\u00e9 dans <code>.travis.yml<\/code>, sera ex\u00e9cut\u00e9 lors de l'ex\u00e9cution de toutes les pull requests pour toutes les branches du d\u00e9p\u00f4t, sauf indication contraire. C'est une fonctionnalit\u00e9 utile car cela signifie que nous pouvons tester tout le code entrant dans le d\u00e9p\u00f4t. Cela permet de savoir si le code est pr\u00eat \u00e0 \u00eatre enregistr\u00e9 dans la branche <code>master<\/code>, et s'il ne perturbera pas le processus de construction du projet. Dans cette configuration globale, j'installe tout localement, lance le serveur de d\u00e9veloppement Webpack en arri\u00e8re-plan (c'est une fonctionnalit\u00e9 de mon flux de travail) et ex\u00e9cute les tests.<\/p>\n<p>Si vous souhaitez que votre d\u00e9p\u00f4t affiche des badges avec des informations sur la couverture de code des tests, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.taniarascia.com\/display-build-status-and-test-coverage\/\">ici<\/a><\/noindex> vous pouvez trouver un guide succinct sur l'utilisation de Jest, Travis CI et Coveralls pour rassembler et afficher ces informations.<\/p>\n<p>Alors, voici le contenu du fichier <code>.travis.yml<\/code>:<\/p>\n<pre><code class=\"plaintext\"># \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u044f\u0437\u044b\u043a\nlanguage: node_js\n\n# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u044e Node.js\nnode_js:\n\u00a0\u00a0- '12'\n\nservices:\n\u00a0\u00a0# \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 Docker\n\u00a0\u00a0- docker\n\ninstall:\n\u00a0\u00a0# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432\n\u00a0\u00a0- npm ci\n\nbefore_script:\n\u00a0\u00a0# \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432\n\u00a0\u00a0- npm run dev &amp;\n\nscript:\n\u00a0\u00a0# \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b\n\u00a0\u00a0- npm run test<\/code><\/pre>\n<p>\nIci se terminent les actions qui sont effectu\u00e9es pour toutes les branches du d\u00e9p\u00f4t et pour les pull requests.<\/p>\n<h3>\u258dD\u00e9ploiement<\/h3>\n<p>\nEn supposant que tous les tests automatis\u00e9s se soient d\u00e9roul\u00e9s avec succ\u00e8s, nous pouvons, sans obligation, d\u00e9ployer le code sur le serveur de production. Comme nous souhaitons le faire uniquement pour le code de la branche <code>master<\/code>, nous donnons au syst\u00e8me des instructions appropri\u00e9es dans les param\u00e8tres de d\u00e9ploiement. Avant que vous n'essayiez d'utiliser dans votre projet le code que nous allons examiner plus loin, je voudrais vous avertir qu'il vous faut un v\u00e9ritable script appel\u00e9 pour le d\u00e9ploiement.<\/p>\n<pre><code class=\"plaintext\">deploy:\n\u00a0\u00a0# Construire le conteneur Docker et l'envoyer sur Docker Hub\n\u00a0\u00a0provider: script\n\u00a0\u00a0script: bash deploy.sh\n\u00a0\u00a0on:\n\u00a0\u00a0\u00a0\u00a0branch: master<\/code><\/pre>\n<p>\nLe script de d\u00e9ploiement remplit deux t\u00e2ches :<\/p>\n<ul>\n<li>La construction, le tagging et l'envoi de l'image sur Docker Hub \u00e0 l'aide de l'outil CI (dans notre cas, c'est Travis CI).<\/li>\n<li>Le t\u00e9l\u00e9chargement de l'image sur le serveur, l'arr\u00eat de l'ancien conteneur et le d\u00e9marrage du nouveau (dans notre cas, le serveur fonctionne sur la plateforme DigitalOcean).<\/li>\n<\/ul>\n<p>\nTout d'abord, il faut configurer le processus automatique de construction, de tagging et d'envoi de l'image sur Docker Hub. Tout cela ressemble beaucoup \u00e0 ce que nous avons d\u00e9j\u00e0 fait manuellement, sauf que nous avons besoin ici d'une strat\u00e9gie pour attribuer des tags uniques aux images et d'automatiser la connexion. J'ai eu des difficult\u00e9s avec certains d\u00e9tails du script de d\u00e9ploiement, comme la strat\u00e9gie de tagging, la connexion, l'encodage des cl\u00e9s SSH, l'\u00e9tablissement de la connexion SSH. Mais, heureusement, mon petit ami s'en sort tr\u00e8s bien avec bash, ainsi qu'avec beaucoup d'autres choses. Il m'a aid\u00e9 \u00e0 \u00e9crire ce script.<\/p>\n<p>Ainsi, la premi\u00e8re partie du script consiste \u00e0 envoyer l'image sur Docker Hub. C'est assez simple \u00e0 faire. Le sch\u00e9ma de tagging que j'utilise implique de combiner le hash git et un tag git, si celui-ci existe. Cela permet de cr\u00e9er un tag unique et facilite l'identification de la build sur laquelle il est bas\u00e9. <code>DOCKER_USERNAME<\/code> et <code>DOCKER_PASSWORD<\/code> \u2014 ce sont des variables d'environnement personnalis\u00e9es que l'on peut d\u00e9finir dans l'interface de Travis CI. Travis CI traite automatiquement les donn\u00e9es sensibles afin qu'elles ne tombent pas entre de mauvaises mains.<\/p>\n<p>Voici la premi\u00e8re partie du script <code>deploy.sh<\/code>.<\/p>\n<pre><code class=\"plaintext\">#!\/bin\/sh\nset -e # \u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u043e\u0448\u0438\u0431\u043e\u043a\n\nIMAGE=&quot;&lt;username&gt;\/&lt;repository&gt;&quot; \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 # \u041e\u0431\u0440\u0430\u0437 Docker\nGIT_VERSION=$(git describe --always --abbrev --tags --long) # Git-\u0445\u044d\u0448 \u0438 \u0442\u0435\u0433\u0438\n\n# \u0421\u0431\u043e\u0440\u043a\u0430 \u0438 \u0442\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0437\u0430\ndocker build -t ${IMAGE}:${GIT_VERSION} .\ndocker tag ${IMAGE}:${GIT_VERSION} ${IMAGE}:latest\n\n# \u0412\u0445\u043e\u0434 \u0432 Docker Hub \u0438 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u043e\u0431\u0440\u0430\u0437\u0430\necho &quot;${DOCKER_PASSWORD}&quot; | docker login -u &quot;${DOCKER_USERNAME}&quot; --password-stdin\ndocker push ${IMAGE}:${GIT_VERSION}<\/code><\/pre>\n<p>\nLa mani\u00e8re dont sera la deuxi\u00e8me partie du script d\u00e9pend enti\u00e8rement de l'h\u00f4te que vous utilisez et de la fa\u00e7on dont la connexion est organis\u00e9e. Dans mon cas, puisque j'utilise Digital Ocean, les commandes utilis\u00e9es pour se connecter au serveur sont <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/digitalocean\/doctl\">doctl<\/a><\/noindex>. Lorsqu'on travaille avec AWS, l'outil utilis\u00e9 sera <code>aws<\/code>, et ainsi de suite.<\/p>\n<p>Configurer le serveur n'\u00e9tait pas particuli\u00e8rement difficile. J'ai configur\u00e9 un droplet bas\u00e9 sur une image de base. Il convient de noter que le syst\u00e8me que j'ai choisi n\u00e9cessite une installation manuelle unique de Docker et un lancement manuel unique de Docker. J'ai utilis\u00e9 Ubuntu 18.04 pour installer Docker, donc si vous utilisez \u00e9galement Ubuntu, vous pouvez simplement suivre <noindex><a rel=\"nofollow\" href=\"https:\/\/phoenixnap.com\/kb\/how-to-install-docker-on-ubuntu-18-04\">ceci<\/a><\/noindex> un guide simple.<\/p>\n<p>Je ne parle pas ici des commandes sp\u00e9cifiques au service, car cet aspect peut varier consid\u00e9rablement selon les cas. Je vais simplement fournir un plan g\u00e9n\u00e9ral d'action \u00e0 r\u00e9aliser apr\u00e8s s'\u00eatre connect\u00e9 par SSH au serveur sur lequel le projet sera d\u00e9ploy\u00e9 :<\/p>\n<ul>\n<li>Vous devez trouver le conteneur actuellement en cours d'ex\u00e9cution et l'arr\u00eater.<\/li>\n<li>Ensuite, vous devez lancer un nouveau conteneur en arri\u00e8re-plan.<\/li>\n<li>Vous devrez d\u00e9finir le port local du serveur \u00e0 <code>80<\/code> \u2014 cela vous permettra d'acc\u00e9der au site \u00e0 une adresse du type <code>example.com<\/code>, sans indiquer le port, au lieu d'utiliser une adresse comme <code>example.com:5000<\/code>.<\/li>\n<li>Et enfin, il faut supprimer tous les anciens conteneurs et images.<\/li>\n<\/ul>\n<p>\nVoici la suite du script.<\/p>\n<pre><code class=\"plaintext\"># \u041d\u0430\u0439\u0442\u0438 ID \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\nCONTAINER_ID=$(docker ps | grep takenote | cut -d&quot; &quot; -f1)\n\n# \u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0442\u0430\u0440\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439, \u043e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0443\ndocker stop ${CONTAINER_ID}\ndocker run --restart unless-stopped -d -p 80:5000 ${IMAGE}:${GIT_VERSION}\ndocker system prune -a -f<\/code><\/pre>\n<p><\/p>\n<h2>Quelques \u00e9l\u00e9ments \u00e0 consid\u00e9rer<\/h2>\n<p>\nIl se peut que lorsque vous vous connectiez au serveur par SSH depuis Travis CI, vous rencontriez un avertissement qui emp\u00eachera la poursuite de l'installation, car le syst\u00e8me attendra la r\u00e9action de l'utilisateur.<\/p>\n<pre><code class=\"plaintext\">L'authenticit\u00e9 de l'h\u00f4te '&lt;hostname&gt; (&lt;IP address&gt;)' ne peut pas \u00eatre \u00e9tablie.\nL\u2019empreinte de la cl\u00e9 RSA est &lt;key fingerprint&gt;.\n\u00cates-vous s\u00fbr de vouloir continuer \u00e0 vous connecter (oui\/non) ?<\/code><\/pre>\n<p>\nJ'ai d\u00e9couvert qu'une cl\u00e9 de cha\u00eene peut \u00eatre cod\u00e9e en base64 afin de la conserver sous une forme qui permet de la manipuler facilement et en toute s\u00e9curit\u00e9. Au stade de l'installation, vous pouvez d\u00e9coder la cl\u00e9 publique et l'enregistrer dans le fichier <code>known_hosts<\/code> afin d'\u00e9viter l'erreur d\u00e9crite ci-dessus.<\/p>\n<pre><code class=\"plaintext\">echo &lt;public key&gt; | base64 # affiche &lt;cl\u00e9 publique cod\u00e9e en base64&gt;<\/code><\/pre>\n<p>\nEn pratique, cette commande pourrait ressembler \u00e0 ceci :<\/p>\n<pre><code class=\"plaintext\">echo \"123.45.67.89 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom\\\/BWDSU\nGPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3\nPbv7kOdJ\\\/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK\\\/7XA\nt3FaoJoAsncM1Q9x5+3V0Ww68\\\/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw\\\/Pb0rwert\\\/En\nmZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z\\\/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx\nNrRFi9wrf+M7Q== you@example.com\" | base64<\/code><\/pre>\n<p>\nVoici \u00e0 quoi ressemble la sortie \u2014 une cha\u00eene encod\u00e9e en base64 :<\/p>\n<pre><code class=\"plaintext\">MTIzLjQ1LjY3Ljg5IHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQUJJd0FBQVFFQWtsT1Vwa0RIcmZIWTE3U2JybVRJcE5MVEdLOVRqb20vQldEU1UKR1BsK25hZnpsSERUWVc3aGRJNHlaNWV3MThKSDRKVzlqYmhVRnJ2aVF6TTd4bEVMRVZmNGg5bEZYNVFWa2JQcHBTd2cwY2RhMwpQYnY3a09kSi9NVHlCbFdYRkNSK0hBbzNGWFJpdEJxeGlYMW5LaFhwSEFac01jaUxxOFY2UmpzTkFRd2RzZE1GdlNsVksvN1hBCnQzRmFvSm9Bc25jTTFROXg1KzNWMFd3NjgvZUlGbWIxenVVRmxqUUpLcHJyWDg4WHlwTkR2allOYnk2dncvUGIwcndlcnQvRW4KbVorQVc0T1pQblRQSTg5WlBtVk1MdWF5ckQyY0U4NlovaWw4YitndzNyMysxbkthdG1Ja2puMnNvMWQwMVFyYVRsTXFWU3NieApOclJGaTl3cmYrTTdRPT0geW91QGV4YW1wbGUuY29tCg==<\/code><\/pre>\n<p>\nVoici la commande mentionn\u00e9e ci-dessus<\/p>\n<pre><code class=\"plaintext\">install:\n  - echo  | base64 -d &gt;&gt; $HOME\/.ssh\/known_hosts<\/code><\/pre>\n<p>\nLa m\u00eame approche peut \u00eatre utilis\u00e9e avec une cl\u00e9 priv\u00e9e lors de l'\u00e9tablissement de la connexion, car vous pourriez avoir besoin de la cl\u00e9 priv\u00e9e pour acc\u00e9der au serveur. Lorsque vous travaillez avec la cl\u00e9, il vous suffit de la conserver en toute s\u00e9curit\u00e9 dans une variable d'environnement Travis CI et de vous assurer qu'elle n'est pas affich\u00e9e.<\/p>\n<p>Une autre chose \u00e0 noter est que vous pourriez avoir besoin d'ex\u00e9cuter tout le script de d\u00e9ploiement pr\u00e9sent\u00e9 sous forme d'une seule ligne, par exemple \u2014 en utilisant <code>doctl<\/code>. Cela peut n\u00e9cessiter quelques efforts suppl\u00e9mentaires.<\/p>\n<pre><code class=\"plaintext\">doctl compute ssh  --ssh-command \"toutes les commandes seront ici &amp;&amp; l\u00e0\"<\/code><\/pre>\n<p><\/p>\n<h2>TLS\/SSL et r\u00e9partition de charge<\/h2>\n<p>\nApr\u00e8s avoir fait tout ce qui a \u00e9t\u00e9 mentionn\u00e9 ci-dessus, le dernier probl\u00e8me auquel j'\u00e9tais confront\u00e9e \u00e9tait que le serveur n'avait pas de SSL. \u00c9tant donn\u00e9 que j'utilise un serveur Node.js, il faut que <noindex><a rel=\"nofollow\" href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/how-to-secure-a-containerized-node-js-application-with-nginx-let-s-encrypt-and-docker-compose\">\u00e0 travailler<\/a><\/noindex> un proxy inverse Nginx et Let's Encrypt, cela n\u00e9cessite pas mal d'efforts.<\/p>\n<p>Je n'avais vraiment pas envie de faire toutes ces configurations SSL manuellement, alors j'ai simplement cr\u00e9\u00e9 un \u00e9quilibreur de charge et enregistr\u00e9 ses informations dans le DNS. Dans le cas de DigitalOcean, par exemple, cr\u00e9er un certificat auto-sign\u00e9 qui se renouvelle automatiquement sur l'\u00e9quilibreur de charge est une proc\u00e9dure simple, gratuite et rapide. Cette approche a \u00e9galement l'avantage d'une configuration tr\u00e8s simple du SSL sur plusieurs serveurs derri\u00e8re l'\u00e9quilibreur de charge. Cela permet aux serveurs de ne pas avoir \u00e0 \u00ab s'inqui\u00e9ter \u00bb du SSL, tout en utilisant le port <code>80<\/code>. Ainsi, la configuration du SSL sur l'\u00e9quilibreur de charge est beaucoup plus simple et pratique que les m\u00e9thodes alternatives.<\/p>\n<p>Vous pouvez maintenant fermer tous les ports sur le serveur acceptant des connexions entrantes \u2014 sauf le port <code>80<\/code>, utilis\u00e9 pour la connexion \u00e0 l'\u00e9quilibreur de charge, et le port <code>22<\/code> pour SSH. En cons\u00e9quence, toute tentative d'acc\u00e8s direct au serveur via d'autres ports, \u00e0 l'exception de ces deux, \u00e9chouera.<\/p>\n<h2>R\u00e9sultats<\/h2>\n<p>\nApr\u00e8s avoir fait tout ce que j'ai d\u00e9crit dans cet article, je ne suis plus intimid\u00e9e ni par la plateforme Docker ni par les concepts des cha\u00eenes CI\/CD automatis\u00e9es. J'ai pu configurer une cha\u00eene d'int\u00e9gration continue, au cours de laquelle le code est test\u00e9 avant son d\u00e9ploiement en production et d\u00e9ploy\u00e9 automatiquement sur le serveur. Tout cela est encore relativement nouveau pour moi, et je suis convaincue qu'il existe des moyens d'am\u00e9liorer mon flux de travail automatis\u00e9 et de le rendre plus efficace. Donc, si vous avez des id\u00e9es \u00e0 ce sujet, faites-le moi savoir. <noindex><a rel=\"nofollow\" href=\"mailto:hello@taniarascia.com\">moi<\/a><\/noindex> J'esp\u00e8re que cet article vous a \u00e9t\u00e9 utile. Je veux croire qu'en le lisant, vous avez appris autant que moi en explorant tout ce dont j'ai parl\u00e9.<\/p>\n<p><b>P.S.<\/b> Dans notre <noindex><a rel=\"nofollow\" href=\"https:\/\/ruvds.com\/ru-rub\/marketplace#order\">sur le marketplace<\/a><\/noindex> il y a une image <noindex><a rel=\"nofollow\" href=\"https:\/\/ruvds.com\/ru-rub\/marketplace\/docker#advantages\">Docker<\/a><\/noindex>, qui s'installe en un clic. Vous pouvez v\u00e9rifier le fonctionnement des conteneurs sur <noindex><a rel=\"nofollow\" href=\"https:\/\/ruvds.com\/\">VPS<\/a><\/noindex>. Tous les nouveaux clients se voient offrir 3 jours gratuits pour des tests.<\/p>\n<p><b>Chers lecteurs !<\/b> Utilisez-vous des technologies CI\/CD dans vos projets ?<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/ruvds.com\/ru-rub\/#order\"><img decoding=\"async\" alt=\"Cr\u00e9ation d&#039;une cha\u00eene CI\/CD et automatisation du travail avec Docker.\" src=\"\/wp-content\/uploads\/2020\/02\/3fbfa90ea56a3d9b6b89ba945eb94570.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<br \/>Source : <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/488668\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u042f \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0430 \u043c\u043e\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0430\u0439\u0442\u044b \u0432 \u043a\u043e\u043d\u0446\u0435 90-\u0445. \u0422\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u0438\u0445 \u0432 \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e. \u0411\u044b\u043b Apache-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 \u043a\u0430\u043a\u043e\u043c-\u043d\u0438\u0431\u0443\u0434\u044c \u043e\u0431\u0449\u0435\u043c \u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0435, \u043d\u0430 \u044d\u0442\u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u043e\u0439\u0442\u0438 \u043f\u043e FTP, \u043d\u0430\u043f\u0438\u0441\u0430\u0432 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u043d\u0435\u0447\u0442\u043e \u0432\u0440\u043e\u0434\u0435 ftp:\/\/ftp.example.com. \u041f\u043e\u0442\u043e\u043c \u043d\u0430\u0434\u043e \u0431\u044b\u043b\u043e \u0432\u0432\u0435\u0441\u0442\u0438 \u0438\u043c\u044f \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u0438 \u0432\u044b\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440. \u0414\u0440\u0443\u0433\u0438\u0435 \u0431\u044b\u043b\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0430, \u0432\u0441\u0451 \u0442\u043e\u0433\u0434\u0430 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":69352,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-69351","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u042f \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0430 \u043c\u043e\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0430\u0439\u0442\u044b \u0432 \u043a\u043e\u043d\u0446\u0435 90-\u0445. \u0422\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u0438\u0445 \u0432 \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/sozdanie-ci-cd-czepochki-i-avtomatizacziya-raboty-s-docker\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"fr_FR\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 CI\/CD-\u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Docker | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u042f \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0430 \u043c\u043e\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0430\u0439\u0442\u044b \u0432 \u043a\u043e\u043d\u0446\u0435 90-\u0445. \u0422\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u0438\u0445 \u0432 \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/sozdanie-ci-cd-czepochki-i-avtomatizacziya-raboty-s-docker\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-02-18T11:44:06+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-03-03T13:15:00+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Cr\u00e9ation d'une cha\u00eene CI\/CD et automatisation du travail avec Docker | ProHoster","description":"J'ai cr\u00e9\u00e9 mes premiers sites \u00e0 la fin des ann\u00e9es 90. \u00c0 l'\u00e9poque, il \u00e9tait tr\u00e8s simple de les mettre en service.","canonical_url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/sozdanie-ci-cd-czepochki-i-avtomatizacziya-raboty-s-docker","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"fr_FR","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 CI\/CD-\u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Docker | ProHoster","og:description":"\u042f \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0430 \u043c\u043e\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0430\u0439\u0442\u044b \u0432 \u043a\u043e\u043d\u0446\u0435 90-\u0445. \u0422\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u0438\u0445 \u0432 \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e.","og:url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/sozdanie-ci-cd-czepochki-i-avtomatizacziya-raboty-s-docker","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-02-18T11:44:06+00:00","article:modified_time":"2020-03-03T13:15:00+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"69351","title":null,"description":null,"keywords":null,"keyphrases":{"focus":[],"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 19:24:45","updated":"2026-08-11 12:50:24","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/69351","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/comments?post=69351"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/69351\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media\/69352"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media?parent=69351"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/categories?post=69351"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/tags?post=69351"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}