Доброго дня. Сегодня мы будем говорить об Ansible и сервисах, можно конечно использовать и другие запчасти для SOA типа Docker, Jenkins и Puppet, но сегодня у нас Ansible, сервисы и пару строчек PHP. Многие из вас видели такие картинки (картинки и символы изменены).
и читали такие статьи c картинками (первая, вторая), где упоминается SOA.
Так и ближе к делу! Cегодня мы будем
Деплоить SOA
2 nginx, 2 фронта и сервис и деплой. Всего 7 ВМ понадобиться для разворачивания SOA песочницы.
В качестве деплой сервера будем использовать локальную машину и в том же сегменте сети у нас развернуты виртуалки с пользователем ansible#ansible. Так же нашим ВМ требуется доступ в интернет для установки софта. Самый просто способ это сделать 2 сетевых интерфейса с NAT и внутренней сетью 192.168.0.0\32. Если пере использовать ВМ то можно сократить это число до 4, в качестве песочницы, но не более.
Главный репозиторий, который нам все это намажет на наш бутерброд из ВМ и чтобы работало.
Также будем использовать ещё 2 репозитория. Они содержат в себе пару строчек PHP кода без привязки к какому либо фреймворку или проекту. Раз и два.
Задача фронта сделать запрос к сервису и отобразить его результат.
Задача сервиса ответить 3 большие буквы. Ваш Капитан очевидность. (Можно попробовать подсунуть свой репозиторий — п.с. Ваш Капитан очевидность снова).
Инвенторий
Так назвается файл в котором храниться описание структуры ВМ и их особенности hosts/prod.ini
Обзовём наши ВМ и дадим им имена. Фронт к которому у нас обращаться пользвоатель это
nginx-front-00 ansible_host=192.168.56.102
Осноной аппликейшен который принимает запросы
php-front-00 ansible_host=192.168.56.103
php-front-01 ansible_host=192.168.56.101
Один маленький балансер который обслуживает наши сервисы
nginx-balance-00 ansible_host=192.168.56.104
Один маленький сервис который горовит слово из 3х букв
service-sign-00 ansible_host=192.168.56.101
service-sign-01 ansible_host=192.168.56.103
Как видете я переиспользую ВМы для сервиса и для форонта, но давйте будем думать что это разные ВМ который находяться на разных железных серверах для отказоустойчивости.
Структура инвентория
Мы обозвали наши хосты, теперь софрмируем из них группы, а сами группы разделим на несколько частей. Первая группа груп это группы сервисов.
Группа сервисы
[nginx-front]
nginx-front-00
[front_app]
php-front-00
php-front-01
[nginx-balancer]
nginx-balance-00
[sign]
service-sign-00
service-sign-01
[deploy]
deploy
Группы Софт
Мы сгруппировали наши хосты в группы и теперь надо указать какой софт необходим каждоый группе для этого необходима ещё одна группа груп.
[php-cli:children]
front_app
[php-fpm:children]
front_app
sign
[git:children]
front_app
[hg:children]
[nginx:children]
nginx-front
nginx-balancer
Добавление группы в группу подскажет нашему деплою что на данную группу необходимо установить соответвуютщее програмное обеспечение. Для хостов входящих в группу php-cli установить консольный вариант PHP для крон заданий например.
П.с. Ваш Капитан очевидность
Группа Сервисы
Следующая группа групп =)
[services:children]
sign
Группирует наши сервисы как сервисы.
Особенность Сервисов
Особенность сервисов состоит в том что сушествуют 2 точки входа
// server_name {{ service_name }}
api/index.php
// server_name {{ service_name }}_web
web/index.php
Зачем эту необходимо? Если вы хотите сделать административную панель сервиса то ненадо делать для неё дополнительный сервис можно использовать эти же ВМ и обраoаться к ним как {{service_name}}_web через ифрайм или курл запросом. Сервисы могут меняться таким образом код администрирования сервисов будет обновляться вместе с сервисом.
Ключи
Каждый раз иcпользовать пароли не очень удобно, поэтому давайте разбросаем ключи на наши ВМ
ansible-playbook -i hosts/prod.ini task/system/authorized_key.yml -k --ask-sudo-pass
специально для вас я уже сгенерировал ключи в папке roles/authorized_key/keys, но вы обязаныможете сделать свои.
Добавим приватный ключ в ключе хранилище
cp roles/authorized_key/keys/id_rsa ~/.ssh/id_rsa_deploy && chmod 700 ~/.ssh/id_rsa_deploy && ssh-add ~/.ssh/id_rsa_deploy
ВАЖНО: после перезагрузки машины ключ надо добавить заново
Или прописать его в конфигурациях например в файл /etc/ssh/ssh_config добавить строчку
IdentityFile /etc/ssh/ssh_hg_deploy_key
Софт
Установим необходимый софт на ВМ
ansible-playbook -i hosts/prod.ini task/system/soft-install.yml
Это поставит нам необходимый софт на наши Группы Софт. Мы можем добавлять или удалять группы из групп чтобы на каждой ВМ стоял только необходимый набор программного обеспечения. В случае если ВМ пере используется в другом сервисе или происходят большие изменения сервиса то проще ВМ уничтожить и развернуть заново.
Мы установили php-cli, php-fpm, git, nginx на ниши машинки что же дальше…
FRONT
Нам необходимо сконфигурировать наш фронтовой НГИНКС который находиться тут
roles/nginx-front/templates/nginx.conf.j2
Как видимо это шаблон с минимально сконфигурированным набором параметров, даже особо не конфигурированный. Также очень необходимый файл:
roles/nginx-front/templates/vhosts.conf.j2
Рассмотрим его более детально
upstream php-front
{
{% for upstream in groups["front_app"] %}
server {{ hostvars[upstream]["ansible_host"] }}:9000;
{% endfor %}
}
Мы конфигурируем наш балансер простейшим способом, для более серьезной конфигурации можно добавлять переменные к хостам и дописать наш балансер с учётом дополнительных переменных.
Виртуальный хост использует upstream php-front.
fastcgi_pass php-front;
Применим эти настройки на наш фронт
ansible-playbook -i hosts/prod.ini task/nginx/front.yml
Теперь наш фронт начал посылать запросы на наш фронт апп!
Но там ещё ничего нет ....
Сервисы
Наш фронт апп также является сервисом как и остальные сервисы, просто он принимает запрос из сети интернет, поэтому он конфигурируеться как и все остальный сервисы.
в папке hosts/group_vars/ в соответвии названием группы находяться файлы конфигурации группы
#hosts/group_vars/front_app.yml
service_name: front_app
deploy_via: git
repo: 'https://github.com/dangerousvasil/simpleFront'
branch: 'master'
keep_releases: 10
также общие конфигурации hosts/group_vars/all.yml
releases_path: '/var/www'
current_release_dir: 'www'
application_configuration_path: '/etc/application/config.ini'
keep_releases: 0
apt_cache_valid_time: 86400
www_user: 'www-data'
Здесь мы можем указать куда деплоить код приложения и файл конфигурации и много других конфигураций который в дальнейшем вам потребуются.
Запустим задачу на обновления кода приложения
ansible-playbook -i hosts/prod.ini task/app/code-update.yml
Теперь наше приложение уже готово принимать первые запросы на фронт! Также мы можем зайти на нашу ВМ и посмотреть где же лежит наш код по умолчанию это
{{ releases_path }}/{{ service_name }}/{{ current_release_dir }}
/var/www/front_app/www
Зайдя на машинку мы увидим что эта папка у нас являеться ссылкой которая ведёт на другую папку releases/20171024121418Z, это сделаного для того чтобы мы всегда могли откатить изменения на прошлый успешный релиз
lrwxrwxrwx /var/www/front_app/www -> /var/www/front_app/releases/20171024121418Z
releases:
total 40
drwxr-xr-x 2 20171024121418Z
drwxr-xr-x 2 20171024120329Z
drwxr-xr-x 2 20171024112918Z
drwxr-xr-x 2 20171024104100Z
drwxr-xr-x 2 20171024102800Z
drwxr-xr-x 2 20171024102702Z
drwxr-xr-x 2 20171024102548Z
drwxr-xr-x 2 20171024102458Z
drwxr-xr-x 2 20171024095629Z
drwxr-xr-x 2 20171024094949Z
Для этого есть задача
ansible-playbook -i hosts/prod.ini task/app/code-rollback.yml
Это передвинет нашу ссылку на прошлый релиз, если он был, или выдаст исключение. Если запустить задачу ещё раз то передвинет ссылку дальше пока релизы не закончатся.
Балансер
Код выложен, фронт настроен, осталось дело за малым — балансировщик сервисов.
Пока используем 1 можно добавить ещё несколько и банасировать между ними с помощью разных инструментов ddns или HAProxy или просто рандомно выбирать сервер на стороне приложения — решать вам.
Запускаем задачу
ansible-playbook -i hosts/prod.ini task/nginx/balancer.yml
С помошью файла hosts/group_vars/nginx-balancer.yml
Создаться конфигурация балансировки указанных сервисов соответвенно тут имя сервиса совпадает с группой в файле инвентория, но может не совпадать с именем сервиса указанным в файле конфигурации сервера
with_services:
- sign
Окружение
Для того чтобы наше приложение знало что её окружает (балансеры, сервисы) мы сгенерируем небольшой ini файл и разложим его на каждую машинку
ansible-playbook -i hosts/prod.ini task/app/app_config.yml
$ cat /etc/application.ini
[application]
service.host[]=192.168.56.102
Теперь наше приложение знает кто отвечает за связь с сервисами, сюда можно и добавить другие настройки вашего приложения.
Тестирование
Открыв в браузере наш фронт http://192.168.56.102 мы увидим неприглядную картинку
string(14) "192.168.56.104"
string(191) "HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 25 Oct 2017 09:51:43 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
<h1>API</h1>"
Для кого-то это кажеться полной ерундой, а кто-то увидит что наш сервис написал нам свои 3 большие буквы "API" и обрадуется.
Заключение
Если вы добавили свой проект в качестве фронта и написали там пару строчек или подключили пару бибилиотек для работы с сервисами по json-rpc( наверно вы разбираетесь в PHP и вам это сильно поможет)
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://' . $serviceHost); // balancer
$header[] = "Host: service"; // необходимый сервис
@curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
$output = curl_exec($ch);
var_dump($output);
Вариант с бибилиотекой fguillot/json-rpc
$client = new Client('http://' . $serviceHost); // balancer
$http = $client->getHttpClient()
->withHeaders(['Host: service']); // service
То поздравляю вы окунули свой проект в самый модный и молодежный тренд сезона SOA.
Пост скриптум
Код проекта ещё требует множества доработок и конфигураций, поэтому сделаны только основные конфигурации чтобы работало.