Comment déployer une application Node.js à l’aide de Terraform sur Ubuntu 14.04

Un article de Stream

introduction

À l’aide des outils d’orchestration, les professionnels de DevOps peuvent déployer une pile en exploitant quelques appels d’API. Terraform est un outil très simple, mais puissant, qui vous permet d’écrire votre pile sous forme de code, puis de la partager et de la maintenir à jour en validant les fichiers de définition à l’aide de https: //git-scm.com/[Git]. Terraform est créé par HashiCorp, les auteurs d’outils populaires à code source ouvert tels que Vagrant, https: //www.packer. io / [Packer] et Consul.

Terraform fournit une configuration commune pour le lancement de votre infrastructure, des serveurs physiques et virtuels aux fournisseurs de messagerie et DNS. Une fois lancé, Terraform modifie efficacement et en toute sécurité l’infrastructure à mesure que la configuration évolue.

Ce tutoriel vous explique comment configurer un environnement pour une application Node.js sophistiquée et entièrement fonctionnelle à l’aide de https://digitalocean.com [DigitalOcean], https: // www. terraform.io/[Terraform], Cloud-init, et PM2 sous Ubuntu 14.04. Comme exemple d’application, nous utiliserons http://cabin.getstream.io [Cabin], un logiciel libre React & http: //redux.js. org / docs / basics / UsageWithReact.html [Redux] Application Node.js développée par http://getstream.io [GetStream.io]. Le résultat final sera une application de réseau social évolutive et riche en fonctionnalités!

Vous commencerez par utiliser Terraform pour déployer Cabin à l’aide d’une configuration prédéfinie. Ensuite, vous allez vous plonger dans cette configuration pour vous familiariser avec son fonctionnement.

Si vous souhaitez uniquement installer Terraform sur votre serveur DigitalOcean, veuillez consulter Comment utiliser Terraform avec DigitalOcean.

Conditions préalables

Pour suivre ce tutoriel, vous aurez besoin de:

  • Un serveur Ubuntu 14.04 de 2 Go, que vous allez créer dans ce tutoriel avec Terraform.

  • Le client Git installé sur votre ordinateur local.

  • Un compte Facebook, afin que vous puissiez créer une application Facebook, car Cabin utilise Facebook pour les connexions.

  • Un domaine tel que + cabin.example.com +; vous dirigerez ce domaine vers l’adresse IPv4 que vous obtiendrez à l’étape 4, et vous en aurez besoin pour l’URL du site dans Facebook.

Bien que cela ne soit pas obligatoire, ce tutoriel suppose que vous avez terminé la série de tutoriels Stream’s Cabin. Vous aurez besoin de clés d’API et de paramètres pour plusieurs fournisseurs, nécessaires au fonctionnement de Cabin en production, car ils jouent un rôle essentiel dans les fonctionnalités de Cabin.

Pour plus d’informations sur ces services, n’hésitez pas à consulter les articles suivants de Stream dans le blog:

Étape 1 - Obtenir l’exemple d’application

Clonez l’application exemple Cabin à partir de GitHub dans un répertoire de votre choix sur votre ordinateur local. Nous utilisons un Mac et supposons que vous l’utilisez également.

Tout d’abord, accédez à votre répertoire personnel.

cd ~

Ensuite, utilisez + git + pour cloner le référentiel:

git clone https://github.com/GetStream/stream-react-example.git

Ceci copie l’exemple d’application dans un nouveau dossier appelé + stream-react-example. Accédez au dossier + stream-react-example / terraform / do / cabin + qui contient le projet Terraform de Cabin.

cd stream-react-example/terraform/do/cabin

Nous allons travailler avec ce dossier dans un peu. Mais commençons par configurer Terraform.

Étape 2 - Installation de Terraform

Pour une installation simple sur OSX, vous pouvez installer Terraform à l’aide de Homebrew en lançant la commande suivante:

brew install terraform

Vous pouvez également télécharger Terraform à partir de http://terraform.io. Une fois que vous l’avez téléchargé, rendez-le disponible sur votre chemin de commande, comme indiqué ci-dessous.

PATH=:$PATH

Cela ajoute temporairement Terraform à votre chemin. Si vous voulez que cette modification soit permanente, éditez le fichier + ~ / .bash_profile + sous OSX et ajoutez cette ligne:

~ / .bash_profile

export PATH=:$PATH

Ensuite, pour vérifier que Terraform a été installé correctement, exécutez la commande suivante:

terraform

La sortie suivante affiche les options de Terraform:

Outputusage: terraform [--version] [--help] <command> [<args>]

Available commands are:
   apply       Builds or changes infrastructure
   destroy     Destroy Terraform-managed infrastructure
   fmt         Rewrites config files to canonical format
   get         Download and install modules for the configuration
   graph       Create a visual graph of Terraform resources
   init        Initializes Terraform configuration from a module
   output      Read an output from a state file
   plan        Generate and show an execution plan
   push        Upload this Terraform module to Atlas to run
   refresh     Update local state file against real resources
   remote      Configure remote state storage
   show        Inspect Terraform state or plan
   taint       Manually mark a resource for recreation
   untaint     Manually unmark a resource as tainted
   validate    Validates the Terraform files
   version     Prints the Terraform version

Avant que Terraform puisse démarrer votre infrastructure, nous devons configurer deux choses:

Commençons donc par le jeton DigitalOcean.

Étape 2 - Configuration du jeton d’accès DigitalOcean

Terraform a besoin de votre jeton d’accès DigitalOcean pour utiliser l’API DigitalOcean.

Connectez-vous à votre compte DigitalOcean et cliquez sur le lien * API *. Cliquez ensuite sur le bouton * Générer un nouveau jeton *. Assurez-vous de vérifier * Accès en écriture *. L’interface utilisateur affichera une nouvelle clé d’accès que vous devrez copier dans votre presse-papiers, car la clé ne sera pas visible si vous revenez sur la page.

Ouvrez maintenant le fichier + variables.tf + avec votre éditeur de texte favori et localisez la section + token +:

variables.tf

variable "token" {
 description = "DO Token"
}

Ajoutez une nouvelle ligne commençant par le texte + default = + et incluez votre jeton d’API DigitalOcean. N’oubliez pas de entourer le jeton de guillemets.

variables.tf

variable "token" {
 description = "DO Token"

}

Enregistrez et fermez le fichier.

Configurons maintenant Terraform pour utiliser notre paire de clés SSH.

Étape 3 - Ajoutez votre paire de clés SSH

Terraform a besoin d’une clé SSH pour se connecter à notre serveur une fois celui-ci créé afin de pouvoir installer des packages et déployer l’application.

Regardez dans votre répertoire + ~ / .ssh + pour voir si vous avez déjà une paire de clés:

ls -al ~/.ssh

Très probablement, vous avez au moins une paire de clés composée d’une clé privée et d’une clé publique. Par exemple, vous pourriez avoir + id_rsa.pub + et + id_rsa +.

Si vous ne possédez aucune paire de clés ou si la clé que vous possédez est déjà associée à votre compte DigitalOcean, veuillez consulter https://www.digitalocean.com/community/tutorials/how-to-use-ssh- keys-with-digitalocean-droplets [Le tutoriel de DigitalOcean sur la configuration des clés SSH] pour en créer une.

Vous devez coller le contenu du fichier + .pub + dans le fichier + variables.tf +, comme vous l’avez fait avec le jeton de l’API. Si vous êtes sur un Mac, vous pouvez copier votre clé publique SSH dans votre presse-papiers en exécutant la commande suivante:

pbcopy < ~/.ssh/

Vous pouvez également afficher le contenu de la clé publique à l’écran à l’aide de la commande + cat + et le copier manuellement dans le Presse-papiers:

cat  ~/.ssh/

Ouvrez ensuite le fichier + variables.tf + dans votre éditeur et ajoutez le contenu de votre fichier de clé publique SSH au paramètre + sshkey +:

variables.tf

variable "sshkey" {
 description = "Public ssh key (for Cabin user)"

}

Une fois cette étape terminée, sauvegardez et quittez le fichier.

Si vous avez généré une nouvelle clé à utiliser avec Terraform et DigitalOcean, vous devez exécuter ces deux commandes pour que votre nouvelle clé soit utilisée à la place de votre clé par défaut:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/your_id_rsa

Vous devrez peut-être l’exécuter à chaque fois que vous ouvrez un nouveau shell si vous utilisez une autre paire de clés.

Maintenant que vous avez fourni à Terraform les variables dont il a besoin, vous êtes prêt à créer votre serveur et déployer votre application avec Terraform.

Étape 4 - Exécution de Terraform

Voici la partie amusante! Voyons l’infrastructure que nous allons construire. Terraform va faire beaucoup de travail pour nous, de la configuration de notre serveur au déploiement de notre application. Terraform peut nous montrer exactement ce qu’il va faire avec la commande suivante:

terraform plan

Le résultat de cette commande est assez détaillé, essayez donc de vous concentrer sur les déclarations suivantes:

Output+ digitalocean_droplet.cabin-web
...
+ digitalocean_floating_ip.cabin-web-ip
...
+ digitalocean_ssh_key.cabin-ssh-key
...
+ template_file.pm2_processes_conf
...
+ template_file.userdata_web
...

Le symbole «» au début d'une ligne signifie que les ressources seront créées. Les ressources préfixées par ` digitalocean +` sont les ressources qui seront créées sur DigitalOcean. Dans ce cas particulier, Terraform créera un Droplet, une adresse IP flottante, et ajoutera notre clé SSH.

Il est maintenant temps de lancer Terraform et de faire tourner Cabin sur votre Droplet.

terraform apply

Après quelques instants, Terraform imprimera les éléments suivants:

OutputApply complete! Resources: 6 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

Expected output:

 web_ipv4 =

+ web_ipv4 + est l’adresse IP flottante que vous pouvez utiliser pour accéder à Droplet.

Connectez-vous à la nouvelle Droplet en utilisant la valeur que vous voyez pour ++:

ssh cabin@

Vous pouvez également utiliser la commande

terraform output web_ipv4

pour afficher l’adresse IP associée à cette valeur si vous l’avez manquée.

Vous verrez ce message de bienvenue lorsque vous vous connecterez:

  _____      _     _
 / ____|    | |   (_)
| |     __ _| |__  _ _ __
| |    / _` | '_ \| | '_ \
| |___| (_| | |_) | | | | |
 \_____\__,_|_.__/|_|_| |_|

Initializing Cabin. Please wait... (up 1 minute) | CTRL+C to interrupt

Vous devrez peut-être attendre plusieurs minutes pour que DigitalOcean mette à disposition l’instance et pour que + cloud-init + installe les packages requis pour Cabin. Mais une fois prêt, vous verrez ceci:

Cabin initialized!
Check running processes...
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid   │ status │ restart │ uptime │ memory      │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ api      │ 0  │ fork │ 14105 │ online │ 0       │ 36s    │ 75.898 MB   │  enabled │
│ app      │ 1  │ fork │ 14112 │ online │ 0       │ 36s    │ 34.301 MB   │  enabled │
│ www      │ 2  │ fork │ 14119 │ online │ 0       │ 36s    │ 50.414 MB   │  enabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app

Une fois que Cabin est opérationnel, pointez votre navigateur mobile sur + http: // +. La cabine est en direct et vous devriez voir un écran de chargement. Mais c’est tout ce que nous aurons jusqu’à ce que nous apportions quelques modifications au code sur le serveur.

Étape 5 - (Facultatif) Configuration de la cabine

L’application Cabin est déployée, mais elle n’est pas encore utilisable. Nous devons configurer Facebook et plusieurs autres services si nous voulons que Cabin soit pleinement opérationnel.

Tout d’abord, vous devrez créer une application Facebook en utilisant un nom de domaine valide, tel que + cabin.example.com +, mappé sur l’adresse + web_ipv4 + générée au cours du processus d’installation. Ajoutez un enregistrement à votre DNS ou ajoutez une entrée dans votre fichier + / etc / hosts + qui mappe votre domaine sur l’adresse IP.

Pour créer l’application Facebook, procédez comme suit:

  1. Visitez https://developers.facebook.com/docs/apps/register#step-by-step-guide.

  2. Connectez-vous à Facebook.

  3. Sous Mes applications, cliquez sur * Ajouter une nouvelle application *.

  4. Entrez un nom pour votre application (par exemple, + Cabin - Mon exemple App +).

  5. Entrez votre * Email de contact *.

  6. Pour * Catégorie *, utilisez le menu déroulant pour sélectionner une catégorie pour l’application. Dans notre cas, c’est * Style de vie *.

  7. Cliquez sur le bouton * Créer un identifiant d’application *.

  8. Si nécessaire, complétez le captcha.

  9. Copiez le + appId +. Ce sera une valeur numérique trouvée en haut de l’écran. Vous en aurez besoin sous peu.

  10. Choisissez * Tableau de bord * dans la barre latérale gauche.

  11. Sous le titre * Premiers pas avec le Kit de développement logiciel (SDK) Facebook *, cliquez sur * Choisissez une plate-forme *.

  12. Choisissez * Web * pour la plate-forme.

  13. Localisez le champ * URL du site * et entrez + http: // cabin.example.com +.

  14. Cliquez sur Suivant*.

Si vous rencontrez des problèmes, vous pouvez suivre ce guide étape par étape. Si vous êtes bloqué, vous trouverez un excellent article sur le débogage de la configuration de votre application sur Facebook à l’adresse suivante: here.

Une fois que vous avez votre + appID +, vous devrez remplacer le paramètre + appID + par défaut sur le serveur.

Assurez-vous donc que vous êtes connecté à votre serveur. Si ce n’est pas le cas, reconnectez-vous avec:

ssh cabin@

Une fois connecté, ouvrez le fichier + ~ / stream-react-example / app / views / index.ejs +:

nano ~/stream-react-example/app/views/index.ejs

Changez la valeur par défaut + appId + avec celle fournie par Facebook.

strea-react-example / app / views / index.ejs

FB.init({
   appId   : ,
   xfbml   : true,
   version : 'v2.6',
   status  : true,
   cookie  : true,
})

Enregistrez ce fichier et fermez-le.

Ensuite, vous devez connaître le mot de passe de la base de données Cabin, qui a été généré par Terraform lors de la création du serveur. Pour obtenir cette valeur, tapez la commande suivante:

grep DB_PASSWORD processes.yml

Copiez ce mot de passe; vous en aurez besoin bientôt.

Le fichier + env.sh + est l’endroit où vous allez saisir vos identifiants pour les différents fournisseurs et services dont dépend Cabin. Ce fichier place ces informations d’identification dans des variables d’environnement, qui sont ensuite lues par l’application. Ceci est une précaution de sécurité, car il garde les mots de passe et les clés hors de Git.

Ouvrez + env.sh +:

nano env.sh

Vous verrez le contenu suivant:

Outputexport NODE_ENV=production
export JWT_SECRET=ABC123
export DB_USERNAME=cabin
export DB_HOST=localhost
export DB_PASSWORD=VALUE
export DB_PORT=3306
export MAPBOX_ACCESS_TOKEN=ADD_VALUE_HERE
export S3_KEY=ADD_VALUE_HERE
export S3_SECRET=ADD_VALUE_HERE
export S3_BUCKET=ADD_VALUE_HERE
export STREAM_APP_ID=ADD_VALUE_HERE
export STREAM_KEY=ADD_VALUE_HERE
export STREAM_SECRET=ADD_VALUE_HERE
export ALGOLIA_APP_ID=ADD_VALUE_HERE
export ALGOLIA_SEARCH_ONLY_KEY=ADD_VALUE_HERE
export ALGOLIA_API_KEY=ADD_VALUE_HERE
export KEEN_PROJECT_ID=ADD_VALUE_HERE
export KEEN_WRITE_KEY=ADD_VALUE_HERE
export KEEN_READ_KEY=ADD_VALUE_HERE
export IMGIX_BASE_URL=https://react-example-app.imgix.net/uploads
export API_URL=http://localhost:8000

Comme vous pouvez le constater, ce fichier exporte de nombreuses variables d’environnement contenant des informations sur les différents services nécessaires à Cabin. Pour que Cabin fonctionne en production, vous devez renseigner toutes ces valeurs.

Voici un aperçu rapide de ces paramètres:

  1. * NODE_ENV *: Environnement dans lequel Node.js s’exécutera. (la production offrira une amélioration de la vitesse).

  2. * JWT_SECRET *: secret d’authentification pour l’authentification de jeton Web JSON entre l’API et l’interface Web (app).

  3. * DB_USERNAME *: nom d’utilisateur de la base de données.

  4. * DB_HOST *: nom d’hôte de la base de données.

  5. * DB_PASSWORD *: Le mot de passe de la base de données, que vous venez de visualiser en regardant +ocess.yml +.

  6. * DB_PORT *: Port de base de données (port par défaut 3306 pour MySQL).

  7. * MAPBOX_ACCESS_TOKEN *: Jeton d’accès à MapBox (pour la cartographie des emplacements de photos).

  8. * S3_KEY *: clé Amazon S3 pour le stockage d’images.

  9. * S3_SECRET *: secret Amazon S3 pour le stockage d’images.

  10. * S3_BUCKET *: compartiment Amazon S3 pour le stockage d’images. Assurez-vous que ce seau existe.

  11. * STREAMAPPID *: ID de l’application en streaming. Assurez-vous que tous les groupes de flux requis existent dans l’application associée à cet ID.

  12. * STREAM_KEY *: clé API de flux.

  13. * STREAM_SECRET *: secret de l’application de flux.

  14. * ALGOLIA_APP_ID *: Identifiant d’application Algolia pour la recherche.

  15. * ALGOLIA_SEARCH_ONLY_KEY *: Algolia recherche uniquement la clé de recherche.

  16. * ALGOLIA_API_KEY *: clé API Algolia pour la recherche.

  17. * KEEN_PROJECT_ID *: Identifiant de projet suivi attentif (pour les statistiques).

  18. * KEEN_WRITE_KEY *: clé d’écriture de suivi (pour les statistiques).

  19. * KEEN_READ_KEY *: clé de lecture de suivi dynamique (pour les statistiques).

  20. * IMGIX_BASE_URL *: URL de base Imgix (pour le rendu de photos de tailles spécifiques).

  21. * API_URL *: l’URL utilisée par cette application pour son API. Vous devrez changer ceci de + localhost + au domaine qui pointe vers votre adresse IP, tel que + cabin.example.com +.

Pour plus de détails sur les variables d’environnement et les services référencés, visitez les articles de blog suivants et vérifiez que vous avez configuré chaque application comme indiqué:

Une fois que vous avez configuré tous les fournisseurs, entrez le mot de passe de votre base de données et les valeurs des fournisseurs dans le fichier + env.sh +.

Quittez et enregistrez le fichier + env.sh +. Puis sourcez le fichier, en chargeant les valeurs dans les valeurs d’environnement que Cabin utilisera:

source ./env.sh

Ensuite, vous devrez exécuter la commande + webpack +. Webpack est un outil de construction JavaScript qui gère le code frontal de Cabin. Webpack régénérera les fichiers JavaScript et CSS en fonction des valeurs définies par le fichier + env.sh + que vous venez de modifier. Donc, allez dans le répertoire + app +:

cd app

Puis exécutez la commande + webpack + pour reconstruire les fichiers JavaScript frontaux. Cela injectera certains des jetons de fournisseur dans le code frontal.

webpack --progress --color

Vous verrez la sortie suivante:

OutputHash: 64dcb6ef9b46a0243a8c
Version: webpack 1.13.1
Time: 21130ms
                 Asset     Size  Chunks             Chunk Names
    ./public/js/app.js  2.22 MB       0  [emitted]  app
./public/css/styles.css    23 kB       0  [emitted]  app
  [0] multi app 28 bytes {0} [built]
   + 685 hidden modules
Child extract-text-webpack-plugin:
       + 2 hidden modules
Child extract-text-webpack-plugin:
       + 2 hidden modules

Une fois les paramètres en place, exécutez PM2 pour recharger tous les processus de l’application afin de vous assurer que tous les composants utilisent les nouveaux paramètres:

pm2 restart all
Output[PM2] Applying action restartProcessId on app [all](ids: 0,1,2)
[PM2] [api](0) ✓
[PM2] [app](1) ✓
[PM2] [www](2) ✓
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid   │ status │ restart │ uptime │ memory      │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ api      │ 0  │ fork │ 30834 │ online │ 516     │ 0s     │ 39.027 MB   │  enabled │
│ app      │ 1  │ fork │ 30859 │ online │ 9       │ 0s     │ 22.504 MB   │  enabled │
│ www      │ 2  │ fork │ 30880 │ online │ 9       │ 0s     │ 19.746 MB   │  enabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘

C’est ça! Vous pouvez maintenant vous déconnecter de votre serveur distant.

exit

Enfin, rendez-vous à la page + http: // + dans votre navigateur pour voir le site. Cela affichera une image de couverture avec un lien pour vous connecter à Facebook. Une fois connecté, vous pourrez explorer l’application plus tard.

Passons maintenant à la configuration de Terraform qui a rendu ce déploiement possible.

Étape 6 - Exploration des tuiles de configuration

Alors, comment est-ce que tout ça fonctionne? Examinons les fichiers du référentiel que nous avons clonés sur notre ordinateur local. Bien que vous n’ayez rien à modifier dans cette section, vous devez tout de même suivre sur votre propre machine pour avoir une idée de la façon dont les pièces s’assemblent.

Le projet Terraform est divisé en plusieurs fichiers et répertoires pour que l’application reste propre et facile à comprendre. Nous avons placé tous nos fichiers DigitalOcean dans le répertoire + terraform / do + du référentiel, qui présente la structure suivante:

dossier terraform

do
└── cabin
   ├── files
   │   ├── cabin-web-nginx.conf
   │   └── cabin_mysql_init.sh
   ├── main.tf
   ├── outputs.tf
   ├── templates
   │   ├── processes.tpl
   │   └── web.tpl
   └── variables.tf

Regardons les fichiers ci-dessus, en commençant par + main.tf +. Ouvrez-le dans votre éditeur de texte préféré.

La première chose à faire est de dire à Terraform le fournisseur de cloud que nous allons utiliser.

main.tf

provider "DigitalOcean" {
 token = "${var.token}"
}

Définir le fournisseur DigitalOcean est aussi simple que cela. Vous pouvez trouver la liste complète des fournisseurs pris en charge dans la documentation Terraform.

Configuration variable

Terraform vous permet de définir des variables, ce qui signifie que vous pouvez définir des valeurs par défaut pour votre déploiement. De cette façon, vous ne devrez pas entrer les détails à chaque fois ou les valeurs en dur dans votre configuration. Voyons comment définir les variables pour le déploiement sur DigitalOcean.

Jetez un coup d’oeil à + ​​variables.tf +, l’emplacement où nous avons défini les variables nécessaires à l’exécution de l’application Cabin.

variables.tf

variable "token" {
 description = "DO Token"
}

variable "region" {
 description = "DO Region"
}

Pour vous aider à mieux comprendre le traitement des variables dans Terraform, passons à l’exemple ci-dessus.

Pour la variable région, nous avons spécifié une valeur par défaut. Si vous ne spécifiez pas de valeur par défaut, Terraform vous en demandera une, comme indiqué dans l’exemple suivant:

Outputterraform plan
var.token
 DO Token

 Enter a value:

Vous pouvez également fournir des variables lorsque vous exécutez + terraform apply +. Par exemple, si vous souhaitez spécifier une autre région, vous pouvez exécuter Terraform avec l’argument + var +:

terraform -var 'region=ams3' apply

Cela remplace tous les paramètres configurés.

Configuration des gouttelettes

Dans + main.tf +, nous demandons à Terraform de fournir un Droplet sous DigitalOcean. Par défaut, nous déployons un serveur présentant les caractéristiques suivantes:

main.tf

resource "digitalocean_droplet" "cabin-web" {
 image = "ubuntu-14-04-x64"
 name = "cabin-web"
 region = "${var.region}"
 size = "2gb"
 ssh_keys = [ "${digitalocean_ssh_key.cabin-ssh-key.id}" ]
 user_data = "${template_file.userdata_web.rendered}"
}

Nous créons un nouveau droplet DigitalOcean avec 2 Go de RAM appelé * cabin-web *, et utilisons l’image * ubuntu-14-04-x64 *. En consultant la définition de ressource ci-dessus, vous constaterez qu’il est facile de modifier l’image et la taille du serveur.

Données utilisateur et Cloud-Init

Ok, alors qu’est-ce que + user-data? C’est le moyen le plus simple d’envoyer des commandes et des instructions à une instance de cloud au démarrage. Couplé avec + cloud-init +, il devient un moyen puissant de configurer votre instance sans tirer parti d’applications tierces inutiles telles que Chef ou https://puppet.com/ [Fantoche].

Le programme + cloud-init + est intégré à de nombreuses distributions Linux. Il contient un petit ensemble d’instructions qui vous permettent d’effectuer des tâches simples, telles que l’ajout d’utilisateurs, la gestion de groupes, la création de fichiers et l’exécution de scripts ou de commandes shell avec les privilèges root.

Explorons l’attribut + user_data + afin d’avoir une meilleure compréhension de ce que c’est:

main.tf

resource "digitalocean_droplet" "cabin-web" {
 ...
 user_data = "${template_file.userdata_web.rendered}"
}

Notre objectif est de démarrer un nouveau Droplet avec Cabin, et de laisser ` cloud-init + `gérer le gros du travail pour nous. Le champ `+ user_data + pointe vers un fichier de gabarit, tandis qu’une variable pointe vers une autre déclaration dans + main.tf +:

main.tf

resource "template_file" "userdata_web" {
 template = "${file("${path.module}/templates/web.tpl")}"

 vars {
   userdata_sshkey = "${var.sshkey}"
   userdata_nginx_conf = "${base64encode(file("${path.module}/files/cabin-web-nginx.conf"))}"
   userdata_mysql_init = "${base64encode(file("${path.module}/files/cabin_mysql_init.sh"))}"
   userdata_pm2_conf = "${base64encode("${template_file.pm2_processes_conf.rendered}")}"
   userdata_env = "${base64encode("${template_file.env.rendered}")}"
   userdata_motd = "${base64encode(file("${path.module}/files/motd"))}"
   userdata_motd_script = "${base64encode(file("${path.module}/files/motd.sh"))}"
   userdata_giturl = "${var.git_url}"
   userdata_index = "${base64encode(file("${path.module}/files/index.html"))}"
 }
}

Terraform fournit des fonctions qui vous permettent de transformer du texte. Nous pouvons utiliser cette fonctionnalité pour injecter des valeurs dans les modèles en lisant des fichiers, puis en convertissant le contenu en chaînes codées en Base64 afin qu’elles puissent être transférées via des appels d’API.

Cette section particulière prépare les données pour le modèle + templates / web.tpl + qui contient tous les paramètres et les commandes à exécuter sur le serveur.

Parcourons le fichier + web.tpl + et voyons ce qu’il fait.

La première partie configure l’utilisateur initial et désactive l’accès root:

templates / web.tpl

#cloud-config
users:
 - name: cabin
   groups: sudo
   sudo: ['ALL=(ALL) NOPASSWD:ALL']
   shell: /bin/bash
   home: /home/cabin
   lock_passwd: true
   ssh-authorized-keys:
     - ${userdata_sshkey}

disable_root: true

La toute première déclaration dans + web.tpl doit être` + # cloud-config`. Si vous oubliez d’ajouter ceci, + cloud-init + ne prendra pas la configuration et les commandes données ne seront pas exécutées sur l’instance cible.

Les commandes de cette section ont les effets suivants:

  • ajouter l’utilisateur + cabin + au système avec une subvention pour devenir un superutilisateur

  • + lock-passwd: true + refuse l’authentification par mot de passe, l’utilisateur + cabin + devra donc utiliser l’authentification par clé SSH pour accéder au serveur.

  • + ssh-allowed-keys + installe la clé ssh de l’utilisateur dans le fichier allowed_keys.

  • + disable_root: true + est utilisé pour désactiver l’accès SSH en tant que root

Rappelez-vous que + $ {userdata_sshkey} + est une variable qui a été définie lorsque nous avons appelé le modèle dans + main.tf +.

Ensuite, nous installons MySQL, Nginx, Git et les autres packages nécessaires à notre application:

package_update: true
packages:
- mysql-server-5.6
- libmysqlclient-dev
- iptables-persistent
- git
- nginx
- npm
- pwgen

Le moyen le plus simple d’installer des packages avec + cloud-init + consiste à utiliser le module Package pour installer une liste de packages donnés. Ce module utilise le gestionnaire de paquets par défaut pour la distribution. Puisque nous utilisons Ubuntu, ce processus installera les paquets avec + apt +.

Ensuite, nous écrivons des fichiers dans le système de fichiers, en utilisant les données que nous avons transmises au modèle en tant que contenu du fichier:

write_files:
- encoding: b64
  content: ${userdata_nginx_conf}
  path: /tmp/cabin-web.conf
- encoding: b64
  content: ${userdata_pm2_conf}
  path: /tmp/processes.yml
- encoding: b64
  content: ${userdata_mysql_init}
  path: /tmp/cabin_mysql_init.sh
  permissions: '0554'

Cette section exploite le module + write_file + pour créer les fichiers. Dans l’exemple ci-dessus, nous créons les fichiers suivants:

  • + cabin-web.conf + contient la configuration de NGINX.

  • +ocess.yml + utilisé par PM2 pour gérer les processus Node.js.

  • + cabin_mysql_init.sh + est un script personnalisé utilisé pour initialiser la base de données MySQL.

Rappelez-vous que lorsque nous avons transmis les données au modèle, nous les avons codées en tant que Base64. Nous spécifions le codage lorsque nous écrivons les fichiers afin que le contenu puisse être décodé.

Dans la section suivante, nous utilisons le module + runcmd + pour exécuter des commandes shell afin de créer des règles de pare-feu en utilisant + iptables +:

runcmd:
- iptables -A INPUT -i lo -j ACCEPT
- iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
- iptables -A INPUT -p tcp --dport ssh -j ACCEPT
- iptables -A INPUT -p tcp --dport 80 -j ACCEPT
- iptables -A INPUT -p tcp --dport 8000 -j ACCEPT
- iptables -A INPUT -p tcp --dport 3000 -j ACCEPT
- iptables -A INPUT -j DROP
- iptables -A OUTPUT -j ACCEPT
- invoke-rc.d iptables-persistent save
…

Le code utilise ensuite + iptables-persistent + pour rendre la configuration du pare-feu disponible au cas où l’instance redémarre.

Une fois les règles de pare-feu en place, les autres commandes permettant de configurer et de démarrer Cabin sont exécutées:

- apt-get update --fix-missing
- curl -sL https://deb.nodesource.com/setup_5.x | bash && apt-get install -y nodejs
- npm install pm2 webpack -g
- cd /home/cabin && sudo -u cabin git clone ${userdata_giturl}
- mv /tmp/env.sh /home/cabin/stream-react-example/env.sh
- cd /home/cabin/stream-react-example/api && sudo -u cabin npm install
- cd /home/cabin/stream-react-example/app && sudo -u cabin npm install
- cd /home/cabin/stream-react-example/www && sudo -u cabin npm install
- chown cabin.cabin /home/cabin/stream-react-example/env.sh && /home/cabin/stream-react-example/env.sh
- mv /tmp/processes.yml /home/cabin/stream-react-example/processes.yml
- chown cabin.cabin /home/cabin/stream-react-example/processes.yml
- /tmp/cabin_mysql_init.sh
- cd /home/cabin/stream-react-example && sudo -u cabin pm2 start processes.yml
- mv /tmp/cabin-web.conf /etc/nginx/sites-available/cabin-web
- rm /etc/nginx/sites-enabled/default
- ln -s /etc/nginx/sites-available/cabin-web /etc/nginx/sites-enabled
- service nginx reload

Toutes ces commandes sont exécutées avec les privilèges root et ne se produisent que lors du tout premier démarrage. Si vous redémarrez la machine, + runcmd + ne sera pas exécuté à nouveau.

Maintenant que vous en avez appris plus sur Terraform, voyons comment gérer le cycle de vie de votre infrastructure.

Étape 7 - Gestion du cycle de vie de la pile

Terraform permet d’enregistrer l’état de votre pile, de la mettre à jour, de la détruire et de déployer les modifications de code.

Vous avez peut-être remarqué qu’après l’exécution de + terraform apply +, un fichier nommé + terraform.tfstate + est créé dans le répertoire + cabin +.

Ce fichier est très important car il contient les références aux ressources réelles créées sur DigitalOcean. Fondamentalement, ce fichier indique à Terraform les identifiants des ressources qu’il gère.

Si vous exécutez à nouveau + terraform apply +, Terraform ne recommencera pas et n’effacera pas tout ce que vous avez créé. Au lieu de cela, il ne fera que les parties qu’il n’a pas encore terminées. Ainsi, si votre processus échoue au milieu en raison d’un problème de réseau ou d’un problème d’API, vous pouvez résoudre les problèmes et réexécuter la commande. Terraform reprendra là où il s’était arrêté.

Changer la configuration des gouttelettes

Vous pouvez également utiliser + terraform apply + pour modifier la configuration de Droplet. Par exemple, si vous devez modifier des centres de données ou des régions, ou augmenter la mémoire utilisée par votre Droplet afin de gérer davantage de trafic, Terraform simplifie considérablement les deux tâches.

Vous pouvez ajuster la région Droplet en exécutant la commande + terraform apply + et en remplaçant les variables + region + et + droplet_size +. Cela permet à Terraform de savoir que le Droplet existant doit être détruit et qu’un nouveau Droplet doit être mis en service afin de répondre aux exigences.

Si vous souhaitez modifier la région ou le centre de données qui contient votre Droplet, exécutez la commande suivante:

terraform apply

De plus, à mesure que votre base d’utilisateurs s’agrandit, vous devrez probablement modifier la taille de la gouttelette pour l’adapter au trafic supplémentaire. Vous pouvez le faire avec la variable + droplet_size + comme ceci:

terraform apply

Le droplet sera supprimé et remplacé par un nouveau, et l’application sera redéployée et configurée.

Détruire la pile

L’un des aspects les plus intéressants de Terraform est qu’il gère l’ensemble du cycle de vie de la pile. Vous pouvez facilement détruire ce que vous avez construit en exécutant une simple commande Terraform (détruire).

terraform destroy

Terraform vous invitera ensuite à confirmer que vous souhaitez réellement détruire toutes les ressources:

OutputDo you really want to destroy?
 Terraform will delete all your managed infrastructure.
 There is no undo. Only 'yes' will be accepted to confirm.

 Enter a value: yes

Une fois Terraform terminé, le résultat final se présentera comme suit:

Outputdigitalocean_droplet.cabin-web: Destroying...
digitalocean_droplet.cabin-web: Still destroying... (10s elapsed)
digitalocean_droplet.cabin-web: Destruction complete
digitalocean_ssh_key.cabin-ssh-key: Destroying...
template_file.userdata_web: Destroying...
template_file.userdata_web: Destruction complete
template_file.pm2_processes_conf: Destroying...
template_file.pm2_processes_conf: Destruction complete
digitalocean_ssh_key.cabin-ssh-key: Destruction complete

Apply complete! Resources: 0 added, 0 changed, 5 destroyed.

Comme vous pouvez le constater, toutes les ressources ont été détruites.

Déploiement de nouvelles versions de code

Si vous apportez des modifications à votre base de code, vous devrez les transmettre au serveur avec un temps d’immobilisation minime, voire nul. Nous avons PM2 installé sur notre serveur et il s’occupe de la lourde tâche qui nous incombe.

PM2 écoute les modifications du système de fichiers dans l’application. Pour exécuter une version plus récente de votre code, il suffit de SSH dans Droplet et exécutez la commande + git pull + dans le répertoire contenant l’application. Cela demandera au serveur de tirer de votre référentiel. Lorsque les fichiers changent, PMZ redémarre automatiquement le processus de nœud.

Par exemple, s’il existe une nouvelle version de Cabin et que vous souhaitez déployer la dernière version du code sur le serveur, vous devez vous connecter à votre serveur:

ssh cabin@

Ensuite, sur le serveur, accédez au dossier contenant l’application Cabin:

cd ~/stream-react-example

Et enfin, retirez la dernière version.

git pull

Une fois le nouveau code en place, votre application redémarrera automatiquement et les visiteurs verront la version la plus récente. Si, pour une raison quelconque, PM2 ne détecte aucune modification, redémarrez-le manuellement.

pm2 restart all

et tous les composants vont redémarrer.

Conclusion

Avec DigitalOcean, Terraform, Cloud-init et PM2, vous avez réussi à configurer un environnement de production pour Cabin.

Lorsque vous utilisez Terraform, toute votre infrastructure est stockée sous forme de code. Cela facilite pour votre équipe le suivi des modifications et la collaboration. Il vous permet également d’apporter de grandes modifications à votre infrastructure avec une relative facilité.

Related