Развертывание приложения Node.js с помощью Systemd и Nginx

При развертывании веб-приложения может возникнуть желание просто использовать те же настройки, которые были использованы в процессе разработки, то есть запустить в терминале ruby app.rb или node server.js. Это очень легко и удобно; кроме того, можно использовать screen, tmux or nohup, чтобы сервер продолжал работать даже тогда, когда SSH-сессия оборвалась. Но это очень опасно: что, если сервер выйдет из строя, а администратора не будет на месте, чтобы перезапустить его?

Некоторые используют для этих целей forever и crontab. В данном руководстве представлен другой подход, более ошибкоустойчивый и в то же время более сложный. При помощи демона systemd (доступен в Arch и Fedora) можно управлять веб-приложениями (логами, аптаймом, ресурсами и безопасностью) через контрольные группы (cgroups).

В данном руководстве используется простое приложение Node.js, но его действия применимы к большинству других приложений (Ruby, Python и т.д.). Для приложений PHP рекомендуется использовать более специализированные LAMP stack или LEMP stack.

Руководство приводит команды для Fedora и Arch; во избежание путаницы везде сделаны необходимые пометки. Если же таковой пометки нет – команда подходит для обеих систем. Кроме того, рекомендуется полностью прочесть руководство, прежде чем приступить к его выполнению, чтобы получить представление о том, к какому результату оно приводит и подходит ли оно в вашей ситуации.

Предварительные требования к системе

  • Демон systemd. Серверы Arch Linux и Fedora поставляются с ним по молчанию.
  • Nginx как обратный прокси http и сервер WebSocket.
  • Git (для установки nvm и загрузки приложения).
  • Root-доступ к серверу. Можно также войти в систему как обычный пользователь с расширенными привилегиями и выполнять все команды через sudo, su – или sudo su.

Установка пакетов

Arch:

# pacman -Sy
# pacman -S nginx git

Fedora:

# yum install nginx git

Предварительные требования к приложению

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

Пользователь

Приложение должно работать на собственной учетной записи пользователя. Выберите имя (для простоты запоминания оно должно повторять имя приложения или как-либо отсылать к нему). В данном руководстве используется srv-node-sample.

# useradd -mrU srv-node-sample

Порт

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

Настройка приложения

Для начала установите все необходимое для запуска приложения. В случае с Node.js (а также Ruby, Python и т.д.) есть два варианта: использовать файлы среды выполнения системы или пользовательскую установку (например, nvm, rbenv, RVM, virtualenv и т.п.).

При использовании ноды системы

Arch:

# pacman -S nodejs

Fedora:

# yum install nodejs

Для пользовательской установки

Эту установку нужно выполнить в домашнем каталоге приложения, то есть в /home/srv-node-sample, потому проще всего войти в сеть как ранее созданный пользователь для приложения:

# su srv-node-sample
$ cd
$ curl https://raw.github.com/creationix/nvm/master/install.sh | sh
$ source ~/.nvm/nvm.sh
$ nvm install 0.10
$ nvm alias default 0.10

Затем запишите, куда был установлен бинарный файл node.

$ which node
/home/srv-node-sample/.nvm/v0.10.22/bin/node

Развертывание приложения

Оставаясь в системе как пользователь srv-node-sample, разверните код (это всего лишь пример, ваш код, конечно, может отличаться):

$ git clone git@server.company.tld:user/repo.git .
$ npm install
$ grunt deploy

В данном руководстве используется следующий пример приложения:

js
var http = require('http');
http.createServer(function(req, res) {
res.end('<h1>Hello, world.</h1>');
}).listen(15301);

Вернитесь в учетную запись root:

$ exit

Настройка Nginx

Данное руководство лишь вкратце охватывает необходимые настройки; за дополнительной информацией обращайтесь к мануалу Nginx.

В блок server (виртуальный хост Nginx) поместите следующее:

location / {
proxy_pass http://localhost:15301/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

Затем настройте демон:

# systemctl enable nginx
# systemctl restart nginx

Настройка Systemd

В /etc/systemd/system/node-sample.service создайте файл service для приложения.

В него нужно внести несколько переменных:

  • [node binary] – это выход оператора which node пользователя srv-node-sample (смотрите раздел «Настройка приложения»), то есть путь /usr/bin/node или the ~/.nvm/…
  • [main file] – главный файл приложения. В данном случае это index.js.
  • Не забудьте заменить srv-node-sample именем своего приложения!

[Service] ExecStart=[node binary] /home/srv-node-sample/[main file] Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=node-sample
User=srv-node-sample
Group=srv-node-sample
Environment=NODE_ENV=production
[Install] WantedBy=multi-user.target

Запустите сервис:

# systemctl enable node-sample
# systemctl start node-sample

Использование Systemd

Состояние

# systemctl status node-sample
node-sample.service
Loaded: loaded (/etc/systemd/system/node-sample.service; enabled)
Active: active (running) since Fri 2013-11-22 01:12:15 UTC; 35s ago
Main PID: 7213 (node)
CGroup: name=systemd:/system/node-sample.service
└─7213 /home/srv-node-sample/.nvm/v0.10.22/bin/node /home/srv-nod...
Nov 22 01:12:15 d02 systemd[1]: Started node-sample.service.

Логи

# journalctl -u node-sample
-- Logs begin at Thu 2013-11-21 19:05:17 UTC, end at Fri 2013-11-22 01:12:15 UTC. --
Nov 22 01:12:15 d02 systemd[1]: Starting node-sample.service...
Nov 22 01:12:15 d02 systemd[1]: Started node-sample.service.
Nov 22 01:12:30 d02 node-sample[7213]: Sample message from application

Перезапуск, остановка и т.п.

Принудительная перезагрузка:

# systemctl restart node-sample

Остановка приложения

# systemctl stop node-sample

Приложение будет автоматически перезапущено в случае ошибки.

# systemctl status node-sample
node-sample.service
Loaded: loaded (/etc/systemd/system/node-sample.service; enabled)
Active: active (running) since Fri 2013-11-22 01:12:15 UTC; 35s ago
Main PID: 7213 (node)
CGroup: name=systemd:/system/node-sample.service
└─7213 /home/srv-node-sample/.nvm/v0.10.22/bin/node /home/srv-nod...
Nov 22 01:12:15 d02 systemd[1]: Started node-sample.service.
# kill 7213
# systemctl status node-sample
node-sample.service
Loaded: loaded (/etc/systemd/system/node-sample.service; enabled)
Active: active (running) since Fri 2013-11-22 01:54:37 UTC; 6s ago
Main PID: 7236 (node)
CGroup: name=systemd:/system/node-sample.service
└─7236 /home/srv-node-sample/.nvm/v0.10.22/bin/node /home/srv-nod...
Nov 22 01:54:37 d02 systemd[1]: node-sample.service holdoff time over, sch...t.
Nov 22 01:54:37 d02 systemd[1]: Stopping node-sample.service...
Nov 22 01:54:37 d02 systemd[1]: Starting node-sample.service...
Nov 22 01:54:37 d02 systemd[1]: Started node-sample.service.

Как видите, PID изменился, а значит, приложение было остановлено и перезапущено.

Веб-сокеты

Если приложение использует веб-сокеты (websockets), внесите в конфигурации Nginx следующие строки:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;

После этого нужно перезапустить Nginx:

# systemctl reload nginx

Готово!

Tags: , , , , , , , ,

Добавить комментарий