Ты написал свой веб-сервис. Обложил тестами, дофиксил баги, сделал последние предрелизные коммиты. Теперь нужно его где-то захостить. Конечно, можно особо не напрягаться и выложить его на обычном хостинге или VPS. Но что, если ты, сам того не зная, написал новый Instagram и завтра к тебе придет миллион юзеров? Хорошо бы сразу настроить все по уму: предусмотреть балансировку нагрузки, доставку кода, правила масштабирования. И желательно без сложностей и преждевременной оптимизации. Займемся этим!

 

Зачем это нужно: краткий ликбез

Как известно, у платформы AWS есть множество сервисов на все случаи жизни. Из всего многообразия сегодня нам понадобятся два наиболее популярных:

  • EC2 — система виртуальных инстансов; по своей логике похожа на Digital Ocean, только более гибкая;
  • RDS — система виртуализации реляционных БД в AWS.

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

  • заходим в консоль AWS;
  • выбираем нужный сервис, например EC2;
  • внутри админки EC2 создаем, скажем, два виртуальных инстанса c гигабайтом памяти (в реальности чуть сложнее, но об этом позже);
  • идем в админку сервиса баз данных (RDS);
  • создаем одну базу данных MySQL с гигабайтом памяти;
  • разрешаем нашим инстансам из EC2 ходить к созданной RDS.

Выглядит довольно просто, если понимаешь логику инфраструктуры AWS. Однако на практике управлять всем этим вручную довольно неудобно. Процесс осложняется, если инстансы нужно сгруппировать в балансировщик нагрузки и включить в autoscaling-группу. Кроме того, что все это нужно просто создать и настроить, сервисами надо как-то управлять, надо их мониторить, иметь возможность быстрого масштабирования, желательно автоматического. Вот тут и приходит на помощь Elastic Beanstalk.

 

Что это такое

EBS — это надстройка-оркестратор над сервисами Amazon. Он поможет по заданной конфигурации быстро поднять несколько инстансов нашего приложения, базу данных, связать их с кешем, настроить балансировщик нагрузки и получить агрегированные логи. Всего несколько простых команд из CLI, и через пару минут у нас готово продакшен-окружение и настроенное приложение, которое будет само масштабироваться в зависимости от нагрузки.

Прелесть EBS в том, что он бесплатный. То есть за услуги оркестрации мы не платим ничего, оплачивается только стоимость инстансов по стандартным тарифам EC2.

 

Чем это отличается от Docker или оркестраторов?

Главное отличие EBS в том, что он более высокоуровневый и заточен под типовые кейсы. Если при работе с Docker тебе, скорее всего, нужно будет написать несколько докерфайлов, настроить доступы и продумать логику построения контейнеров на хосте (что не всегда так уж и просто, хотя compose сильно облегчает задачу), то EBS берет все это на себя. Все, что нужно сделать, — это загрузить исходный код приложения, выбрать стек технологий для нее (например, Ruby on Rails или Node.js) и указать команду, которой твое приложение запускается. Все остальное EBS сделает сам. К тому же в твоем распоряжении из коробки окажется вся мощь инфраструктуры Amazon с практически неограниченными ресурсами, а значит — и возможностями масштабирования.

Конечно, EBS с дочерними сервисами — это по логике работы такие же контейнеры, как и Docker. Но под капотом большая разница. Docker — это настоящие, честные изолированные контейнеры, которые могут располагаться на одном хосте — инстансе виртуальной машины. При желании ты сможешь перенести Docker-контейнеры на другой хост (с некоторым количеством телодвижений). А вот EBS — это контейнеры «более низкого уровня», здесь роль контейнера выполняет сам инстанс EC2, внутри которого может хоститься воркер, веб-сервер или реляционная база данных.

 

Приступаем к работе

Процесс работы с EBS довольно прост:

  1. Сначала нужно установить пакет консольных утилит для облегчения работы с EBS. Скачивается с сайта Amazon.
  2. Далее в директории нашего приложения (репозитория) нужно инициализировать новый EBS-проект. В процессе инициализации тебе потребуется выбрать регион, где будет хоститься приложение (Европа, США, Ирландия), стек (Node/Ruby/Python/etc.), количество памяти, диска на один инстанс в пуле балансировщика нагрузки (тип инстанса), а также задать имена для окружения, в котором и будет располагаться твое приложение (например, myapp.dev или myapp.live), и имя самого приложения (например, myapp); результатом будет сгенерированный файл конфигурации, который появится в директории .elasticbeanstalk в корне твоего проекта.
  3. После этого нужно дать команду EBS создать новое окружение и настроить балансировщик нагрузки.
  4. Далее надо закоммитить последние изменения в репозиторий, а затем собственно пушнуть код в EBS.
  5. Через несколько секунд в созданном окружении будет запущено новое приложение, и можно будет проверять работу по URL твоего окружения.

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

 

Из чего состоит EBS-проект?

EBS-проект обычно состоит из двух основных компонентов:

  • директории .elasticbeanstalk, которая содержит глобальные файлы-сценарии для конфигурации проекта и окружения EB: название, типы инстансов, переменные окружения, настройки окружения;
  • директории .exbextensions, которая включает набор файлов-сценариев для конфигурации твоего инстанса. Файлы представляют собой набор инструкций в формате YML, которые запускаются автоматически в момент создания нового инстанса или обновления существующего. Порядок запуска сценариев определяется названием файлов: сначала 001_..., затем 002_... и так далее.

Что могут содержать файлы-конфигурации в .exbextensions? Почти все. Приведу пример задач, которые (по крайней мере у меня) обычно решаются с помощью этих конфигов:

  • определение переменных окружения (см. ниже);
  • компиляция CoffeeScript в JS;
  • миграция базы данных к актуальному состоянию.

Пример такого файла конфигурации (из доков AWS, но показательный):

option_settings:
  - namespace: aws:autoscaling:scheduledaction
    resource_name: ScheduledAction01
    option_name: MinSize
    value: 2
  - namespace: aws:autoscaling:scheduledaction
    resource_name: ScheduledAction01
    option_name: MaxSize
    value: 5
  - namespace: aws:autoscaling:scheduledaction
    resource_name: ScheduledAction01
    option_name: StartTime
    value: "2015-05-14T19:25:00Z"

Каждый узел конфига включает в себя namespace и option_name. Конфиги EBS представляют собой набор значений для предопределенных в документации параметров. Все параметры удобно сгруппированы по неймспейсам. EBS поддерживает следующие неймспейсы:

  • общие опции для контейнеров любых типов;
  • для Docker-контейнеров;
  • для контейнеров на Java с Tomcat;
  • для контейнеров на .NET;
  • для контейнеров на Node.js;
  • для контейнеров на PHP;
  • для контейнеров на Python;
  • для контейнеров на Ruby.

Например, для Node.js (неймспейс aws:elasticbeanstalk:container:nodejs) ты можешь сконфигурировать следующие параметры:

  • NodeCommand — команда, которой будет запускаться твое Node.js-приложение, обычно node app.js;
  • NodeVersion — версия Ноды, которую использовать для запуска приложения (нужно, если инстанс собран на базе образа, который включает несколько версий Ноды);
  • GzipCompression — использовать ли Gzip-компрессию;
  • ProxyServer — тип прокси-сервера, которым отдавать статику. Нужно, если ты хочешь отдавать статические файлы вроде .css или .js напрямую, с помощью nginx, не утруждая этим Node.js.

Также у Node.js есть дочерний конфигурационный неймспейс aws:elasticbeanstalk:container:nodejs:staticfiles, единственный параметр которого может в своем имени содержать путь, откуда прокси-серверу (nginx/Apache) нужно будет сервить статические файлы.

 

Готовим приложение

Давай создадим приложение на Node.js и задеплоим его в EBS. Приведу простейший пример приложения, которое на любой запрос будет отвечать текущей датой, полученной из PostgreSQL. Сейчас и далее предполагаем, что у тебя установлен и настроен Node.js, PostgreSQL, npm и Git.

Инициализируем новый пакет:

$ npm init
...
$ npm install pg --save
...
$ touch app.js

Добавим в app.js следующий код:

// Определим зависимости
var http      = require('http')
  , pg        = require('pg')
  // Наша строка подключения
  , conString = "postgres://postgres:passwd@192.168.59.103/ts.dev"

// Создадим сервер
http.createServer(function (req, res) {

  // Получим инстанс клиента Postgres
  pg.connect(conString, function(err, client, done) {

    // Получим текущую дату из БД
    client.query('SELECT now();',function(err, result) {

      // Освободим клиент
      done();

      // Выдернем из ответа БД то, что нужно клиенту
      var response = String(result.rows[0].now);

      // Вернем дату в ответ на запрос клиента
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end(response);
    });
  });
}).listen(process.env.PORT || 3000, '0.0.0.0');

С целью экономии места из листинга намеренно вырезаны все обработчики ошибок. Тем не менее это вполне рабочее веб-приложение на Node.js и для наших учебных целей оно подойдет.

Теперь, когда ты запустишь скрипт командой node app.js (предполагаем, что у тебя установлен Node и модуль pg), в ответ на http://localhost:3000 придет что-то вроде

Fri Aug 28 2015 17:44:55 GMT+0300 (MSK)

Окей, Гугл, пришло время закоммитить наш код в репозиторий. Забегая вперед, сразу скажу, что код в EBS можно доставлять двумя способами:

  • загрузить в архиве руками;
  • автоматически отправить последний слепок (коммит) в EBS.

Код будет лежать в хранилище S3 в автоматически созданном бакете (корзине) с именем вроде elasticbeanstalk-eu-west-1-095776481970. Каждая новая версия приложения представляет собой зазипованный срез исходного кода по последнему коммиту репозитория. Этот zip-архив будет добавляться в нашу «корзину» и станет актуальной версией приложения, которую и будет использовать EBS.

Пример бакета с множеством версий приложения
Пример бакета с множеством версий приложения

Итак, создаем репозиторий:

$ git init
Initialized empty Git repository in /Users/f1nn/dev/myapp/.git/

Добавляем node_modules/ в .gitignore (ни к чему тащить в EBS модули, он сам установит все зависимости по файлу зависимостей package.json при создании инстанса):

$ touch .gitignore
$ nano .gitignore
<добавь строку node_modules/>

Файл .gitignore должен выглядеть так:

$ cat .gitignore
node_modules/

Коммитим код в репозиторий:

$ git add .
$ git commit -a -m "[init] Initial commit"
[master (root-commit) b8cc8ef] [init] Initial commit
 3 files changed, 40 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 app.js
 create mode 100644 package.json

Теперь давай разбираться с самим EBS.

 

Ставим EB CLI

EB CLI — это набор консольных утилит для работы с EBS. Он поддерживается для всех основных ОС: Windows, Linux и OS X. На сегодняшний день официально Amazon предлагает только один вариант установки EBS — с помощью пакетного менеджера pip для Python. Однако для OS X доступна еще и формула для Homebrew (brew install awsebcli).

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

$ sudo pip install awsebcli

Если ты на Windows, тебе, возможно, понадобится скачать и установить сам Python, а также pip. Детальные инструкции для твоей ОС можно найти здесь.

Проверяем установленную версию EB CLI:

$ eb --version
EB CLI 3.5.2 (Python 2.7.1)

Все хорошо, идем дальше.

 

Инициализируем EBS-проект

Перед тем как уже выложить наш проект в EBS, открой консоль EBS и посмотри, как выглядит админка этого сервиса.

«Чистая» админка EBS без созданных окружений и приложений
«Чистая» админка EBS без созданных окружений и приложений

Возможно, ты обратил внимание на кнопки Create new application и форму выбора платформы. Все верно, EBS предоставляет возможность быстрого запуска тестового сервиса на базе нужной платформы с помощью GUI. К сожалению, такой метод не очень удобен и немного противоречит правильному workflow при работе с EBS, поэтому мы будем делать все из консоли, чтобы лучше понять принцип.

Итак, переходим в директорию нашего репозитория и инициализируем новый проект:

$ eb init

EBS начнет задавать вопросы о конфигурации проекта. Пройдемся быстро по ним.

Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-southeast-1 : Asia Pacific (Singapore)
7) ap-southeast-2 : Asia Pacific (Sydney)
8) ap-northeast-1 : Asia Pacific (Tokyo)
9) sa-east-1 : South America (Sao Paulo)
(default is 3):

Инстансы EBS — это на самом деле инстансы EC2. Как и любой сервис AWS, они могут физически располагаться в одном из девяти дата-центров AWS. Выбирай тот, который географически ближе к твоей аудитории, чтобы пинг был меньше. Я обычно использую или Франкфурт, или Ирландию.

You have not yet set up your credentials or your credentials are incorrect
You must provide your credentials.
(aws-access-id):

EBS — это сервис AWS, значит, авторизация к нему происходит на основании общих механизмов, принятых в инфраструктуре AWS. Если конкретнее, ты должен создать ключ и секретный ключ, у которых будут права на работу с частью сервисов, нужной EBS. В нашем случае это EC2, LoadBalancers, S3 и управление ролями EC2.

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

Предложим, ты создал юзера, приаттачил к нему необходимые политики (права) и получил следующие ключи:

Access Key ID:
AKIAJ3K2BCHW2LB7UDWQ
Secret Access Key:
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

Вводи их в EBS.

Enter Application Name
(default is "myapp"):

EBS попросит ввести имя для твоего приложения. Оставляем myapp.

Application myapp has been created.

It appears you are using Node.js. Is this correct?
(y/n): y

В нашем случае EBS угадал стек технологий, на которых работает наше приложение. Если по каким-то причинам этого не произошло, ответь n и выбери нужный образ, например Ruby on Rails или Django.

Do you want to set up SSH for your instances?
(y/n): n

Мне SSH обычно не нужен, однако если тебе понадобится физически зайти на какой-нибудь инстанс и проверить, что там творится, то в последнем вопросе можно ответить y, предоставив EBS SSH-ключик, с которым создавать инстанс.

Отлично, проект создан! Убедимся в этом:

$ ls -la
total 24
drwxr-xr-x   8 f1nn  staff  272 Sep  1 15:49 .
drwxr-xr-x  12 f1nn  staff  408 Aug 31 00:38 ..
drwxr-xr-x   3 f1nn  staff  102 Sep  1 16:02 .elasticbeanstalk
drwxr-xr-x  13 f1nn  staff  442 Aug 31 00:47 .git
-rw-r--r--   1 f1nn  staff  122 Sep  1 16:03 .gitignore
-rw-r--r--   1 f1nn  staff  790 Aug 28 18:24 app.js
drwxr-xr-x   3 f1nn  staff  102 Aug 31 00:39 node_modules
-rw-r--r--   1 f1nn  staff  268 Aug 31 00:39 package.json

$ ls -la .elasticbeanstalk/
total 8
drwxr-xr-x  3 f1nn  staff  102 Sep  1 16:02 .
drwxr-xr-x  8 f1nn  staff  272 Sep  1 15:49 ..
-rw-r--r--  1 f1nn  staff  198 Sep  1 16:03 config.yml

Пока наш файл глобального конфига EBS не очень информативен. Он не содержит самого главного — информации об окружении, в котором будет исполняться наше приложение:

$ cat .elasticbeanstalk/*
branch-defaults:
  master:
    environment: null
global:
  application_name: myapp
  default_ec2_keyname: null
  default_platform: Node.js
  default_region: eu-central-1
  profile: eb-cli
  sc: git

Давай это исправим и создадим окружение:

$ eb create

Опять несколько вопросов:

Enter Environment Name
(default is myapp-dev):

Оставляй как есть — myapp-dev.

Enter DNS CNAME prefix
(default is myapp-dev):

CNAME-префикс для рабочего URL, по которому будет открываться твое приложение. Что-то вроде myapp-dev.elasticbeanstalk.com. Оставляй как есть.

That cname is not available. Please choose another.
Enter DNS CNAME prefix
(default is myapp-dev):

Упс! Кто-то уже создал приложение с таким же CNAME-доменом, они уникальны для всего EBS по понятным причинам. Зададим myapp-dev-xa.

Enter DNS CNAME prefix
(default is myapp-dev): myapp-dev-xa

2.0+ Platforms require a service role. We will attempt to create one for you. You can specify your own role using the --service-role option.
Type "view" to see the policy, or just press ENTER to continue:
WARNING: You have uncommitted changes.
Creating application version archive "b8cc".
Application myapp has been created.
Environment details for: myapp-dev
Application name: myapp
Region: eu-central-1
Deployed Version: b8cc
Environment ID: e-4mkjeypmmv
Platform: 64bit Amazon Linux 2015.03 v2.0.0 running Node.js
Tier: WebServer-Standard
CNAME: myapp-dev-xa.elasticbeanstalk.com
Updated: 2015-09-01 13:25:16.507000+00:00
Printing Status:
INFO: createEnvironment is starting.
INFO: Using elasticbeanstalk-eu-central-1-361536763074 as Amazon S3 storage bucket for environment data.
INFO: Environment health has transitioned to Pending. There are no instances.
INFO: Created security group named: sg-11d85078
INFO: Created load balancer named: awseb-e-4-AWSEBLoa-5LPP1PI1P2UN
INFO: Created security group named: awseb-e-4mkjeypmmv-stack-AWSEBSecurityGroup-Y5ZYIWHUSVZ6
INFO: Created Auto Scaling launch configuration named: awseb-e-4mkjeypmmv-stack-AWSEBAutoScalingLaunchConfiguration-GQSF0EHZ5VZY
INFO: Added instance [i-08d7cdc6] to your environment.
...

Сейчас начнется долгий процесс построения рабочего окружения, в котором будет запускаться наше приложение. В процессе создания консоль AWS покажет одно созданное окружение в статусе Pending:

Созданное окружение, еще без инстансов в статусе Pending
Созданное окружение, еще без инстансов в статусе Pending

Если ты получаешь ошибку вида:

The instance profile aws-elasticbeanstalk-ec2-role associated with the environment does not exist.

это значит, что ты не приаттачил к своему IAM-юзеру права для создания EC2-ролей. Подробнее читай тут.

Если все прошло успешно, ты получишь сообщение о том, что окружение создано:

...
INFO: Created CloudWatch alarm named: awseb-e-4mkjeypmmv-stack-AWSEBCloudwatchAlarmLow-1BEV2IFQKK95Y
INFO: Environment health has transitioned from Pending to Ok.
INFO: Successfully launched environment: myapp-dev

Давай наконец посмотрим на наше приложение в браузере! Пишем:

$ eb open

Открывается браузер, и мы видим…

Что-то пошло не так
Что-то пошло не так

Кажется, что-то задеплоилось не так — приложение не работает, а nginx отдает 502. Судя по тому, что мы получаем 502 от nginx, а не простой тайм-аут, наш первый инстанс действительно работает и его nginx пытается получить ответ от нашего приложения. И в этот момент случается что-то нехорошее. Давай разбираться.

 

Что тут могло пойти ТАК?

Конечно же, внимательный читатель заметит, что в самом начале при создании нашего приложения мы обращались к базе данных со строкой соединения

"postgres://postgres:passwd@192.168.59.103/ts.dev"

Это работало на нашей локальной машине (192.168.59.103 — адрес моего Docker-контейнера с PostgreSQL). Но в AWS его нет. Соответственно, наше приложение пытается присоединиться к БД, получает NOT FOUND и отдает ошибку! Отсюда и 502, который показывает нам nginx, — он просто не получает валидного ответа от Node.js-приложения при попытке проксировать клиентский запрос.

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

$ eb logs
Retrieving logs...

Ответом будет длиннющая простыня логов. Кстати, иногда получать логи из консоли не очень удобно, поэтому можно зайти в опции твоего окружения и запросить нужный объем через GUI:

Запрашиваем логи через GUI в настройках нашего окружения
Запрашиваем логи через GUI в настройках нашего окружения
 

Спасаем положение

 

Создаем БД

Давай создадим БД, с которой и будет работать наше приложение. Для этого воспользуемся сервисом Amazon Relational Database Service, далее — RDS.

RDS — сервис для виртуализации реляционных БД в AWS
RDS — сервис для виртуализации реляционных БД в AWS

Переходи в админку RDS и создавай новую БД на движке PostgreSQL. Особо долго останавливаться не буду, иначе эта статья никогда не закончится. Подчеркну только несколько моментов.

Читай, что предлагает тебе AWS. Например, если, не думая, оставить опцию «use Multi-AZ Deployment and Provisioned IOPS Storage as defaults while creating this instance», можно нехило удивиться счету, который выставит тебе AWS в конце месяца. Для нашего тестового приложения вся эта избыточная надежность совсем не нужна.

Выставляем опции инстанса и настройки PG
Выставляем опции инстанса и настройки PG

К следующему шагу нужно отнестись особенно внимательно.

Publicly Accessible. Выставляй No, нам не нужно, чтобы всякие роботы стучались в нашу БД. Сами мы будем получать к ней доступ по внутреннему адресу через амазоновскую private network.

VPC Security Group(s). Доступы к сервисам в AWS предоставляются на основе так называемых Securtiy Groups. Если кратко, это набор правил для файрвола для входящего и исходящего трафика. Нам нужно запретить любой исходящий трафик с нашей БД, но при этом разрешить входящий трафик с любого инстанса из всего пула нашего балансировщика нагрузки, который был автоматически создан вместе с нашим окружением.

Почему это важно? Дело в том, что сейчас у нашего балансировщика нагрузки всего один инстанс и мы можем указать его внутренний IP в качестве разрешенного для доступа к нашей БД (TCP 5432, 5432 — порт Постгреса). Однако, когда трафик вырастет, балансировщик нагрузки создаст еще один инстанс и начнет распределять трафик между ними двумя, у нового инстанса уже не будет доступа к БД, так как его IP нет в списке разрешенных на файрволе БД.

Решение проблемы — создать отдельную Security-группу для нашей БД и указать в качестве разрешенного источника трафика не какой-то конкретный инстанс, а сам балансировщик нагрузки (по его названию).

Создаем секьюрити-группу с нужным источником трафика
Создаем секьюрити-группу с нужным источником трафика

Теперь возвращаемся к созданию RDS и выбираем нужную нам секьюрити-группу:

Задаем для RDS созданную секьюрити-группу
Задаем для RDS созданную секьюрити-группу

Ура, наконец-то наша RDS создана и готова к работе.

Наша созданная RDS с правильно выставленными правилами для входных соединений
Наша созданная RDS с правильно выставленными правилами для входных соединений
 

Пробуем подружить окружение с нашей БД

Теперь нужно научить наше приложение коннектиться к созданной БД. Самый простой путь — передать данные о подключении через переменные окружения, добавив их в наше окружение myapp-dev. Есть два способа сделать это:

  • добавить их через веб-конфигуратор в опциях нашего окружения, а затем перезапустить его;
  • добавить переменные через скрипты конфигурации в .exbextensions, закоммитить изменения, а затем пушнуть обновления в EBS.
Веб-конфигуратор нашего окружения
Веб-конфигуратор нашего окружения

Если использовать первый вариант, можно довольно быстро все починить, однако это не наш метод :). GUI-конфигуратор, безусловно, удобен, и на самом деле он предоставляет доступ к большинству опций, которые задаются через переменные и неймспейсы конфигов. Однако он не дает необходимого уровня автоматизации при повторном деплое приложения, так что воспользуемся первым, чтобы лучше понять процесс.

В разделе Software Configuration можно просто добавить все нужные нам переменные окружения
В разделе Software Configuration можно просто добавить все нужные нам переменные окружения

Итак, для задания переменных окружения создадим в папке .ebextensions файл 001_env.config со следующим содержимым:

option_settings:
  - option_name: POSTGRES_HOST
    value: value
  - option_name: POSTGRES_PORT
    value: value
  - option_name: POSTGRES_DBNAME
    value: value
  - option_name: POSTGRES_USER
    value: value
  - option_name: POSTGRES_PASS
    value: value

Обрати внимание, что вместо реальных значений мы ставим заглушки value. Дело в том, что файл .ebextensions/001_env.config нужно добавить в наш репозиторий приложения. Если он будет содержать реальные пароли для доступа к БД, это может оказаться небезопасно (даже если наш репозиторий приватный). Поэтому сейчас мы добавляем заглушки, а позже через веб-конфигуратор подставим реальные значения.

Теперь необходимо научить наше приложение коннектиться к БД по предоставленным ему переменным окружения. Что-то пояснять здесь смысла нет, просто приведу код итогового приложения:

// Получаем переменные окружения
var POSTGRES_HOST   = process.env.POSTGRES_HOST
  , POSTGRES_PORT   = process.env.POSTGRES_PORT
  , POSTGRES_DBNAME = process.env.POSTGRES_DBNAME
  , POSTGRES_USER   = process.env.POSTGRES_USER
  , POSTGRES_PASS   = process.env.POSTGRES_PASS

// Определим зависимости
var http      = require('http')
  , pg        = require('pg')
  , conString = 'postgres://' + POSTGRES_USER + ':' + POSTGRES_PASS + '@' + POSTGRES_HOST + ':' + POSTGRES_PORT + '/' + POSTGRES_DBNAME

// Создадим сервер
http.createServer(function (req, res) {

  // Получим инстанс клиента Postgres
  pg.connect(conString, function(err, client, done) {

    // Получим текущую дату из БД
    client.query('SELECT now();',function(err, result) {

      // Освободим клиент
      done();

      // Выдернем из ответа БД то, что нужно клиенту
      var response = String(result.rows[0].now);

      // Вернем дату в ответ на запрос клиента
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end(response);
    });
  });
}).listen(process.env.PORT || 3000, '0.0.0.0');

Закоммитим изменения:

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   .gitignore
    modified:   app.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    .ebextensions/

no changes added to commit (use "git add" and/or "git commit -a")
$ git add .
$ git commit -a -m "[fix] .ebextensions, use env vars"
[master f7a99e9] [fix] .ebextensions, use env vars
 3 files changed, 36 insertions(+), 9 deletions(-)
 create mode 100644 .ebextensions/001_env.config
 

Обновляем приложение

Теперь самое время запушить обновления нашего приложения в EBS:

$ eb deploy
Creating application version archive "f7a9".
Uploading myapp/f7a9.zip to S3. This may take a while.
Upload Complete.
INFO: Environment update is starting.
INFO: Deploying new version to instance(s).
INFO: Environment health has transitioned from Ok to Info. Command is executing on all instances.
INFO: New application version was deployed to running EC2 instances.
INFO: Environment update completed successfully.

Как мы видим, создан новый «срез» кода с меткой «f7a9». Он и отправляет на все инстансы приложения в нашем окружении, и через пару минут окружение будет обновлено. По завершении обновления если мы зайдем в настройки нашего окружения, то увидим, что наши скрипты сработали и переменные окружения подцепились.

Окружение обновилось с учетом добавленных конфигов
Окружение обновилось с учетом добавленных конфигов

Естественно, наше приложение будет по-прежнему отдавать 502, так как значения переменных дефолтные. Давай забьем настоящие. Адрес БД можно получить в свойствах БД в консоли RDS. Он будет примерно таким:

pgmyappdev.cdblqpj9xqk1.eu-central-1.rds.amazonaws.com:5432
Добавляем «настоящие» значения в переменные окружения
Добавляем «настоящие» значения в переменные окружения

После чего применим изменения, и окружение начнет пересборку.

Пересборка окружения после применения новых значений переменных окружения
Пересборка окружения после применения новых значений переменных окружения

Немного погодя идем по заветному URL и…

PROFIT!
PROFIT!
 

Домашнее задание

Вот мы и задеплоили наше первое приложение в EBS. Со стороны процесс может показаться довольно сложным, но, если чуть-чуть въехать в AWS, во всех шагах появляется логика.

Мы не коснулись темы установки правил масштабирования в зависимости от трафика / количества подключений или запуска cron-задач на leader_only. Все это местами с трудом, но гуглится, а статья получилась и так гигантская :). Если есть вопросы по этим темам, пиши на rusanen@glc.ru. Буду рад помочь. Удачи!

Комментарии

Подпишитесь на ][, чтобы участвовать в обсуждении

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

Check Also

WWW: TLDR pages — замена справке man, показывающая только самое важное

Что ты делаешь каждый раз, когда набираешь команду man в Linux или Unix? Правильно: тяжело…