Развертывание серверов приложения и обратного прокси-сервера Nginx с помощью map-файлов Salt
Centos | Комментировать запись
При развертывании готового приложения в среде производства важно учитывать необходимость балансировки нагрузки, масштабирования и дальнейшего обновления. Также нужно помнить о проверке и тестировании конфигурации. Все эти задачи можно автоматизировать.
Данный мануал поможет создать map-файл Salt Cloud и пользовательские зерна Salt для определения ролей серверов и динамической конфигурации обратного прокси-сервера.
Требования
- Сервер CentOS 7, настроенный по этому мануалу. Все команды в текущем мануале нужно выполнять через пользователя с доступом к sudo.
- 1 Гб памяти минимум.
- SSH-ключ для root-пользователя. Запишите имя, которое вы назначили ключу в панели управления хостингом (в мануале используется условное имя salt-master-root-key). Вы также должны указать местоположение закрытого ключа; по умолчанию это /root/.ssh/id_rsa.
- Токен доступа. Обязательно установите область для чтения и записи.
1: Установка Salt и Salt Cloud
Для начала необходимо установить и настроить Salt Cloud на вашем сервере. Для этого можно использовать скрипт запуска Salt.
Загрузите скрипт.
wget -O install_salt.sh https://bootstrap.saltstack.com
Запустите скрипт. Флаг –М установит salt-master.
sh install_salt.sh -M
Кодовая база Salt Cloud была объединена с основным проектом Salt, но для CentOS она по-прежнему упакована отдельно. К счастью, скрипт install_salt настроил все необходимые репозитории, поэтому вы можете просто установить salt-cloud с помощью yum:
yum install salt-cloud
Теперь проверьте версию Salt Cloud, чтобы убедиться, что установка прошла успешно.
salt-cloud --version
salt-cloud 2015.5.3 (Lithium)
Версия может отличаться.
2: Настройка Salt Cloud
Теперь нужно подключить Salt Cloud к вашим серверам.
Создание файла провайдера
В Salt Cloud файлы провайдера определяют метод создания новых виртуальных машин. Провайдеры определяются в каталоге /etc/salt/cloud.providers.d.
Создайте файл для вашего провайдера:
nano /etc/salt/cloud.providers.d/your_provider.conf
Вставьте нижеприведенный код, заменив условные значения переменных своими данными (укажите свой IP-адрес сервера и токен доступа, а также имя и файл ключа SSH).
### /etc/salt/cloud.providers.d/your_provider.conf ###
######################################################
do:
provider: your_provider
minion:
master: your_server_ip
# Access Token
personal_access_token: your_access_token
# This is the name of your SSH key
# as it appears in the control panel.
ssh_key_name: salt-master-root-key
# This is the path on disk to the private key
ssh_key_file: /root/.ssh/id_rsa
Ограничьте доступ к файлу ключа, иначе SSH откажется использовать его.
chmod 600 /root/.ssh/id_rsa
Настройка профилей для развертываемых серверов
Профилями в Salt Cloud называются отдельные виртуальные машины, привязанные к провайдеру. Они определяются в каталоге /etc/salt/cloud.profiles.d.
Создайте файл профиля:
nano /etc/salt/cloud.profiles.d/your_provider.conf
Вставьте в него следующий код:
### /etc/salt/cloud.profiles.d/your_provider.conf ###
#####################################################
ubuntu_512MB_ny3:
provider: your_provider
image: ubuntu-14-04-x64
size: 512MB
location: nyc3
private_networking: True
ubuntu_1GB_ny3:
provider: your_provider
image: ubuntu-14-04-x64
size: 1GB
location: nyc3
private_networking: True
Сохраните и закройте файл. Он определяет два профиля.
- Виртуальная машина Ubuntu 14.04, 512 Мб памяти, в регионе New York 3
- Виртуальная машина Ubuntu 14.04, 1 Гб памяти, регион New York 3
Протестируйте свою настройку с помощью быстрого запроса:
salt-cloud -Q
[INFO ] salt-cloud starting
your_provider:
----------
your_provider:
----------
centos-salt:
----------
id:
2806501
image_id:
6372108
public_ips:
192.241.247.229
size_id:
63
state:
active
3: Создание простого map-файла
Map-файл – это файл YAML, в котором перечислены профили и количество серверов, которые нужно создать. Начните с простого map-файла, в дальнейшем его можно будет расширить.
Используя приведенные выше профили, предположим, вы хотите, чтобы два сервера приложений по 1 Гб находились за обратным прокси-сервером размером 512 Мб. Создайте файл /etc/salt/cloud.maps.d/app-with-rproxy.map и определите приложение.
nano /etc/salt/cloud.maps.d/app-with-rproxy.map
Вставьте в него следующее:
### /etc/salt/cloud.maps.d/app-with-rproxy.map ####
######################################################
ubuntu_512MB_ny3:
- nginx-rproxy
ubuntu_1GB_ny3:
- appserver-01
- appserver-02
Простой map-файл готов. Теперь разверните эти серверы:
salt-cloud -m /etc/salt/cloud.maps.d/app-with-rproxy.map
После завершения команды проверьте серверы с помощью ping:
salt '*' test.ping
[label salt '*' test.ping
appserver-01:
True
appserver-02:
True
nginx-rproxy:
True
Виртуальные машины были созданы по вашему файлу. Теперь их можно удалить:
salt-cloud -d -m /etc/salt/cloud.maps.d/app-with-rproxy.map
Примечание: Будьте осторожны с этой командой – она удаляет все виртуальные машины, определенные в указанном map-файле.
4: Расширение map-файла
Простой map-файл работает, но для полноценной среды производства он слишком прост. Теперь нужно определить размер приложения. Вернитесь к map-файлу и добавьте еще несколько функций.
nano /etc/salt/cloud.maps.d/app-with-rproxy.map
Удалите его предыдущее содержимое и замените его следующим кодом:
### /etc/salt/cloud.maps.d/app-with-rproxy.map ###
#####################################################
ubuntu_512MB_ny3:
- nginx-rproxy:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: rproxy
ubuntu_1GB_ny3:
- appserver-01:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
- appserver-02:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
Кажется, файл стал намного сложнее, но на самом деле в нем появилось всего два новых раздела: mine_functions и grains.
Теперь Salt Cloud может изменить конфигурацию Salt Minion для этих виртуальных машин и добавить пользовательские зерна. Зерна присваивают обратному прокси-серверу роль rproxy, а серверам приложений роль appserver. Это позволяет динамически настраивать обратный прокси.
mine_functions тоже добавляются в конфигурации Salt Minion. Миньон сможет передавать IP-адрес на интерфейсе eth0 мастеру Salt и хранить его в mine. Это означает, что Salt Master автоматически узнает IP-адрес нового сервера. Это пригодится в дальнейшем.
5: Определение обратного прокси-сервера
Теперь установите обратный прокси-сервер и настройте его. Здесь в качестве обратного прокси-сервера используется Nginx.
Определение состояния Nginx
Пришло время написать несколько состояний Salt. Сначала создайте дерево Salt по умолчанию:
mkdir /srv/salt
Перейдите в этот каталог и создайте в нем новый каталог для nginx:
cd /srv/salt
mkdir /srv/salt/nginx
Перейдите в новый каталог и создайте файл rproxy.sls:
cd /srv/salt/nginx
nano /srv/salt/nginx/rproxy.sls
Добавьте в файл такие строки:
### /srv/salt/nginx/rproxy.sls ###
##################################
### Install Nginx and configure it as a reverse proxy, pulling the IPs of
### the app servers from the Salt Mine.
nginx-rproxy:
# Install Nginx
pkg:
- installed
- name: nginx
# Place a customized Nginx config file
file:
- managed
- source: salt://nginx/files/awesome-app.conf.jin
- name: /etc/nginx/conf.d/awesome-app.conf
- template: jinja
- require:
- pkg: nginx-rproxy
# Ensure Nginx is always running.
# Restart Nginx if the config file changes.
service:
- running
- enable: True
- name: nginx
- require:
- pkg: nginx-rproxy
- watch:
- file: nginx-rproxy
# Restart Nginx for the initial installation.
cmd:
- run
- name: service nginx restart
- require:
- file: nginx-rproxy
Этот файл:
- Устанавливает Nginx.
- Помещает пользовательские конфигурации в файл /etc/nginx/conf.d/awesome-app.conf.
- Проверяет работу Nginx.
Это состояние Salt просто устанавливает Nginx и добавляет конфигурационный файл.
Создание конфигурационного файла для обратного прокси-сервера Nginx
Создайте еще один каталог:
mkdir /srv/salt/nginx/files
cd /srv/salt/nginx/files
Откройте в нем конфигурационный файл:
nano /srv/salt/nginx/files/awesome-app.conf.jin
Поместите в конфигурационный файл следующие строки. Никаких изменений не требуется, если вы не используете частные сети (если да – измените значение 1 на 0 в выделенной красным строке):
### /srv/salt/nginx/files/awesome-app.conf.jin ###
##################################################
### Configuration file for Nginx to act as a
### reverse proxy for an app farm.
# Define the app servers that we're in front of.
upstream awesome-app {
{% for server, addrs in salt['mine.get']('roles:appserver', 'network.ip_addrs', expr_form='grain').items() %}
server {{ addrs[0] }}:1337;
{% endfor %}
}
# Forward all port 80 http traffic to our app farm, defined above as 'awesome-app'.
server {
listen 80;
server_name {{ salt['network.ip_addrs']()[1] }}; # <-- change the '1' to '0' if you're not using
# Private networking.
access_log /var/log/nginx/awesome-app.access.log;
error_log /var/log/nginx/awesome-app.error.log;
## forward request to awesome-app ##
location / {
proxy_pass http://awesome-app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Используйте расширение .jin, чтобы указать, что файл содержит шаблоны Jinja. Jinja помогает организовать логику файлов, чтобы вы могли динамически генерировать детали конфигурации.
Этот конфигурационный файл позволяет Nginx принимать весь HTTP-трафик с порта 80 и перенаправлять его на серверы приложения. Он состоит из двух частей: upstream (определяет серверы приложений) и конфигурации прокси-сервера.
Давайте рассмотрим раздел upstream. Обычный upstream (не в шаблоне) содержит набор IP-адресов. Однако сейчас мы не знаем IP-адреса миньонов, поскольку их просто не существует, а редактировать файлы конфигурации вручную нет смысла (так ничего автоматизировать не получится, вы все будете делать сами).
Помните строки mine_function в map-файле? Миньоны передают свои IP-адреса мастеру Salt, который хранит их как раз для такого случая.
{% for server, addrs in salt['mine.get']('roles:appserver', 'network.ip_addrs', expr_form='grain').items() %}
Это цикл for Jinja, который запускает произвольные функции Salt. В данном случае он запускает mine.get. Вот все параметры:
- roles:appserver собирает данные только от миньонов с ролью appserver.
- network.ip_addrs определяет данные, которые нужно выбрать из mine-хранилища.
- expr_form=’grain’ настраивает таргетинг миньонов по зернам.
После выполнения этого цикла переменная {{addrs}} содержит список IP-адресов (даже если в нем только один адрес).
Теперь рассмотрим строку:
server_name {{ salt['network.ip_addrs']()[0] }};
Это то же самое, что и вызов mine (вызов функции Salt в Jinja), только проще. Эта строка вызывает network.ip_addrs и принимает первый элемент из возвращаемого списка. Она позволяет не редактировать файл вручную.
6: Определение серверов приложения
Обратный прокси-сервер не очень полезен, если у него нет приложения. Давайте создадим небольшое приложение Node.js, которое просто сообщит IP-адрес сервера, на котором оно работает (чтобы вы могли убедиться, что обе машины работают правильно).
Создайте новый каталог awesome-app и перейдите в него:
mkdir -p /srv/salt/awesome-app
cd /srv/salt/awesome-app
Создайте новое состояние:
nano /srv/salt/awesome-app/app.sls
Вставьте в него такой код:
### /srv/salt/awesome-app/app.sls ###
#####################################
### Install Nodejs and start a simple
### web application that reports the server IP.
install-app:
# Install prerequisites
pkg:
- installed
- names:
- node
- npm
- nodejs-legacy # workaround for Debian systems
# Place our Node code
file:
- managed
- source: salt://awesome-app/files/app.js
- name: /root/app.js
# Install the package called 'forever'
cmd:
- run
- name: npm install forever -g
- require:
- pkg: install-app
run-app:
# Use 'forever' to start the server
cmd:
- run
- name: forever start app.js
- cwd: /root
Это состояние:
- Устанавливает пакеты nodejs, npm и nodejs-legacy.
- Добавляет файл JavaScript,который будет простым приложением.
- Устанавливает Forever с помощью NPM.
- Запускает приложение.
Создайте каталог:
mkdir /srv/salt/awesome-app/files
cd /srv/salt/awesome-app/files
В нем создайте файл:
nano /srv/salt/awesome-app/files/app.js
Добавьте в файл приложения следующий код:
/* /srv/salt/awesome-app/files/app.js
A simple Node.js web application that
reports the server's IP.
Shamefully stolen from StackOverflow:
http://stackoverflow.com/questions/10750303/how-can-i-get-the-local-ip-address-in-node-js
*/
var os = require('os');
var http = require('http');
http.createServer(function (req, res) {
var interfaces = os.networkInterfaces();
var addresses = [];
for (k in interfaces) {
for (k2 in interfaces[k]) {
var address = interfaces[k][k2];
if (address.family == 'IPv4' && !address.internal) {
addresses.push(address.address)
}
}
}
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(JSON.stringify(addresses));
}).listen(1337, '0.0.0.0');
console.log('Server listening on port 1337');
Это простой сервер Node.js, который делает одно: принимает HTTP-запросы на порт 1337 и в ответ отправляет IP-адреса сервера.
На этом этапе у вас должна быть структура, которая выглядит следующим образом:
/srv/salt
├── awesome-app
│ ├── app.sls
│ └── files
│ └── app.js
└── nginx
├── rproxy.sls
└── files
└── awesome-app.conf.jin
7: Развертывание приложения
Развертывание серверов с помощью Salt Cloud
Запустите команду для развертывания серверов:
salt-cloud -m /etc/salt/cloud.maps.d/app-with-rproxy.map
Подождите, пока Salt Cloud завершит работу. Затем убедитесь, что развертывание прошло успешно.
salt -G 'roles:appserver' test.ping
Вы увидите:
appserver-02:
True
appserver-01:
True
Пропингуйте обратный прокси:
salt -G 'roles:rproxy' test.ping
nginx-rproxy:
True
Сборка приложения
Теперь запустите команду Salt, чтобы автоматически собрать серверы приложения и обратный прокси. Сначала соберите серверы приложений:
salt -G 'roles:appserver' state.sls awesome-app.app
Вывод должен заканчиваться так:
------------
Succeeded: 6 (changed=6)
Failed: 0
------------
Total states run: 6
Теперь соберите обратный прокси:
salt -G 'roles:rproxy' state.sls nginx.rproxy
Вывод должен заканчиваться так:
------------
Succeeded: 4 (changed=4)
Failed: 0
------------
Total states run: 4
Первая команда (для серверов приложений) приняла состояние Salt и выполнила его на двух серверах приложений. Это привело к тому, что у вас появились две машины с идентичной конфигурацией и идентичными версиями кода.
Вторая команда (для обратного прокси-сервера) выполнила состояние Salt, предназначенное для Nginx. Она установила Nginx и добавила файл конфигурации, динамически заполняя IP-адреса серверов приложений.
После того, как эти команды будут выполнены, вы можете убедиться, что развертывание прошло успешно. Найдите IP-адрес обратного прокси-сервера:
salt -G 'roles:rproxy' network.ip_addrs
Вы можете получить два адреса, если на сервере включена частная сеть.
Введите внешний IP-адрес в браузер и посетите страницу. Обновите страницу несколько раз, чтобы убедиться, что Nginx проксирует запросы между двумя серверами приложений. Вы должны увидеть, что IP-адреса меняются.
Если вы видите один и тот же IP-адрес, даже обновив страницу несколько раз, это, вероятно, связано с кэшированием браузера. Вместо этого вы можете попробовать использовать curl. Выполните эту команду несколько раз и следите за выводом:
curl http://ip-of-nginx-rproxy
Полностью автоматизировать развертывание приложений можно через OverState. Это позволяет создать единую команду, с помощью которой Salt будет собирать серверы приложений, прежде чем перейти к созданию обратного прокси, что обеспечит правильный порядок процесса сборки.
8: Масштабирование (опционально)
Цель Salt – автоматизировать процесс сборки; цель Salt Cloud и map-файлов –упростить масштабирование развертывания. Если вы хотите добавить еще несколько серверов приложений (скажем, еще два), вы должны обновить свой map-файл так:
### /etc/salt/cloud.maps.d/app-with-rproxy.map ###
#####################################################
ubuntu_512MB_ny3:
- nginx-rproxy:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: rproxy
ubuntu_1GB_ny3:
- appserver-01:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
- appserver-02:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
- appserver-03:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
- appserver-04:
minion:
mine_functions:
network.ip_addrs:
interface: eth0
grains:
roles: appserver
Снова запустите команду salt-cloud и команды salt:
salt-cloud -m /etc/salt/cloud.maps.d/app-with-rproxy.map
salt -G 'roles:appserver' state.sls awesome-app.app
salt -G 'roles:rproxy' state.sls nginx.rproxy
Повторный запуск Salt не повлияет на существующие серверы, новые серверы будут собраны по спецификации, а конфигурация Nginx будет обновлена для поддержки маршрутизации трафика на новые серверы приложений.
Заключение
На примере этого простого приложения Node.js вы можете развернуть более сложное приложение. К слову, Salt поддерживает множество других языков программирования.
Если вы хотите использовать эту инфраструктуру для развертывания своего собственного приложения, вам просто нужно автоматизировать задачу установки вашего приложения на сервере (либо с помощью сценария, либо с помощью состояний Salt) и заменить название приложения awesome-app именем своего приложения.
Tags: CentOS 7, NGINX, salt, Salt Cloud, SaltStack