Дипломный практикум в YandexCloud
Цели:
- Зарегистрировать доменное имя (любое на ваш выбор в любой доменной зоне).
- Подготовить инфраструктуру с помощью Terraform на базе облачного провайдера YandexCloud.
- Настроить внешний Reverse Proxy на основе Nginx и LetsEncrypt.
- Настроить кластер MySQL.
- Установить WordPress.
- Развернуть Gitlab CE и Gitlab Runner. Настроить CI/CD для автоматического развёртывания приложения.
- Настроить мониторинг инфраструктуры с помощью стека: Prometheus, Alert Manager и Grafana.
Этапы выполнения:
Зарегистрировано доменное имя ITILI4.RU у регистратора reg.ru, управление DNS зоной делегировано в Яндекс CloudDNS.
Необходимо для автоматизации управления DNS записями зоны.
Для создания инфраструктуры использовал Terraform, в качестве backend S3 хранилище от YandexCloud. Создал два workspace prod и stage.
Все инфраструктура выполняется от роли сервисного аккаунта с достаточным количеством привилегий.
Отличия в workspace:
- Имена виртуальных машин(не hostname) в панели управления указываются с учетом workspace в котором они созданы.
- Мощность(системные требования) создаваемых виртуальных машин не для prod workspace уменьшены в 2 раза, там где это возможно.
- В prod workspace виртуальные машины создаются с параметрами запрещающим их остановку по желанию YandexCloud. В stage этот параметр разрешен, т.к. время жизни виртуальных машин значительно меньше чем в prod, дополнительно это опция экономит баланс.
Скриншот с примером prod workspace.
Ниже представлен листинг файла terraform variables.tf определяем переменные используемые во всей инфраструктуре.
variable "yandex_cloud_id" {
default = "b1ghoagi59974h152cps"
}
variable "yandex_folder_id" {
default = "b1g5mpl5ths26blfceli"
}
# ID можно узнать с помощью команды yc compute image list
variable "centos-7-base" {
default = "fd88d14a6790do254kj7"
}
variable "dns_zone_id" {
default = "dns0i82057c3jl8cntu6"
}
Ниже представлен листинг файла terraform provider.tf определяем какой провайдер для YandexCloud используем, как попасть в S3 bucket, и ключи доступа для работы от имени сервисного аккаунта.
terraform {
required_providers {
yandex = {
source = "yandex-cloud/yandex"
}
}
backend "s3" {
endpoint = "storage.yandexcloud.net"
bucket = "diplom-bucket"
region = "ru-central1"
key = "terraform/terraform.tfstate"
access_key = "YCAJELZI5zOAW2vJTgDV7UUbc"
secret_key = "YCN8WGUE6cFjxTVG2TgHsEhn_3ZC7xMw3HssOCNz"
skip_region_validation = true
skip_credentials_validation = true
}
}
provider "yandex" {
service_account_key_file = "key.json"
cloud_id = "${var.yandex_cloud_id}"
folder_id = "${var.yandex_folder_id}"
}
Файл inventory для Ansible формирует terraform после создания инфраструктуры, листинг файла inventory.tf
resource "local_file" "inventory" {
content = <<-DOC
[nodes:children]
frontend
dbservers
glservers
runnerservers
gpaservers
dbha
[reversproxy]
rproxy.itili4.ru ansible_host=${yandex_compute_instance.rproxy.network_interface.0.nat_ip_address}
[frontend]
wordpress.itili4.ru ansible_host=${yandex_compute_instance.wordpress.network_interface.0.ip_address}
[dbservers]
db01.itili4.ru ansible_host=${yandex_compute_instance.db01.network_interface.0.ip_address}
db02.itili4.ru ansible_host=${yandex_compute_instance.db02.network_interface.0.ip_address}
[glservers]
gitlab.itili4.ru ansible_host=${yandex_compute_instance.gitlab.network_interface.0.ip_address}
[runnerservers]
grunner.itili4.ru ansible_host=${yandex_compute_instance.grunner.network_interface.0.ip_address}
[gpaservers]
gpa.itili4.ru ansible_host=${yandex_compute_instance.gpa.network_interface.0.ip_address}
[dbha]
dbha.itili4.ru ansible_host=${yandex_compute_instance.dbha.network_interface.0.ip_address}
[nodes:vars]
ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ProxyCommand="ssh -W %h:%p -q centos@${yandex_compute_instance.rproxy.network_interface.0.nat_ip_address}"'
ansible_ssh_user=centos
[reversproxy:vars]
ansible_ssh_common_args='-o StrictHostKeyChecking=no'
ansible_ssh_user=centos
ansible_ssh_private_key_file=/home/yolo/.ssh/id_rsa
DOC
filename = "../ansible/inventory"
depends_on = [
yandex_compute_instance.rproxy,
yandex_compute_instance.db01,
yandex_compute_instance.db02,
yandex_compute_instance.dbha,
yandex_compute_instance.gitlab,
yandex_compute_instance.grunner,
yandex_compute_instance.gpa
]
}
Для удоства работы с инфраструктурой и provisioning создал alias.
alias tera="terraform apply --auto-approve"
alias terd="terraform destroy --auto-approve"
alias terprov="ansible-playbook -i /home/yolo/PycharmProjects/diplom-netology/src/ansible/inventory /home/yolo/PycharmProjects/diplom-netology/src/ansible/mainplaybook.yml"
Пришел к ней после выполнения всех этапов работы, некоторые конфигурации были изменены(Увеличил RAM у GitlabServer), добавил сервер dbha.itili4.ru для переключения нагрузку в случае падения основного сервера кластера MySQL.
А-записи доменов создаются при развертывания инфраструктуры, т.к. наполнением ДНС-зоны занимается terraform. DNS-зона делегирована и развернута в YandexCloud как отдельный сервис.
В процессе установки роль настраивает Selinux, подключаем необходимый репозиторий, устанавливает пакеты для Nginx.
Выполняет копирование шаблонов конфигураций виртуальных хостов и наполняет их данными из переменных.
Выполняет получение сертификатов с LetsEncrypt.
Получили сертификаты и проверили перенаправление.
Основные возникшие проблемы при выполнения описанного этапа возникли из-за незнания принципов работы Selinux, по мере выполнения дипломной работы становилось понятней, очень помогает audit.log и google.
Роль для установки и настройки кластера MySQL называется install-mysql-service
Роль сначала выполняет базовую настройку устновку и настройку сервиса. Создает пользователей для работы с БД и для репликации. Далее, создаем базу данных, назначаем пользователям права для работы с ней и настраиваем возможность доступа к серверу БД из вне. Далее, добавляем базу данных в репликацию и запускаем её. Проверяем, что репликация запустилась и работает.
Кластер из MySQL собирал в первый раз, до этого работал только с кластерными конфигурациями PostgreSQL и MS SQL. Пришлось также повозиться с Selinux и корректной раздачей прав.
Скриншоты демонстрации успешного выполнения роли.
Мастер сервер
Ведомый сервер
Роль для установки reverse proxy для Mysql Cluster. install-mysql-service
Роль как и дополнительный сервер необходимо реализовать, в противном случае при падении сервера прописанного в конфигурационном файле wp-config.php упадет и сайт, т.к. в качестве точки входа в базу данных указа Master-server т.к. только он доступен на запись. Описанная роль создает обратный прокси для tcp-соединений, и следит за состоянием хостов backend. В случае падения основного сервера все запросы перейду на вторичный. Который в свою очередь, после падения основного, станет главным. В процессе работы роли, устанавливается специальный пакет Nginx-mod-stream скомпилированный с дополнительным пакетом поддержки tcp-потоков. Конфигурационный файл копируется из шаблона.
Роль для установки и настройки Wordpress install-wordpress
В качестве WEB-сервера для разнообразия выбрал Apache. Роль устанавливает необходимые пакеты для Web-server Apache, далее подключаем дополнительный репозиторий для нужной версии PHP(в моем случае 7.4), в стандартном репозитории Centos 7 была только 5ая версия PHP. Далее настраиваем VHOSTS для работы с сайтом, создаем необходимые папки(корень сайта и папка с логами). Далее скачиваем и устанавливаем Wordpress, заменяем файл WP-CONFIG.php на наш, преднастроенный файл для созданной инфраструктуры.
Далее уже руками заходим через интернет-бразуер и проверяем что сайт открывается корректно и ошибок нет.
На этом этапе Selinux был очень против переноса каталога с лог-файлами в другое место.
Роль для установки и настройки Gitlab CE называется install-gitlab
Роль добавляет необходимый репозиторий, устанавливает требуемые пакеты, копирует преднастроенный шаблон и заполняется данными из переменных. Далее перезапускаем сервис для принятия параметров из конфигурационного файла. Логин, пароль от учетной записи root и token для регистрации runner'а заранее предопределены в переменных. Для стабильной работы сервиса потребовалось увеличение оперативной памяти до 8Gb.
Роль для установки и настройки Gitlab CE Runner называется install-grunner
Роль добавляет необходимый репозиторий, устанавливает требуемые пакеты, создает преднастроенный шаблон конфигурационного файла и заполняется данными из переменных. Для регистрации runner использует token переданные ему в переменной, который предварительно был определен при конфигурировании сервера Gitlab CE. Все прошло успешно, в WEB-интерфейсе Gitlab CE можно увидеть зарегистрированный Runner.
CI/CD Pipeline install-rsync
Шаги для реализации pipeline:
0) Для корректной работы Pipeline в части передачи кода из репозитория через runner, необходимо дополнительно установить на application-server(WordPress) Rsync-сервис, с преднастроенной точкой обмена. На Gitlab runner устанавливает клиентскую часть. Все манипуляции выполняются одной ролью, логика работы зависит от имени сервера на котором была запущена роль.
- Создаем репозиторий для проекта. Заходим в веб-часть Gitlab и создаем новый репозиторий "Wordpress"
- Заходим на application-server в корневую директорию сайта, инициализируем git внутри кореневого каталога, настраиваем локальный репозиторий согласно инструкции полученной от Gitlab при создании пустого репозитория. Делаем первый коммит, если все прошло успешно то в веб-части Gitlab появится файлы из директории сайта.
- Создаем CI/CD Pipeline в Gitlab. В интерфейсе Gitlab выбираем CI/CD->Editor, нам предлагают создать ".gitlab-ci.yml". Файл в котором и будет храниться код CI/CD текущего проекта.
- Заменяем содержимое шаблонного файла нашим кодом.
variables:
GIT_STRATEGY: clone
stages:
- deploy
tag-job:
stage: deploy
rules:
- if: '$CI_COMMIT_TAG != null'
script:
- echo $CI_RSYNC_PASS > /home/gitlab-runner/rsyncd.scrt
- chmod 600 /home/gitlab-runner/rsyncd.scrt
- rsync -rult --password-file=/home/gitlab-runner/rsyncd.scrt --exclude '.*' $CI_PROJECT_DIR/ grunner@wordpress.itili4.ru::www
- rm /home/gitlab-runner/rsyncd.scrt
Делаем commit и сохраняем получившийся файл в репозиторий с проектом, теперь Gitlab CI/CD будет знать что и когда ему делать, Auto DevOps, вмешиваться больше не должен.
Создаем переменную окружения $CI_RSYNC_PASS
т.к. она определена нами и не содержится в стандартных переменных Gitlab.
Переходим в Settings->CI/CD->Variables, создаем новую переменную...
...и снимаем флажки. Я в первый раз их не снял и получил ошибку, так как pipeline не смог получить доступ к переменной.
- Pipeline ГОТОВ!
Проверяем...
- Создаем пустой файл в репозитории проекта через web-ide gitlab(так быстрее всего), пишем в него одну строчку, делаем коммит.
- Идем смотреть появились ли новые Job или был ли запущен pipeline. Ничего не сработало, значит пока все в порядке.
- Вносим изменения в файл, добавляем вторую строчку, делаем коммит, делает тег на коммит.
- Идем проверять новые job. Видим что появились новые job на тегированном коммите, значит все работает...
- Идем проверять директорию. Вернемся в прошлое и получим скриншот того что было до тегированного коммита
Нового файла нет
Идем в настоящее
Файл есть, содержимое совпадает. Теперь точно все работает.
Роль для установки и настройки Node Exporter install-node_exporter
Роль скачивает с репозитория указанную версию дистрибутива, распаковывает во временную папку, раскладывает исполняемые файлы, заполняет конфигурационный файл шаблона из переменных и создаем systemd файл для удобного управления сервисом, в окончании проверяем что служба работает и открыт нужный порт.
Роль для установки и настройки Prometheus install-prometheus
Роль скачивает с репозитория указанную версию дистрибутива, распаковывает во временную папку, раскладывает исполняемые файлы, заполняет конфигурационный файл шаблона(Указываем точки сбора трафика, описываем алерты и куда отправлять алерты) из переменных и создаем systemd файл для удобного управления сервисом.
Роль для установки и настройки Grafana install-grafana
Роль скачивает с репозитория указанную версию дистрибутива, распаковывает во временную папку, раскладывает исполняемые файлы, заполняет конфигурационный файл шаблона(Данные учетной записи для входа и источники данных) из переменных и создаем systemd файл для удобного управления сервисом. Дополнительно загружаем шаблон для демонстрации данных Node Exporter, шаблон передаем файлово т.к. загрузка из центрального репозитория Grafana не работает/временно не работает из YandexCloud...
Роль для установки и настройки Alert Manager install-alertmanager
Роль скачивает с репозитория указанную версию дистрибутива, распаковывает во временную папку, раскладывает исполняемые файлы, заполняет конфигурационный файл шаблона из переменных и создаем systemd файл для удобного управления сервисом, в окончании проверяем что служба работает и открыт нужный порт. Дополнительно передаем параметры доставка оповещений о сработке алертов.
Роль для сбора метрик install-wordpressexporter
Экспортер метрик написан на Golang, за метриками ходит прямо в MySQL в базу данных сайта.
Вытаскивает данные по количестову зарегистрированных пользователей, количество постов, количество комментариев.
Сбор метрик можно расширить при необходимости, дописав скрипт на Go.
Дашбоард для Grafana устанавливается в роли по настройке Grafana, Job для Prometheus аналогично.
Пример получаемых метрик через консоль:
[root@itili4 centos]# curl http://wordpress.itili4.ru:8888/metrics | grep wp_
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 6409 0 6409 0 0 566k 0 --:--:-- --:--:-- --:--:-- 625k
# HELP wp_num_comments_metric Shows the number of total comments in the WordPress site
# TYPE wp_num_comments_metric counter
wp_num_comments_metric 1
# HELP wp_num_posts_metric Shows the number of total posts in the WordPress site
# TYPE wp_num_posts_metric counter
wp_num_posts_metric 1
# HELP wp_num_users_metric Shows the number of registered users in the WordPress site
# TYPE wp_num_users_metric counter
wp_num_users_metric 1
[root@itili4 centos]#
Скриншоты интерфейса Grafan с нужным дашбородом. (Источник данных и запросы пришлось править руками в WEB, в дашбордах пока не силен...)