UNPKG

nodebook

Version:

Node.js • Apprendre par la pratique. Familiarisez-vous avec JavaScript, Node.js et l'écosystème de modules npm. Apprenez à concevoir et à déployer des *applications web* et des *outils en ligne de commande*.

1,468 lines (1,387 loc) 170 kB
<!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="generator" content="Asciidoctor 2.0.9"> <title>Déployer notre&#160;code</title> <style> #header, #content, #footer { margin: 2rem auto; max-width: 46rem; } #header { margin-top: 0; } .title, #toctitle { color: var(--dark-accent); } a { /* white-space: nowrap; */ } img, iframe, video, audio { max-width: 100%; } p { font-weight: normal; } /* Taken out from book.css */ dl dt { margin-bottom: 0.3125em; font-weight: bold; } dl dd { margin-bottom: 1.25em; } dt, th.tableblock, td.content, div.footnote { text-rendering: optimizeLegibility; } .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { overflow: auto; word-wrap: break-word; } .literalblock pre.nowrap, .literalblock pre[class].nowrap, .listingblock pre.nowrap, .listingblock pre[class].nowrap { overflow-x: auto; white-space: pre; word-wrap: normal; } .listingblock { margin: 0 0 2em; } .listingblock > .content { position: relative; } .listingblock > .title { font-weight: bold; } .listingblock code[data-lang]::before { display: none; content: attr(data-lang); position: absolute; font-size: 0.75em; top: 1em; right: 1em; line-height: 1; text-transform: uppercase; color: #999; } .listingblock:hover code[data-lang]::before { display: block; } .listingblock.terminal pre .command::before { content: attr(data-prompt); padding-right: 0.5em; color: #999; } td.hdlist1, td.hdlist2 { vertical-align: top; padding-right: 0.625em; } td.hdlist1 { font-weight: bold; } .literalblock + .colist, .listingblock + .colist { margin-top: -1.5em; } .colist td:not([class]):first-child { padding: 0.4em 0.75em 0 0.75em; line-height: 1; vertical-align: top; } .colist td:not([class]):first-child img { max-width: none; } .colist td:not([class]):last-child { padding: 0.25em 0; } /* Custom classes */ .line-through { text-decoration: line-through; } .RemarquePreTitre, #toctitle { font-style: normal; font-weight: bold; } .RemarquePreTitre::after { content: "•"; padding-left: 5px; } .admonitionblock { } .admonitionblock > table, .exampleblock { --commented: rgba(17, 17, 68, .65); --border-radius-base: 8px; background-color: #fafafa; border: 1px solid var(--dark-shade); border-left: none; border-right: none; margin: 1.5em 0; padding: 1em; } .exampleblock .title { font-weight: bold; } .icon .title { font-size: 2em; } .admonitionblock > table td.icon { display: none; vertical-align: middle; } @media screen and (min-width: 769px) { .admonitionblock > table td.icon { display: table-cell; } } .admonitionblock > table td.icon { padding-right: 1em; } .admonitionblock > table td.icon img { max-width: none; } .colist ol { margin-left: 1.5em; /* aligns with the listing edge */ padding-left: 0; font-weight: bold; /* makes it stand out more */ } .colist ol p { margin: 0 0 .5em; } .listingblock:not(.prismjs) pre, .language-bash.hljs { background: #323232; color: wheat; margin: 0; padding: 1rem; } .language-bash.hljs .hljs-built_in, .language-bash.hljs .hljs-builtin-name { color: white; } .language-bash.hljs .hljs-string { color: lightgreen; } .language-bash.hljs .hljs-variable { color: lightskyblue; } .keyseq { font-weight: normal; white-space: nowrap; } .language-bash.hljs .keyseq { color: white; } .language-bash.hljs kbd { background: transparent; box-shadow: none; color: white; font-size: 0.8em; font-weight: bold; padding: 0.1em 0.4em; } .listingblock pre.highlightjs, .listingblock pre.prismjs { background-color: transparent; margin: 0; padding: 0; } .listingblock pre.highlightjs > code, .listingblock pre.prismjs { border-left: 4px solid var(--dark-accent); padding-left: 1em; font-size: .8em; } .listingblock pre.highlightjs > code.language-bash { border-left-color: limegreen; } .token.comment .conum { font-weight: normal; } .hdlist .hdlist1 { text-align: right; white-space: nowrap; } td > p:first-child { margin-top: 0; } .hljs-comment { font-style: normal !important; } #toc.toc2 a { text-decoration: none; white-space: normal; } #toc.toc2 a:hover, #toc.toc2 a:focus { text-decoration: underline; } #toc.toc2 ul { list-style: none; } #toc.toc2 > ul { padding-left: 0; } #toc.toc2 ul ul { padding-left: 1em; } @media screen and (min-width: 769px) { body { padding-left: 25vw !important; } #header, #content, #footer { margin-left: 0; } #toc.toc2 { height: 100%; left: 0; max-width: 20vw; overflow: auto; padding: 1rem; position: fixed; top: 0; z-index: 1000; } #toc.toc2 > ul { font-size: 0.85em; } #toc li.active > a[href^="#"], [id]:target { background: #ffc; } } .admonitionblock.context-callout > table { border-width: 5px; border-color: var(--brand-color); } </style> <style type="text/css" class="prism-theme">/** * prism.js default theme for JavaScript, CSS and HTML * Based on dabblet (http://dabblet.com) * @author Lea Verou */ code[class*="language-"], pre[class*="language-"] { color: black; background: none; text-shadow: 0 1px white; font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; font-size: 1em; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.5; -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; -webkit-hyphens: none; -moz-hyphens: none; -ms-hyphens: none; hyphens: none; } pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { text-shadow: none; background: #b3d4fc; } pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection { text-shadow: none; background: #b3d4fc; } @media print { code[class*="language-"], pre[class*="language-"] { text-shadow: none; } } /* Code blocks */ pre[class*="language-"] { padding: 1em; margin: .5em 0; overflow: auto; } :not(pre) > code[class*="language-"], pre[class*="language-"] { background: #f5f2f0; } /* Inline code */ :not(pre) > code[class*="language-"] { padding: .1em; border-radius: .3em; white-space: normal; } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: slategray; } .token.punctuation { color: #999; } .namespace { opacity: .7; } .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: #905; } .token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #690; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { color: #9a6e3a; background: hsla(0, 0%, 100%, .5); } .token.atrule, .token.attr-value, .token.keyword { color: #07a; } .token.function, .token.class-name { color: #DD4A68; } .token.regex, .token.important, .token.variable { color: #e90; } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } </style> <link rel="stylesheet" href="https://oncletom.io/styles/blog.css?v=v3.3.2"> <!-- WebMentions --> <link rel="pingback" href="https://webmention.io/oncletom.io/xmlrpc"> <link rel="webmention" href="https://webmention.io/oncletom.io/webmention"> <!-- Open Graph --> <meta property="og:type" content="book"> <meta property="og:image" content="https://oncletom.io/images/publications/nodejs-cover.png"> <meta property="og:book:author" content="Thomas Parisot"> <meta property="og:book:isbn" content="978-2212139938"> <meta property="og:book:release_date" content="2018-12-06"> <meta property="og:book:tag" content="Node.js"> <meta property="og:book:tag" content="JavaScript"> <meta property="og:book:tag" content="npm"> <meta property="og:book:tag" content="Développement front-end"> <meta property="og:book:tag" content="Développement back-end"> <meta property="og:locale" content="fr_FR"> <meta property="og:site_name" content="Node.js • Apprendre par la pratique"> <!-- Twitter OpenGraph --> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:site" content="@oncletom"> <meta name="twitter:creator" content="@oncletom"> <style type="text/css" class="extension-interactive-runner">[data-interactive-runtime="loaded"] .interactive--javascript code[data-lang]:before { background-color: #fcfcfc; border: 1px solid #0c2; border-radius: 1px; color: #0c2; cursor: pointer; display: inline-block; font-weight: bold; padding: .5em 1em; top: -2em; } [lang="en"] [data-interactive-runtime="loaded"] .interactive--javascript code[data-lang]:before { content: "▶ run code"; } [lang="fr"] [data-interactive-runtime="loaded"] .interactive--javascript code[data-lang]:before { content: "▶ voir le résultat"; } .interactive--javascript code[data-label]:before { content: attr(data-label); } .interactive iframe { position: absolute; visibility: hidden; } .interactive.status--loaded iframe { position: inherit; visibility: visible; } .interactive.status--loading { opacity: .5; } </style> <script class="extension-interactive-runner"> (function(d){ document.addEventListener('DOMContentLoaded', function(){ const script = d.createElement('script'); script.src = 'https://embed.runkit.com/'; script.async = true; script.onload = function(){ function makeListingInteractive (element){ if (element.classList.contains('interactive--installed') || element.classList.contains('status--loading')) { return; } const code = element.querySelector('code'); const nodeVersion = /interactive--runtime--node-([^\s]+)/.exec(element.className)[1]; const isEndpoint = element.classList.contains('interactive--endpoint'); const mode = isEndpoint ? 'endpoint' : null; let preamble = ''; const source = code .textContent .replace(/\/\/\s*\(\d+\)$/gm, '') .replace(/^["']?use strict["'][; ]*\n/, ''); if (isEndpoint) { preamble = `process.nextTick(() => { if (typeof module.exports === 'function') { exports.endpoint = module.exports; } else if (typeof server !== 'undefined') { exports.endpoint = server.listeners("request").pop(); } });` } element.classList.add('status--loading'); // eslint-disable-next-line no-undef RunKit.createNotebook({ nodeVersion, element, source, mode, preamble, onLoad: function(ntbk) { element.classList.add('interactive--installed'); element.classList.remove('status--loading'); element.classList.add('status--loaded'); code.parentNode.setAttribute('hidden', true); ntbk.evaluate(); } }); } function installEvents () { function getParent(el, condition) { let parent = el; while(parent = parent.parentNode) { if (condition(parent)) { return parent; } } } function hasClass(className) { return function check(el) { return el.classList.contains(className); } } document.querySelector('body').addEventListener('click', function(el) { if (el.target.classList.contains('language-javascript') || el.target.classList.contains('language-js')) { const parentNode = getParent( el.target, hasClass('interactive--javascript') ); makeListingInteractive(parentNode); } }); } installEvents(); document.body.dataset.interactiveRuntime = 'loaded'; }; document.body.appendChild(script); }); })(document);</script> <style type="text/css"> .listingblock [data-bash-subs]::before { content: attr(data-bash-subs) " "; opacity: .5; } .listingblock [data-bash-conum]::before { content: "(" attr(data-bash-conum) ")"; font-weight: bold; opacity: .7; }</style> <script> (function(d){ d.addEventListener('DOMContentLoaded', function(){ const {origin} = window.location; Array.from(document.querySelectorAll('a[href]')) .filter(link => link.href.indexOf(origin) !== 0) .forEach(link => { link.setAttribute('target', '_blank'); link.setAttribute('rel', 'noopener'); }); }); })(document);</script> <script> (function(d){ d.addEventListener('DOMContentLoaded', function(){ const script = d.createElement('script'); script.src = 'https://unpkg.com/menuspy@1.3.0/dist/menuspy.js'; script.async = true; script.onload = () => new MenuSpy(document.querySelector('#toc'), {enableLocationHash: false}); d.body.appendChild(script); }); })(document);</script> <style type="text/css"> #toc li.active > a[href^="#"] { font-weight: bold; } #toc li.active > a[href^="#"]::before { content: "▶ "; display: inline-block; position: absolute; margin-left: -1.2em; font-size: .8em; margin-top: 3px; } </style> </head> <body class="book toc2 toc-left"> <div id="header"> <h1>Déployer notre&#160;code</h1> <div id="toc" class="toc2"> <div id="toctitle">Table des matières</div> <ul class="sectlevel1"> <li><a href="#deploy">1. Déployer une application&#160;Node</a> <ul class="sectlevel2"> <li><a href="#deploy.notebook">1.1. En codant dans un navigateur&#160;web</a></li> <li><a href="#deploy.sftp">1.2. En transférant des fichiers via&#160;SSH</a></li> <li><a href="#deploy.github">1.3. En important du code depuis GitHub</a></li> <li><a href="#deploy.cli">1.4. Avec l&#8217;outil en ligne de commande de l&#8217;hébergeur</a></li> <li><a href="#deploy.git">1.5. En faisant git&#160;push depuis sa machine</a></li> <li><a href="#deploy.clone">1.6. En faisant git&#160;pull lors d&#8217;une session&#160;SSH</a></li> <li><a href="#deploy.recipe">1.7. Avec une recette de déploiement (Ansible, Chef, etc.)</a></li> <li><a href="#deploy.docker">1.8. En publiant une image Docker</a></li> <li><a href="#deploy.ci">1.9. En paramétrant un logiciel d&#8217;intégration continue</a></li> </ul> </li> <li><a href="#hosting">2. Choisir son hébergement</a> <ul class="sectlevel2"> <li><a href="#hosting.paas">2.1. Plate-forme de services (Platform as a Service, PaaS)</a></li> <li><a href="#hosting.shared">2.2. Hébergement mutualisé</a></li> <li><a href="#hosting.cloud">2.3. Serveur virtualisé, dédié ou&#160;cloud</a></li> <li><a href="#hosting.lambda">2.4. Fonction événementielle (Serverless, Lambda)</a></li> </ul> </li> <li><a href="#améliorer_la_portabilité_applicative">3. Améliorer la portabilité applicative</a> <ul class="sectlevel2"> <li><a href="#node.version">3.1. Utiliser la bonne version de&#160;Node</a></li> <li><a href="#port">3.2. L&#8217;application tourne mais elle est injoignable</a></li> <li><a href="#configuration">3.3. S&#8217;affranchir des chemins et configurations écrits &#8220;en dur&#8221;</a></li> <li><a href="#data-persistence">3.4. Faire persister les fichiers en dehors de notre application</a></li> <li><a href="#database-migration">3.5. Versionner les schémas de base de données</a></li> </ul> </li> <li><a href="#startup">4. Démarrer automatiquement une application</a> <ul class="sectlevel2"> <li><a href="#lhébergeur_sen_occupe_à_notre_place">4.1. L&#8217;hébergeur s&#8217;en occupe à notre place</a></li> <li><a href="#process-manager">4.2. Avec un gestionnaire de processus</a></li> <li><a href="#system-service">4.3. En créant un service système</a></li> <li><a href="#application-manager">4.4. Avec un serveur d&#8217;applications&#160;web</a></li> </ul> </li> <li><a href="#monitoring">5. À quoi penser après la mise en ligne ?</a> <ul class="sectlevel2"> <li><a href="#uptime">5.1. L&#8217;application a planté</a></li> <li><a href="#exceptions">5.2. S&#8217;informer des erreurs applicatives</a></li> <li><a href="#security.node">5.3. Notre version de Node fait l&#8217;objet d&#8217;une faille de sécurité</a></li> <li><a href="#security.npm">5.4. Un des modules&#160;npm fait l&#8217;objet d&#8217;une faille de sécurité</a></li> </ul> </li> <li><a href="#conclusion">6. Conclusion</a></li> </ul> </div> </div> <div id="content"> <div id="preamble"> <div class="sectionbody"> <div class="admonitionblock tip context-callout"> <table> <tr> <td class="icon"> <div class="title">💡</div> </td> <td class="content"> <div class="paragraph"> <p>Vous êtes en train de lire le Chapitre 6 du <a href="https://oncletom.io/node.js/">livre &#8220;Node.js&#8221;</a>, écrit par <a href="https://oncletom.io">Thomas Parisot</a> et publié aux <a href="https://editions-eyrolles.com/Livre/9782212139938">Éditions Eyrolles</a>.</p> </div> <div class="paragraph"> <p>L&#8217;ouvrage vous plaît&#160;? Achetez-le sur <a href="https://amzn.to/2E58PEw">Amazon.fr</a> ou en <a href="https://www.placedeslibraires.fr/livre/9782212139938">librairie</a>. <a href="https://opencollective.com/nodebook">Donnez quelques euros</a> pour contribuer à sa gratuité en ligne.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>En déployant une application Node, nous améliorerons la qualité de notre code en gommant les derniers bogues et en automatisant la détection des erreurs et des failles de sécurité.</p> </div> <div class="exampleblock"> <div class="content"> <div class="ulist"> <div class="title">Sommaire</div> <ul> <li> <p>Déployer une application Node</p> </li> <li> <p>Choisir son hébergement</p> </li> <li> <p>Améliorer la portabilité</p> </li> <li> <p>Démarrer automatiquement nos applications</p> </li> <li> <p>À quoi penser après la mise en ligne&#160;?</p> </li> </ul> </div> </div> </div> <div class="quoteblock abstract"> <blockquote> <div class="paragraph"> <p>Ce chapitre nous permettra d&#8217;y voir plus clair du côté de l&#8217;hébergement et de la mise en ligne d&#8217;une application Node. Nous pourrons choisir ce qui nous paraît le plus abordable, que ça soit en termes d&#8217;argent ou de complexité d&#8217;utilisation.</p> </div> <div class="paragraph"> <p>Nous mettrons en œuvre les <a href="../chapter-04/index.html#process.env">variables d&#8217;environnement</a> du chapitre 4 pour que nos applications en ligne fonctionnent de la même manière que sur notre ordinateur.</p> </div> <div class="paragraph"> <p>Enfin, nous verrons différents types de service pour être tenu·e informé·e des erreurs applicatives et des failles de sécurité, sans effort.</p> </div> </blockquote> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">💬</div> </td> <td class="content"> <div class="title"><span class="RemarquePreTitre">Remarque</span> Versions de Node et npm</div> <div class="paragraph"> <p>Le contenu de ce chapitre utilise les versions <strong>Node&#160;v10</strong> et <strong>npm&#160;v6</strong>. Ce sont les versions stables recommandées en&#160;2019.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <div class="title">💡</div> </td> <td class="content"> <div class="title"><span class="RemarquePreTitre">Pratique</span> Jouer avec les exemples dans un terminal</div> <div class="paragraph"> <p>Les exemples titrés d&#8217;un nom de fichier peuvent être installés sur votre ordinateur. Exécutez-les dans un terminal et amusez-vous à les modifier en parallèle de votre lecture pour voir ce qui change.</p> </div> <div class="listingblock"> <div class="title">Installation des exemples via le module npm <code>nodebook</code></div> <div class="content"> <pre><span data-bash-subs="$"></span>npm install --global nodebook <span data-bash-subs="$"></span>nodebook install chapter-06 <span data-bash-subs="$"></span>cd $(nodebook dir chapter-06)</pre> </div> </div> <div class="paragraph"> <p>La commande suivante devrait afficher un résultat qui confirme que vous êtes au bon endroit&#160;:</p> </div> <div class="listingblock"> <div class="content"> <pre><span data-bash-subs="$"></span>node hello.js</pre> </div> </div> <div class="paragraph"> <p>Suivez à nouveau les instructions d&#8217;installation pour rétablir les exemples dans leur état initial.</p> </div> </td> </tr> </table> </div> </div> </div> <div class="sect1"> <h2 id="deploy">1. Déployer une application&#160;Node</h2> <div class="sectionbody"> <div class="paragraph"> <p>Le choix de la technique de déploiement dépend de plusieurs facteurs qui renvoient à eux-mêmes&#160;: l&#8217;hébergement peut dépendre du déploiement et vice-versa.</p> </div> <div class="paragraph"> <p>Je vous propose de partir balayer les différentes techniques de déploiement avec des exemples et de voir quelles seraient les raisons d&#8217;opter pour l&#8217;une ou l&#8217;autre d&#8217;entre&#160;elles.</p> </div> <div class="paragraph"> <p>Le choix est subjectif et vous appartient, en fonction de votre aisance à vous en emparer. C&#8217;est un sujet qui prend du temps avant d&#8217;être maîtrisé, donc n&#8217;hésitez pas à vous y reprendre à plusieurs&#160;fois.</p> </div> <table class="tableblock frame-all grid-all stretch"> <caption class="title">Tableau 1. Quelles techniques de déploiement utiliser avec quel type d&#8217;hébergement ?</caption> <colgroup> <col style="width: 20%;"> <col style="width: 20%;"> <col style="width: 20%;"> <col style="width: 20%;"> <col style="width: 20%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top"></th> <th class="tableblock halign-left valign-top"><a href="#hosting.paas"><em>PaaS</em></a></th> <th class="tableblock halign-left valign-top"><a href="#hosting.shared">Mutualisé</a></th> <th class="tableblock halign-left valign-top"><a href="#hosting.cloud">Cloud</a></th> <th class="tableblock halign-left valign-top"><a href="#hosting.lambda">Lambda</a></th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#deploy.notebook">Notebook&#160;web</a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#deploy.sftp">SSH/SFTP</a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2248;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#deploy.github">Import GitHub</a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#deploy.cli">CLI</a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#deploy.git"><code>git push</code></a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#deploy.clone">SSH +&#160;<code>git pull</code></a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#deploy.recipe">Recette</a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#deploy.docker"><code>docker push</code></a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2718;</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#deploy.ci">Intégration continue</a></p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">&#x2714;</p></td> </tr> </tbody> </table> <div class="sect2"> <h3 id="deploy.notebook">1.1. En codant dans un navigateur&#160;web</h3> <div class="paragraph"> <p> </p> </div> <div class="paragraph"> <p>Le moyen le plus rapide d&#8217;exécuter un programme Node sans avoir à se préoccuper du déploiement est d&#8217;utiliser un service en ligne et de modifier le code avec un navigateur&#160;web.</p> </div> <div class="paragraph"> <p>Je recommande <em>RunKit</em> (<span class="URL"><a href="https://runkit.com" class="bare">runkit.com</a></span>) pour créer rapidement du code qui tient dans un seul fichier, sans installer Node sur sa machine. Le code est exécuté sur les serveurs de RunKit, le résultat s&#8217;affiche chez nous. Les <a href="../chapter-05/index.html#modules">modules <code>npm</code></a> (<a href="../chapter-05/index.html">chapitre&#160;5</a>) sont installés automatiquement dans leur version la plus récente. </p> </div> <div class="imageblock"> <div class="content"> <img src="./images/runkit-notebook.png" alt="runkit notebook" width="85%"> </div> <div class="title">Figure 1. Exemple de notebook RunKit dans le navigateur Firefox</div> </div> <div class="paragraph"> <p>RunKit propose aussi un modèle de <a href="#lambda">fonction éphémère</a> dont le résultat devient accessible depuis une URL dédiée. Essayez de copier/coller le code suivant dans un nouveau notebook en vous rendant sur <span class="URL"><a href="https://runkit.com/new" class="bare">runkit.com/new</a></span>&#160;:</p> </div> <div class="listingblock"> <div class="title">runkit-endpoint.js</div> <div class="content"> <pre class="highlight highlight-prismjs prismjs language-javascript"><code class="language-javascript" data-lang="javascript"><span class="token string">'use strict'</span><span class="token punctuation">;</span> <span class="token keyword">const</span> pokemon <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'pokemon-random-name'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> // <b class="conum">(1)</b> exports<span class="token punctuation">.</span><span class="token function-variable function">endpoint</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">request<span class="token punctuation">,</span> response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> // <b class="conum">(2)</b> response<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token function">pokemon</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre> </div> </div> <div class="colist arabic"> <ol> <li> <p>Le module npm <span class="URL"><a href="https://npmjs.com/pokemon-random-name" class="bare">npmjs.com/pokemon-random-name</a></span> exporte une fonction qui retourne un nom aléatoire de Pokémon.</p> </li> <li> <p><code>exports.endpoint</code> est spécifique à RunKit et accepte une fonction identique à l&#8217;événement <code>server.on('request')</code> du <a href="../chapter-04/index.html#http">module <code>http</code></a> (<a href="../chapter-04/index.html">chapitre&#160;4</a>).</p> </li> </ol> </div> <div class="paragraph"> <p>Une fois sauvegardé puis cliqué sur le lien <span class="Menu">endpoint</span>, un nouvel onglet s&#8217;ouvre et affiche un nom aléatoire de Pokémon. C&#8217;est la valeur de retour passée à la réponse, comme on l&#8217;aurait fait avec le <a href="../chapter-04/index.html#http">module&#160;<code>http</code></a> ou dans une <a href="../chapter-07/index.html">application web</a> (<a href="../chapter-07/index.html">chapitre&#160;7</a>).</p> </div> <div class="paragraph"> <p>Le service en ligne <em>Glitch</em> (<span class="URL"><a href="https://glitch.com" class="bare">glitch.com</a></span>) va plus loin en développant, hébergeant et partageant des applications complètes. Le service redéploie notre application à chaque changement. Le fichier <code>.env</code> stocke les <a href="../chapter-04/index.html#process.env">variables d&#8217;environnement</a> de manière sécurisée&#160;– personne d&#8217;autre que nous n&#8217;y a accès. </p> </div> <div class="imageblock"> <div class="content"> <img src="./images/glitch-app.png" alt="glitch app" width="85%"> </div> <div class="title">Figure 2. Exemple d&#8217;application Node sur glitch.com</div> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <div class="title">💡</div> </td> <td class="content"> <div class="title"><span class="RemarquePreTitre">Pratique</span> Console&#160;web</div> <div class="paragraph"> <p> Glitch nous offre même une console web&#160;: un <a href="../chapter-02/index.html#shell">terminal</a> entièrement fonctionnel, depuis un navigateur&#160;!</p> </div> <div class="paragraph"> <p>C&#8217;est parfait pour <a href="../chapter-08/index.html">coder un outil en ligne de commande</a> (<a href="../chapter-08/index.html">chapitre&#160;8</a>) en travaillant depuis plusieurs ordinateurs sans avoir à tout réinstaller à chaque&#160;fois.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <div class="title">💡</div> </td> <td class="content"> <div class="title"><span class="RemarquePreTitre">Pratique</span> Remixez les exemples de cet ouvrage</div> <div class="paragraph"> <p>Vous pouvez créer votre premier projet sur Glitch. Remixez cet ouvrage en vous rendant sur <span class="URL">https://glitch.com/edit/#!/remix/nodebook</span>.</p> </div> <div class="paragraph"> <p>Le contenu et les exemples seront copiés dans un nouveau projet, exécutable et modifiable selon vos envies.</p> </div> </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="deploy.sftp">1.2. En transférant des fichiers via&#160;SSH</h3> <div class="paragraph"> <p></p> </div> <div class="paragraph"> <p>Transférer des fichiers est idéal pour débuter et lorsqu&#8217;on n&#8217;utilise pas Git pour versionner son&#160;code.</p> </div> <div class="paragraph"> <p>Les services d&#8217;hébergement mutualisé, virtualisé ou dédié accordent un accès à votre espace en ligne par le biais de SSH (<span class="URL"><a href="https://fr.wikipedia.org/wiki/Secure_Shell" class="bare">fr.wikipedia.org/wiki/Secure_Shell</a></span>). Ce protocole crée une connexion sécurisée&#160;: les commandes saisies dans votre terminal font effet sur la machine sur laquelle vous êtes connecté·e.</p> </div> <div class="paragraph"> <p>Des logiciels comme <em>FileZilla Client</em> (<span class="URL"><a href="https://filezilla-project.org/" class="bare">filezilla-project.org/</a></span>) servent d&#8217;interfaces graphiques pour transférer des fichiers vers une machine distante.</p> </div> <div class="paragraph"> <p>Les codes d&#8217;accès SSH se trouvent en général dans la section <span class="Menu">Aide</span> ou <span class="Menu">Guides</span> de votre hébergeur.</p> </div> <div class="imageblock"> <div class="content"> <img src="./images/filezilla-file-transfer.png" alt="filezilla file transfer" width="85%"> </div> <div class="title">Figure 3. Exemple de connexion à un serveur SSH distant avec FileZilla Client sous macOS</div> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <div class="title">💡</div> </td> <td class="content"> <div class="title"><span class="RemarquePreTitre">Windows</span> WinSCP</div> <div class="paragraph"> <p><em>WinSCP</em> (<span class="URL"><a href="https://winscp.net" class="bare">winscp.net</a></span>) est une alternative libre à FileZilla pour Windows.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">💬</div> </td> <td class="content"> <div class="title"><span class="RemarquePreTitre">Avancé</span> scp et rsync</div> <div class="paragraph"> <p> Notre terminal peut aussi servir à transférer des fichiers. Deux programmes se basent sur SSH et sont installés par défaut sur la plupart des ordinateurs Linux et macOS&#160;:</p> </div> <div class="ulist"> <ul> <li> <p><code>scp</code> pour envoyer des fichiers de machine à machine&#160;;</p> </li> <li> <p><code>rsync</code> pour n&#8217;envoyer que les fichiers qui ont été modifiés ou supprimés.</p> </li> </ul> </div> </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="deploy.github">1.3. En important du code depuis GitHub</h3> <div class="paragraph"> <p></p> </div> <div class="paragraph"> <p>Importer du code depuis GitHub est la manière la plus simple de transférer tous les fichiers versionnés sans être familier avec&#160;Git.</p> </div> <div class="paragraph"> <p>La plate-forme de <a href="#deploy.notebook">programmation en ligne</a> Glitch offre une option pour importer n&#8217;importe quel projet GitHub&#160;– à partir du moment où le dépôt est public.</p> </div> <div class="imageblock"> <div class="content"> <img src="./images/glitch-github-import.png" alt="glitch github import" width="85%"> </div> <div class="title">Figure 4. Bouton d&#8217;import d&#8217;un dépôt GitHub sur glitch.com</div> </div> <div class="paragraph"> <p>Un clic sur le bouton <b class="button">Import from GitHub</b> ouvre une invite de saisie destinée à mentionner le nom du dépôt GitHub concerné. Le projet en cours sera entièrement remplacé par le contenu du dépôt distant. C&#8217;est pratique pour récupérer des exercices ou pour apprendre en travaillant sur du code écrit par quelqu&#8217;un d&#8217;autre.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <div class="title">💡</div> </td> <td class="content"> <div class="title"><span class="RemarquePreTitre">Pratique</span> Importer les exemples de cet ouvrage</div> <div class="paragraph"> <p>Récupérez tout le contenu et les exemples de cet ouvrage en recopiant <code>oncletom/nodebook</code> dans l&#8217;invite de saisie.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>La <a href="#paas">plate-forme de services</a> <em>Heroku</em> (<span class="URL"><a href="https://heroku.com" class="bare">heroku.com</a></span>) pousse l&#8217;import GitHub un peu plus loin. Sa fonctionnalité déploie l&#8217;application à chaque nouveau commit. L&#8217;application redémarre ensuite automatiquement pour prendre les changements en compte.</p> </div> <div class="imageblock"> <div class="content"> <img src="./images/heroku-github-import.png" alt="heroku github import" width="85%"> </div> <div class="title">Figure 5. Paramétrage de déploiement automatisé depuis un dépôt GitHub sur heroku.com</div> </div> <div class="paragraph"> <p>Une option nous permet de déployer une nouvelle version de l&#8217;application à la suite d&#8217;une <a href="#deploy.ci">intégration continue réussie</a>. Nous réduisons ainsi les risques de déployer une version défectueuse.</p> </div> </div> <div class="sect2"> <h3 id="deploy.cli">1.4. Avec l&#8217;outil en ligne de commande de l&#8217;hébergeur</h3> <div class="paragraph"> <p> </p> </div> <div class="paragraph"> <p>L&#8217;outil en ligne de commande d&#8217;un hébergeur permet de gérer les déploiements et d&#8217;autres aspects de l&#8217;hébergement en même temps.</p> </div> <div class="paragraph"> <p>La <a href="#paas">plate-forme de services</a> <em>now</em> (<span class="URL"><a href="https://zeit.co/now" class="bare">zeit.co/now</a></span>) est un exemple de simplicité à ce niveau. </p> </div> <div class="listingblock"> <div class="title">Installation et configuration de l&#8217;outil&#160;now</div> <div class="content"> <pre><span data-bash-subs="$"></span>npm install -g now <span data-bash-subs="$"></span>now login</pre> </div> </div> <div class="paragraph"> <p>Dans un terminal, déplacez-vous vers le répertoire de l&#8217;application à déployer. Il suffit de taper&#160;<code>now</code> pour transférer les fichiers. Les dépendances s&#8217;installent et le déploiement est accessible quelques secondes plus tard&#160;:</p> </div> <div class="listingblock"> <div class="content"> <pre><span data-bash-subs="$"></span>now Deploying ~/workspace/dtc-innovation/food-coops-dashboards <span data-bash-subs=">"></span>Using Node.js 9.10.1 (requested: `&gt;=8.0.0`) <span data-bash-subs=">"></span>https://food-coops-dashboards-okgwzegyus.now.sh <span data-bash-subs=">"></span>Synced 1 file (169.84KB) [11s] <span data-bash-subs=">"></span>Building... <span data-bash-subs=">"></span>▲ npm install <span data-bash-subs=">"></span>✓ Using "package-lock.json" <span data-bash-subs=">"></span>⧗ Installing 9 main dependencies... <span data-bash-subs=">"></span>▲ npm install <span data-bash-subs=">"></span>added 389 packages in 8.609s <span data-bash-subs=">"></span>▲ Snapshotting deployment <span data-bash-subs=">"></span>Build completed <span data-bash-subs=">"></span>Verifying instantiation in bru1 <span data-bash-subs=">"></span>✔ Scaled 1 instance in bru1 [31s] <span data-bash-subs=">"></span>Success! Deployment ready</pre> </div> </div> <div class="paragraph"> <p>En optant pour l&#8217;offre payante, nous pouvons aussi gérer les noms de domaine et sous-domaines en leur attribuant l&#8217;URL du déploiement&#160;:</p> </div> <div class="listingblock"> <div class="content"> <pre><span data-bash-subs="$"></span>now alias food-coops-dashboards-okgwzegyus.now.sh my-domain.com</pre> </div> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">💬</div> </td> <td class="content"> <div class="title"><span class="RemarquePreTitre">Pratique</span> Application de bureau</div> <div class="paragraph"> <p>Le client en ligne de commande existe en version graphique. Un glisser/déposer de fichiers suffit à lancer un déploiement.</p> </div> <div class="paragraph"> <p>Il se télécharge sur <span class="URL"><a href="https://zeit.co/download" class="bare">zeit.co/download</a></span>.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>L&#8217;outil de la <a href="#paas">plate-forme de services</a> <em>Heroku</em> suit une approche légèrement différente. Il nous informe de l&#8217;état de nos applications et en augmente ou diminue la quantité de ressources allouée à leur fonctionnement. Il simplifie la configuration de&#160;Git et <a href="#deploy.git">délègue le déploiement</a> à ce dernier. L&#8217;outil se télécharge sur <span class="URL"><a href="https://devcenter.heroku.com/articles/heroku-cli" class="bare">devcenter.heroku.com/articles/heroku-cli</a></span>.</p> </div> <div class="listingblock"> <div class="title">Configuration de l&#8217;outil <code>heroku</code></div> <div class="content"> <pre><span data-bash-subs="$"></span>heroku login</pre> </div> </div> <div class="paragraph"> <p>La commande <code>heroku apps:create</code> crée une nouvelle application chez <em>Heroku</em>. On peut faire la même chose dans un navigateur web en nous rendant sur <span class="URL"><a href="https://dashboard.heroku.com/new-app" class="bare">dashboard.heroku.com/new-app</a></span>. La commande <code>heroku git:remote</code> associe notre copie locale Git à cette application&#160;:</p> </div> <div class="listingblock"> <div class="title">Configuration de notre dépôt Git pour en faire une application Heroku</div> <div class="content"> <pre><span data-bash-subs="$"></span>heroku apps:create --region eu Creating app... done, ⬢ <mark>polar-taiga-61296</mark>, region is eu https://polar-taiga-61296.herokuapp.com/ https://git.heroku.com/polar-taiga-61296.git <span data-bash-subs="$"></span>heroku git:remote --app <mark>polar-taiga-61296</mark></pre> </div> </div> <div class="paragraph"> <p>Il ne nous reste plus qu&#8217;à <a href="#deploy.git">pousser notre code avec&#160;Git</a> pour terminer la mise en ligne.</p> </div> </div> <div class="sect2"> <h3 id="deploy.git">1.5. En faisant git&#160;push depuis sa machine</h3> <div class="paragraph"> <p></p> </div> <div class="paragraph"> <p>Le déploiement d&#8217;une branche Git est le moyen le plus facile d&#8217;automatiser tous les aspects d&#8217;un déploiement.</p> </div> <div class="paragraph"> <p>Cette méthode est privilégiée par les <a href="#paas">plates-formes de services</a> comme <em>Heroku</em>, <em>now</em> et <em>Clever Cloud</em>. Chaque projet d&#8217;application est accessible via un dépôt Git distant (<em>remote</em>)&#160;: un dépôt est utilisé pour versionner notre code (GitHub par exemple) tandis qu&#8217;un autre sert pour réceptionner le code à déployer.</p> </div> <div class="paragraph"> <p>L&#8217;exemple suivant part du principe que notre terminal est positionné dans un répertoire qui est un projet Git contenant au moins un <em>commit</em>. Vous avez déjà configuré le dépôt distant à l&#8217;aide de l'<a href="#deploy.cli">outil de déploiement</a> <em>Heroku</em> (<a href="#deploy.cli">section précédente</a>).</p> </div> <div class="paragraph"> <p>Nous pouvons vérifier si le dépôt est bien configuré à l&#8217;aide de la commande <code>git remote</code>&#160;:</p> </div> <div class="listingblock"> <div class="title">Liste des dépôts distants d&#8217;un projet Git configuré pour Heroku</div> <div class="content"> <pre><span data-bash-subs="$"></span>git remote -v <mark>heroku</mark> https://git.heroku.com/mon-application.git (fetch) <mark>heroku</mark> https://git.heroku.com/mon-application.git (push) origin git@github.com:mon-compte/mon-application.git (fetch) origin git@github.com:mon-compte/mon-application.git (push)</pre> </div> </div> <div class="paragraph"> <p>La commande <code>heroku git:remote</code> crée un <em>remote</em> nommé <code>heroku</code>. Heroku redéploie notre application dès qu&#8217;on lui envoie du code avec <code>git push heroku</code>&#160;:</p> </div> <div class="listingblock"> <div class="content"> <pre><span data-bash-subs="$"></span>git push heroku <span data-bash-subs=">"></span>Counting objects: 4, done. <span data-bash-subs=">"></span>Delta compression using up to 4 threads. <span data-bash-subs=">"></span>Compressing objects: 100% (4/4), done. <span data-bash-subs=">"></span>Writing objects: 100% (4/4), 17.77 KiB | 5.92 MiB/s, done. <span data-bash-subs=">"></span>Total 4 (delta 2), reused 0 (delta 0) <span data-bash-subs=">"></span>remote: Compressing source files... done. <span data-bash-subs=">"></span>remote: Building source: <span data-bash-subs=">"></span>remote: <span data-bash-subs=">"></span>remote: -----&gt; Node.js app detected <span data-bash-subs=">"></span>remote: <span data-bash-subs=">"></span>remote: -----&gt; Creating runtime environment <span data-bash-subs=">"></span>... <span data-bash-subs=">"></span>remote: -----&gt; Launching... <span data-bash-subs=">"></span>remote: Released v30 // <b class="conum">(1)</b> <span data-bash-subs=">"></span>remote: https://mon-application.herokuapp.com/ deployed <span data-bash-subs=">"></span>remote: <span data-bash-subs=">"></span>remote: Verifying deploy... done.</pre> </div> </div> <div class="colist arabic"> <ol> <li> <p>C&#8217;est le trentième déploiement&#160;– on peut revenir à une version antérieure si nécessaire.</p> </li> </ol> </div> <div class="paragraph"> <p>L&#8217;URL de l&#8217;application est rappelée dans les <em>logs</em> du déploiement. En cas d&#8217;erreur, la version précédente de l&#8217;application reste en ligne. Nous avons ainsi le temps de corriger le problème sans interruption de service.</p> </div> </div> <div class="sect2"> <h3 id="deploy.clone">1.6. En faisant git&#160;pull lors d&#8217;une session&#160;SSH</h3> <div class="paragraph"> <p> </p> </div> <div class="paragraph"> <p>La récupération du code source à distance avec Git et SSH est une manière de déployer similaire à la mise à jour et au démarrage d&#8217;une application sur notre ordinateur.</p> </div> <div class="paragraph"> <p>Cette technique s&#8217;applique si notre application est placée sur un <a href="#hosting.shared">hébergement mutualisé</a>, <a href="#hosting.vm">dédié ou virtualisé</a> ou une <a href="#hosting.cloud">offre cloud</a>.</p> </div> <div class="paragraph"> <p>L&#8217;exemple suivant illustre l&#8217;initialisation d&#8217;un projet via la connexion SSH à un <a href="#hosting.shared">hébergement mutualisé</a> chez alwaysdata.</p> </div> <div class="listingblock"> <div class="title">Première récupération d&#8217;un dépôt Git lors d&#8217;une session&#160;SSH</div> <div class="content"> <pre><span data-bash-subs="$"></span>ssh moncompte@ssh-moncompte.alwaysdata.net <span data-bash-subs="$$"></span>git clone https://github.com/moncompte/monprojet . <span data-bash-subs="$$"></span>npm install</pre> </div> </div> <div class="paragraph"> <p>Nous avons cloné un projet comme nous aurions pu le faire si nous installions notre projet depuis zéro sur notre ordinateur.</p> </div> <div class="paragraph"> <p>Dans le cas d&#8217;une mise à jour, nous récupérons les changements depuis le dépôt distant avec <code>git pull</code>. <code>npm install</code> met à jour les dépendances s&#8217;il y a des différences entre le contenu du fichier <code>package.json</code> et les modules déjà installés (<a href="../chapter-05/index.html">chapitre&#160;5</a>).</p> </div> <div class="listingblock"> <div class="title">Mise à jour d&#8217;une application lors d&#8217;une session&#160;SSH</div> <div class="content"> <pre><span data-bash-subs="$"></span>ssh moncompte@ssh-moncompte.alwaysdata.net <span data-bash-subs="$$"></span>git pull <span data-bash-subs="$$"></span>npm install</pre> </div> </div> <div class="paragraph"> <p>Dans le cas d&#8217;alwaysdata, l&#8217;application se redémarre depuis l'<a href="#hosting.shared">interface d&#8217;administration</a>. Dans les autres cas, redémarrez l&#8217;application selon le procédé choisi après avoir lu la section &#8220;<a href="#startup">Démarrer automatiquement nos applications</a>&#8221;.</p> </div> </div> <div class="sect2"> <h3 id="deploy.recipe">1.7. Avec une recette de déploiement (Ansible, Chef, etc.)</h3> <div class="paragraph"> <p> </p> </div> <div class="paragraph"> <p>La recette de déploiement est la manière la plus complète de partager et d&#8217;automatiser un déploiement complexe.</p> </div> <div class="paragraph"> <p>Cette méthode se place dans la continuité de <a href="#deploy.clone"><code>git pull</code> lors d&#8217;une session SSH</a>&#160;: nous orchestrons les actions nécessaires au déploiement en les listant dans un fichier de configuration, en choisissant dans quel ordre les déclencher et sur quel(s) serveur(s).</p> </div> <div class="paragraph"> <p>Nous retrouvons Puppet (<span class="URL"><a href="https://puppet.com" class="bare">puppet.com</a></span>), Chef (<span class="URL"><a href="https://www.chef.io" class="bare">www.chef.io</a></span>) et Ansible (<span class="URL"><a href="https://ansible.com" class="bare">ansible.com</a></span>) parmi les outils les plus utilisés et les mieux documentés. Ils ont des philosophies de configuration et d&#8217;exécution différentes – l&#8217;idéal est encore d&#8217;essayer d&#8217;écrire une première recette avec chacun d&#8217;entre eux pour voir celui qui vous semble le plus naturel à utiliser.</p> </div> <div class="paragraph"> <p>Ma préférence va vers Ansible car le logiciel s&#8217;installe facilement sur macOS et Linux, se configure avec une syntaxe que je connais déjà (YAML) et je trouve ses messages d&#8217;erreurs in