Как развернуть приложение Node.js с помощью Terraform в Ubuntu 14.04

Статья из Stream

Вступление

С помощью инструментов оркестровки профессионалы DevOps могут развернуть стек, используя несколько вызовов API. Terraform - очень простой, но мощный инструмент, который позволяет вам записывать свой стек в виде кода, а затем делиться им и обновлять его, фиксируя файлы определений с помощью https: //git-scm.com/[Git]. Terraform создан HashiCorp, авторами популярных инструментов с открытым исходным кодом, таких как Vagrant, https: //www.packer. io / [Packer] и Consul.

Terraform предоставляет общую конфигурацию для запуска вашей инфраструктуры, от физических и виртуальных серверов до провайдеров электронной почты и DNS. После запуска Terraform безопасно и эффективно меняет инфраструктуру по мере развития конфигурации.

Из этого туториала Вы узнаете, как настроить среду для полнофункционального, сложного приложения Node.js, используя https://digitalocean.com [DigitalOcean], https: // www. terraform.io/[Terraform], Cloud-init и PM2 в Ubuntu 14.04. В качестве нашего примера приложения мы будем использовать http://cabin.getstream.io [Cabin], открытый исходный код React & http: //redux.js. org / docs / basics / UsageWithReact.html [Redux] Приложение Node.js, разработанное http://getstream.io [GetStream.io]. Окончательный результат будет многофункциональным, масштабируемым приложением для социальных сетей!

Вы начнете с использования Terraform для развертывания Cabin с использованием предопределенной конфигурации. Затем вы глубоко погрузитесь в эту конфигурацию, чтобы узнать, как она работает.

Если вы заинтересованы только в установке Terraform на вашем сервере DigitalOcean, см. Https://www.digitalocean.com/community/tutorials/how-to-use-terraform-with-digitalocean[How для использования Terraform с DigitalOcean].

Предпосылки

Чтобы следовать этому уроку, вам понадобится:

  • Один 2-гигабайтный сервер Ubuntu 14.04, который вы создадите в этом руководстве с помощью Terraform.

  • Клиент Git установлен на вашем локальном компьютере.

  • Учетная запись Facebook, так что вы можете создать приложение Facebook, так как Cabin использует Facebook для входа в систему.

  • Домен, такой как + cab.example.com +; вы указываете этот домен на IPv4-адрес, который вы получите на шаге 4, и он понадобится вам для URL сайта в Facebook.

Хотя это руководство не является обязательным, предполагается, что вы завершили серию учебных пособий Stream’s Cabin. Вам понадобятся ключи API и настройки для нескольких провайдеров, которые необходимы Cabin для работы в производстве, поскольку они играют неотъемлемую роль в функционировании Cabin.

Для получения дополнительной информации об этих услугах, пожалуйста, не стесняйтесь посетить следующие сообщения в блоге от Stream:

Шаг 1 - Получение примера приложения

Клонируйте пример приложения Cabin с GitHub в каталог по вашему выбору на локальном компьютере. Мы используем Mac и предполагаем, что вы тоже.

Сначала перейдите в свой домашний каталог.

cd ~

Затем используйте + git + для клонирования репозитория:

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

Это клонирует пример приложения в новую папку с именем + stream-реагировать-пример +. Перейдите в папку «+ stream-реагировать-пример / terraform / do / Cab +», которая содержит проект Terraform в кабине.

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

Мы немного поработаем с этой папкой. Но сначала давайте настроим Terraform.

Шаг 2 - Установка Terraform

Для простой установки в OSX вы можете установить Terraform, используя Homebrew, введя следующую команду:

brew install terraform

Кроме того, вы можете скачать Terraform с http://terraform.io. Как только вы загрузите его, сделайте его доступным для вашего командного пути, как показано ниже.

PATH=:$PATH

Это временно добавляет Terraform к вашему пути. Если вы хотите, чтобы это изменение было постоянным, отредактируйте файл + ~ / .bash_profile + в OSX и добавьте следующую строку:

~ / .Bash_profile

export PATH=:$PATH

Затем, чтобы проверить, что Terraform был установлен правильно, выполните следующую команду:

terraform

Вы увидите следующий вывод, показывающий опции 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

Прежде чем Terraform сможет запустить вашу инфраструктуру, нам нужно настроить две вещи:

Итак, давайте сначала позаботимся о токене DigitalOcean.

Шаг 2 - Настройка токена доступа DigitalOcean

Terraform необходим ваш токен доступа DigitalOcean для использования API DigitalOcean.

Войдите в свою учетную запись DigitalOcean и нажмите ссылку * API *. Затем нажмите кнопку * Generate New Token *. Не забудьте проверить * Доступ для записи *. Пользовательский интерфейс отобразит новый ключ доступа, который вы должны скопировать в буфер обмена, так как ключ не будет виден, если вы снова зайдете на страницу.

Теперь откройте файл + variables.tf + в вашем любимом текстовом редакторе и найдите раздел + token +:

variables.tf

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

Добавьте новую строку, начинающуюся с текста + default = +, и включите свой токен API DigitalOcean. Не забудьте окружить токен кавычками.

variables.tf

variable "token" {
 description = "DO Token"

}

Сохраните и закройте файл.

Теперь давайте настроим Terraform для использования нашей пары ключей SSH.

Шаг 3 - Добавьте свою пару ключей SSH

Terraform нужен SSH-ключ для подключения к нашему серверу после его создания, чтобы он мог устанавливать пакеты и развертывать приложение.

Посмотрите в директории + ~ / .ssh +, чтобы увидеть, есть ли у вас пара ключей:

ls -al ~/.ssh

Скорее всего, у вас есть хотя бы одна пара ключей, состоящая из закрытого и открытого ключа. Например, у вас могут быть + id_rsa.pub + и + id_rsa +.

Если у вас нет пар ключей или если ключ у вас уже связан с вашей учетной записью DigitalOcean, перейдите по ссылке https://www.digitalocean.com/community/tutorials/how-to-use-ssh-. keys-with-digitalocean-droplets [Руководство DigitalOcean по настройке ключей SSH] для его установки.

Вам нужно вставить содержимое файла + .pub + в файл + variables.tf +, как вы это делали с токеном API. Если вы работаете на Mac, вы можете скопировать свой открытый ключ SSH в буфер обмена, введя следующую команду:

pbcopy < ~/.ssh/

Вы также можете отобразить содержимое открытого ключа на экране с помощью команды + cat + и скопировать его в буфер обмена вручную:

cat  ~/.ssh/

Затем откройте файл + variables.tf + в вашем редакторе и добавьте содержимое вашего файла открытого ключа SSH в настройку + sshkey +:

variables.tf

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

}

После завершения этого шага сохраните и закройте файл.

Если вы сгенерировали новый ключ для использования с Terraform и DigitalOcean, вам нужно будет выполнить эти две команды, чтобы вместо вашего ключа по умолчанию использовался ваш новый ключ:

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

Возможно, вам придется запускать это каждый раз, когда вы открываете новую оболочку, если вы используете альтернативную пару ключей.

Теперь, когда вы предоставили Terraform необходимые переменные, вы готовы создать свой сервер и развернуть приложение с помощью Terraform.

Шаг 4 - Запуск Terraform

Здесь начинается самое интересное! Давайте посмотрим на инфраструктуру, которую мы собираемся построить. Terraform собирается сделать для нас большую работу, от настройки нашего сервера до развертывания нашего приложения. Мы можем заставить Terraform показать нам, что именно он собирается делать, с помощью следующей команды:

terraform plan

Вывод этой команды довольно многословен, поэтому постарайтесь сосредоточиться на следующих утверждениях:

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
...

Символ «» в начале строки означает, что ресурсы будут созданы. Ресурсы с префиксом ` digitalocean +` - это ресурсы, которые будут созданы в DigitalOcean. В этом конкретном случае Terraform создаст Droplet, плавающий IP, и добавит наш SSH-ключ.

Теперь пришло время запустить Terraform и раскрутить Cabin на вашей капле.

terraform apply

Через некоторое время вы увидите, как Terraform распечатает следующее:

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 + - это плавающий IP-адрес, который вы можете использовать для доступа к дроплету.

Войдите во вновь созданную Droplet, используя значение, которое вы видите для ++:

ssh cabin@

Вы также можете использовать команду

terraform output web_ipv4

отображать IP-адрес, связанный с этим значением, если вы его пропустили.

При входе в систему вы увидите это приветственное сообщение:

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

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

Возможно, вам придется подождать несколько минут, чтобы DigitalOcean предоставил экземпляр и + cloud-init + установил необходимые пакеты для Cabin. Но как только он будет готов, вы увидите это:

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

Когда Cabin запущен и работает, наведите в своем мобильном браузере на «+ http: // +». Кабина жива, и вы должны увидеть загрузочный экран. Но это все, что мы получим, пока не внесем некоторые изменения в код на сервере.

Шаг 5 - (опционально) Настройка Cabin

Приложение Cabin развернуто, но его пока нельзя использовать. Мы должны настроить Facebook и несколько других сервисов, если мы хотим, чтобы Cabin работал в полную силу.

Во-первых, вам нужно создать приложение Facebook с использованием действительного доменного имени, например + cab.example.com +, которое сопоставлено с адресом + web_ipv4 +, который был создан в процессе установки. Добавьте запись в свой DNS или добавьте запись в файл + / etc / hosts +, которая сопоставляет ваш домен с IP-адресом.

Чтобы создать приложение Facebook, выполните следующие действия.

  1. Посетите https://developers.facebook.com/docs/apps/register#step-by-step-guide.

  2. Зайди в Фейсбук.

  3. В разделе Мои приложения нажмите * Добавить новое приложение *.

  4. Введите имя для вашего приложения (например, + Cabin - Мой пример приложения +).

  5. Введите свой * контактный адрес электронной почты *.

  6. Для * Категория * используйте раскрывающееся меню, чтобы выбрать категорию для приложения. В нашем случае это «Стиль жизни».

  7. Нажмите кнопку * Создать идентификатор приложения *.

  8. При необходимости заполните капчу.

  9. Скопируйте + appId +. Это будет числовое значение, найденное в верхней части экрана. Вам это понадобится в ближайшее время.

  10. Выберите * Dashboard * на левой боковой панели.

  11. Под заголовком * Начало работы с Facebook SDK * нажмите * Выбрать платформу *.

  12. Выберите * Web * для платформы.

  13. Найдите поле * Site URL * и введите + http: // cab.example.com +.

  14. Нажмите кнопку "Далее*.

Если у вас возникнут проблемы, вы можете следовать ths пошаговое руководство. Если вы застряли, есть отличная статья об отладке настроек вашего приложения на Facebook, которую можно найти по адресу here.

Когда у вас есть + appID +, вам нужно заменить стандартную настройку + appID + на сервере.

Итак, убедитесь, что вы вошли на свой сервер. Если вы этого не сделаете, войдите в систему с помощью:

ssh cabin@

После входа откройте файл + ~ / stream-реагировать-пример / app / views / index.ejs +:

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

Измените + appId + по умолчанию на тот, который предоставлен Facebook.

Strea-реагирующие-пример / приложение / просмотров / index.ejs

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

Сохраните этот файл и закройте его.

Затем вам нужно будет знать пароль базы данных для Cabin, который был сгенерирован Terraform при создании сервера. Чтобы получить это значение, введите следующую команду:

grep DB_PASSWORD processes.yml

Скопируйте этот пароль; Вам это понадобится в ближайшее время.

В файле + env.sh + вы вводите свои учетные данные для различных поставщиков и услуг, от которых зависит Cabin. Этот файл помещает эти учетные данные в переменные среды, которые затем считываются приложением. Это мера безопасности, поскольку она хранит пароли и ключи вне Git.

Откройте + env.sh +:

nano env.sh

Вы увидите следующее содержание:

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

Как видите, этот файл экспортирует множество переменных среды, которые содержат информацию о различных сервисах, которые нужны Cabin. Чтобы кабина работала в производстве, вам необходимо заполнить все эти значения.

Вот краткий перечень этих настроек:

  1. * NODE_ENV *: Среда, в которой будет работать Node.js. (производство предложит увеличение скорости).

  2. * JWT_SECRET *: Секрет аутентификации для аутентификации JSON Web Token между API и веб-интерфейсом (приложения).

  3. * DB_USERNAME *: имя пользователя для базы данных.

  4. * DB_HOST *: имя хоста базы данных.

  5. * DB_PASSWORD *: пароль для базы данных, которую вы только что просмотрели, посмотрев на + process.yml +.

  6. * DB_PORT *: Порт базы данных (порт по умолчанию 3306 для MySQL).

  7. * MAPBOX_ACCESS_TOKEN *: токен доступа для MapBox (для отображения местоположений фотографий).

  8. * S3_KEY *: ключ Amazon S3 для хранения изображений.

  9. * S3_SECRET *: секрет Amazon S3 для хранения изображений.

  10. * S3_BUCKET *: корзина Amazon S3 для хранения изображений. Убедитесь, что это ведро существует.

  11. * STREAMAPPID *: идентификатор потокового приложения. Убедитесь, что в приложении есть все необходимые группы каналов, связанные с этим идентификатором.

  12. * STREAM_KEY *: ключ API потока.

  13. * STREAM_SECRET *: Секрет потокового приложения.

  14. * ALGOLIA_APP_ID *: идентификатор приложения Algolia для поиска.

  15. * ALGOLIA_SEARCH_ONLY_KEY *: Алголия ищет только ключ для поиска.

  16. * ALGOLIA_API_KEY *: ключ API Algolia для поиска.

  17. * KEEN_PROJECT_ID *: острый идентификатор проекта отслеживания (для статистики).

  18. * KEEN_WRITE_KEY *: Ключ записи активного отслеживания (для статистики).

  19. * KEEN_READ_KEY *: Ключ к активному отслеживанию чтения (для статистики).

  20. * IMGIX_BASE_URL *: базовый URL Imgix (для рендеринга фотографий определенного размера).

  21. * API_URL *: URL-адрес, используемый этим приложением для его API. Вам нужно изменить это значение с + localhost + на домен, который указывает на ваш IP-адрес, например + cab.example.com +.

Для получения дополнительной информации о ссылочных переменных среды и службах, посетите следующие посты в блоге и убедитесь, что вы настроили каждое приложение, как указано:

После настройки всех провайдеров введите пароль для своей базы данных и значения для провайдеров в файле + env.sh +.

Выйдите и сохраните файл + env.sh +. Затем создайте исходный файл, загрузив значения в значения окружения, которые Cabin будет использовать:

source ./env.sh

Затем вам нужно выполнить команду + webpack +. Webpack - это инструмент для сборки JavaScript, который управляет кодом внешнего интерфейса для Cabin. Webpack регенерирует файлы JavaScript и CSS на основе значений, установленных только что измененным файлом + env.sh +. Итак, перейдите в каталог + app +:

cd app

А затем выполните команду + webpack +, чтобы перестроить внешние файлы JavaScript. Это вставит некоторые из токенов провайдера в код переднего плана.

webpack --progress --color

Вы увидите следующий вывод:

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

После установки параметров запустите PM2, чтобы перезагрузить все процессы приложения и убедиться, что все компоненты используют новые параметры:

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 │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘

Это оно! Теперь вы можете выйти из вашего удаленного сервера.

exit

Наконец, снова посетите + http: // + в вашем браузере, чтобы увидеть сайт. Будет отображено изображение обложки со ссылкой для входа в Facebook. Как только вы войдете в систему, вы сможете изучить приложение позже.

Теперь давайте углубимся в конфигурацию Terraform, которая сделала возможным это развертывание.

Шаг 6 - Изучение плиток конфигурации

Так как же все это работает? Давайте посмотрим на файлы в хранилище, которое мы клонировали на наш локальный компьютер. Несмотря на то, что вам нечего изменить в этом разделе, вы все равно должны следовать на своем собственном компьютере, чтобы вы могли почувствовать, как части сочетаются друг с другом.

Проект Terraform разделен на несколько файлов и каталогов, чтобы приложение было чистым и простым для понимания. Мы поместили все наши файлы DigitalOcean в каталог + terraform / do + репозитория, который имеет следующую структуру:

папка terraform

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

Давайте посмотрим на вышеуказанные файлы, начиная с + main.tf +. Откройте его в вашем любимом текстовом редакторе.

Первое, что мы делаем, это сообщаем Terraform, какого облачного провайдера мы будем использовать.

main.tf

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

Определить провайдера DigitalOcean так же просто. Вы можете найти полный список поддерживаемых провайдеров в документации Terraform.

Переменная конфигурация

Terraform позволяет вам определять переменные, что означает, что вы можете установить значения по умолчанию для вашего развертывания. Таким образом, вам не нужно будет вводить детали каждый раз или вводить жесткие значения кода в вашей конфигурации. Давайте посмотрим, как установить переменные для развертывания в DigitalOcean.

Взгляните на + variables.tf +, где мы определили переменные, необходимые для запуска приложения Cabin.

variables.tf

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

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

Чтобы помочь вам лучше понять, как обрабатываются переменные внутри Terraform, давайте рассмотрим пример выше.

Для переменной региона мы указали значение по умолчанию. Если вы не укажете значение по умолчанию, Terraform предложит вам указать его, как показано в следующем примере:

Outputterraform plan
var.token
 DO Token

 Enter a value:

Вы также можете указывать переменные, когда запускаете + terraform apply +. Например, если вы хотите указать другой регион, вы можете запустить Terraform с аргументом + var +:

terraform -var 'region=ams3' apply

Это отменяет любые настроенные параметры.

Настройка капли

В + main.tf + мы сообщаем Terraform предоставить Droplet в DigitalOcean. По умолчанию мы развертываем сервер со следующими характеристиками:

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}"
}

Мы создаем новую DigitalOcean Droplet с 2 ГБ оперативной памяти под названием * Cabin-Web * и используем изображение * ubuntu-14-04-x64 *. Взглянув на определение ресурса выше, вы увидите, что легко изменить изображение и размер сервера.

Данные пользователя и Cloud-Init

Хорошо, так что же такое + user-data? Это самый простой способ отправлять команды и инструкции в облачный экземпляр во время загрузки. В сочетании с + cloud-init + он становится мощным способом настройки вашего экземпляра без использования ненужных сторонних приложений, таких как Chef или https://puppet.com/. [Марионетка].

Программа + cloud-init + встроена во многие дистрибутивы Linux. Он содержит небольшой набор инструкций, которые позволяют выполнять простые задачи, такие как добавление пользователей, управление группами, создание файлов и запуск сценариев или команд оболочки с правами root.

Давайте углубимся в атрибут + user_data +, чтобы вы лучше поняли, что это такое:

main.tf

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

Наша цель - запустить новую Droplet с запущенной и работающей кабиной, и заставить + cloud-init + 'справиться с тяжелой работой для нас. Поле `+ user_data + указывает на файл шаблона, а переменная указывает на другое объявление в + 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 предоставляет функции, которые позволяют вам преобразовывать текст. Мы можем использовать эту функцию для вставки значений в шаблоны, читая файлы и затем конвертируя содержимое в строки в кодировке Base64, чтобы их можно было передавать через вызовы API.

Этот конкретный раздел подготавливает данные для шаблона + templates / web.tpl +, который содержит все настройки и команды для выполнения на сервере.

Давайте пройдемся по файлу + web.tpl + и посмотрим, что он делает.

Первая часть настраивает первоначального пользователя и отключает root-доступ:

шаблоны / 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

Самым первым оператором в + web.tpl должно быть` + # cloud-config`. Если вы забудете добавить это, + cloud-init + не подберет конфигурацию, и данные команды не будут выполнены на целевом экземпляре.

Команды в этом разделе делают следующее:

  • добавьте пользователя + Cabin + в систему с грантом, чтобы стать суперпользователем

  • + lock-passwd: true + запрещает аутентификацию по паролю, поэтому пользователю + Cabin + потребуется использовать аутентификацию по SSH-ключу для доступа к серверу.

  • + ssh-авторизованные ключи + устанавливает ssh-ключ пользователя в файл авторизованные ключи.

  • + disable_root: true + используется для отключения доступа SSH от имени пользователя root

Помните, что + $ {userdata_sshkey} + - это переменная, которая была установлена, когда мы вызывали шаблон в + main.tf +.

Далее мы устанавливаем MySQL, Nginx, Git и другие пакеты, необходимые для нашего приложения:

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

Самый простой способ установить пакеты с помощью + cloud-init + - использовать модуль Package для установки списка указанных пакетов. Этот модуль использует менеджер пакетов по умолчанию для распространения. Поскольку мы используем Ubuntu, этот процесс установит пакеты с + apt +.

Затем мы записываем некоторые файлы в файловую систему, используя данные, которые мы передали в шаблон в качестве содержимого файла:

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'

Этот раздел использует модуль + write_file + для создания файлов. В приведенном выше примере мы создаем следующие файлы:

  • + cab-web.conf + содержит конфигурацию NGINX.

  • + projects.yml + используется PM2 для обработки процессов Node.js.

  • + cab_mysql_init.sh + - это собственный скрипт, используемый для инициализации базы данных MySQL.

Помните, что когда мы передавали данные в шаблон, мы кодировали их как Base64. Мы задаем кодировку при записи файлов, чтобы содержимое можно было декодировать.

В следующем разделе мы используем модуль + runcmd + для запуска некоторых команд оболочки для создания правил брандмауэра с использованием + 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
…

Затем код использует + iptables-persistent +, чтобы сделать конфигурацию брандмауэра доступной в случае перезапуска экземпляра.

После того, как правила брандмауэра введены в действие, выполняются остальные команды для настройки и запуска Cabin:

- 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

Все эти команды выполняются с правами суперпользователя и только происходят при первой загрузке. Если вы перезагрузите компьютер, + runcmd + больше не будет выполняться.

Теперь, когда вы узнали больше о Terraform, давайте рассмотрим, как управлять жизненным циклом вашей инфраструктуры.

Шаг 7 - Управление жизненным циклом стека

Terraform позволяет сохранить состояние вашего стека, обновить его, уничтожить и внедрить изменения кода.

Возможно, вы заметили, что после запуска + terraform apply + в каталоге + cab + создается файл с именем + terraform.tfstate +.

Этот файл очень важен, так как содержит ссылки на реальные ресурсы, созданные в DigitalOcean. По сути, этот файл сообщает Terraform идентификаторы ресурсов, которыми он управляет.

Если вы снова запустите + terraform apply +, Terraform не запустится заново и не сотрет все созданное вами. Вместо этого он будет выполнять только те части, которые еще не закончены. Таким образом, если ваш процесс завершается с ошибкой в ​​середине из-за проблем с сетью или API, вы можете устранить проблемы и снова запустить команду. Терраформ подхватит там, где остановился.

Изменение конфигурации капли

Вы также можете использовать + terraform apply +, чтобы изменить конфигурацию дроплета. Например, если вам нужно изменить центры обработки данных или регионы или увеличить объем памяти, используемый вашей Droplet, чтобы вместить больше трафика, Terraform делает обе задачи чрезвычайно простыми.

Вы можете настроить область Droplet, запустив команду + terraform apply + и переопределив переменные + region + и + droplet_size +. Это позволяет Terraform знать, что существующая капля должна быть уничтожена, а новая капля должна быть подготовлена ​​для удовлетворения требований.

Если вы хотите изменить регион или центр обработки данных, в котором находится ваш дроплет, выполните следующую команду:

terraform apply

И, по мере роста вашей пользовательской базы, вам, вероятно, придется изменить размер капли, чтобы приспособиться к дополнительному трафику. Вы можете сделать это с помощью переменной + droplet_size + следующим образом:

terraform apply

Капля будет удалена и заменена на новую, а приложение будет развернуто и настроено.

Уничтожение стека

Одна из замечательных особенностей Terraform заключается в том, что он обрабатывает весь жизненный цикл стека. Вы можете легко уничтожить то, что построили, запустив одну простую команду Terraform (уничтожить).

terraform destroy

Terraform предложит вам подтвердить, что вы действительно хотите уничтожить все ресурсы:

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

После завершения Terraform окончательный результат будет выглядеть следующим образом:

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.

Как видите, все ресурсы были уничтожены.

Развертывание новых версий кода

В случае, если вы вносите изменения в свою кодовую базу, вам нужно будет передать эти изменения на сервер практически без простоев. На нашем сервере установлен PM2, и он справится с тяжелой работой для нас.

PM2 прослушивает изменения файловой системы в приложении. Чтобы запустить более новую версию вашего кода, просто введите SSH в Droplet и введите команду + git pull + в каталоге, содержащем приложение. Это даст команду серверу извлечь из вашего хранилища. Когда файлы изменятся, PMZ автоматически перезапустит процесс Node.

Например, если есть новая версия Cabin, и вы хотите развернуть последнюю версию кода на сервере, вы должны войти на свой сервер:

ssh cabin@

Затем на сервере перейдите к папке, содержащей приложение Cabin:

cd ~/stream-react-example

И, наконец, вытащить последнюю версию.

git pull

Как только новый код будет введен, ваше приложение автоматически перезапустится, и посетители увидят самую новую версию. Если по какой-то причине PM2 не улавливает изменения, перезапустите все вручную с помощью

pm2 restart all

и все компоненты будут перезапущены.

Заключение

Используя DigitalOcean, Terraform, Cloud-init и PM2, вы успешно настроили производственную среду для Cabin.

При использовании Terraform вся ваша инфраструктура сохраняется в виде кода. Это позволяет вашей команде легко отслеживать изменения и сотрудничать. Это также дает вам возможность относительно легко вносить значительные изменения в инфраструктуру.

Related