Ссылки на этапы:
- Спринт 1: https://github.com/andryplekhanov/sf-diploma-sprint1
- Спринт 2: https://gitlab.com/andryplekhanov/dj-project
- Спринт 3: https://gitlab.com/andryplekhanov/monitoring
Опишите инфраструктуру будущего проекта в виде кода с инструкциями по развертке, нужен кластер Kubernetes и служебный сервер (будем называть его srv).
1. Выбираем облачный провайдер и инфраструктуру.
2. Описываем инфраструктуру.
3. Автоматизируем установку.
**Нам нужно:**
- кластер Kubernetes;
- сервер **srv** для инструментов мониторинга, логгирования и сборок контейнеров.
Описывать инфраструктуру мы будем, конечно, в Terraform.
Надо реализовать возможность установки на сервер всех необходимых нам настроек и пакетов, будь то docker-compose, gitlab-runner или наши публичные ключи для доступа по SSH. Положите код автоматизации в Git-репозиторий.
- Вы должны производить действия на локальном хосте с Unix-системой (у меня Ubuntu 2204); должен быть установлен terraform; должны быть сгенерированы ssh-ключи без пароля с именами
id_rsa
иid_rsa.pub
в директории~/.ssh/
- Скачать репо и перейти в директорию
git clone https://github.com/andryplekhanov/sf-diploma-sprint1.git && cd sf-diploma-sprint1/terraform
- Инициировать терраформ
terraform init
- Применить
terraform apply -var="yandex_cloud_token=<ваш токен>" -var="cloud_id=<ваш cloud_id>" -var="folder_id=<ваш folder_id>"
- В результате получаем в консоли ip-адрес контроллер-сервера srv:
external_ip_address_srv = [
[
"158.160.102.92",
],
]
- Подключиться по ssh к серверу srv
ssh ubuntu@<external_ip_address_srv>
- Сделаться суперюзером
sudo su -
- Перейти в директорию
cd /opt/kubernetes_setup
- Запустить скрипт
sh cluster_install.sh
Данный скрипт при помощи Terraform развернёт в Яндекс-облаке необходимую инфраструктуру для кластера k8s. После развёртывания получаем информацию об инфраструктуре. Нас интересует ip ингресс-контроллера и балансировщика:
instance_group_ingresses_public_ips = tolist([
"158.160.164.226",
])
load_balancer_public_ip = tolist([
"158.160.165.17",
])
Запомним ip. Нам они понадобятся на следующем спринте.
- Через 85 секунд автоматически начнётся развёртка кластера k8s при помощи Ansible.
- В результате получаем в консоли информацию о кластере:
Если ничего больше не нужно, то удаляем всё в 2 этапа:
- На сервере srv:
sudo su -
,cd /opt/kubernetes_setup
,sh cluster_destroy.sh
- На локальном хосте в каталоге
sf-diploma-sprint1/terraform
:terraform destroy -var="yandex_cloud_token=<ваш токен>" -var="cloud_id=<ваш cloud_id>" -var="folder_id=<ваш folder_id>"
1. Клонируем репозиторий, собираем его на сервере srv.
Это простое приложение на Django с уже написанным Dockerfile.
Приложение работает с PostgreSQL, в самом репозитории уже есть реализация docker-compose — её можно брать за референс при написании Helm-чарта.
Необходимо склонировать репозиторий выше к себе в Git и настроить пайплайн с этапом сборки образа и отправки его в любой docker registry.
Для пайплайнов рекомендуем GitLab.
2. Описываем приложение в Helm-чарт. Стоит хранить данные в БД с помощью PVC в Kubernetes.
3. Описываем стадию деплоя в Helm.
Настраиваем деплой стадию пайплайна. Применяем Helm-чарт в наш кластер.
Нужно сделать так, чтобы наше приложение разворачивалось после сборки в Kubernetes и было доступно по бесплатному домену или на IP-адресе с выбранным портом.
Для деплоя должен использоваться свежесобранный образ.
По возможности нужно реализовать сборку из тегов в Git, где тег репозитория в Git будет равен тегу собираемого образа.
Чтобы создание такого тега запускало пайплайн на сборку образа c таким именем hub.docker.com/skillfactory/testapp:2.0.3.
- Зарегистрировал доменное имя
andryplekhanov.ru
на reg.ru и подключил его к DNS Яндексаns1.yandexcloud.net
иns2.yandexcloud.net
. - На Яндекс-облаке создал публичную зону
andryplekhanov.ru.
и wildcard A-запись*.andryplekhanov.ru.
, указывающую на IP балансировщика (load_balancer_public_ip
), который мы получили на предыдущем спринте.
- Создал новый репо на Gitlab, перенёс сюда django-приложение.
- Добавил новый раннер в проект:
Settings - CI/CD - Runners - New project runner
и получил команду для его регистрации:gitlab-runner register --url https://gitlab.com --token <токен>
. - Зашел на сервер srv:
ssh ubuntu@<external_ip_address_srv>
, залогинился под sudo:sudo su
и применил там вышеуказанную команду. Экзекьютор выбрал shell.
- Идём на Dockerhub. Создаём репо проекта. Записываем себе его название в формате
myusername/myprojectname
. - Переходим в раздел
My account / security
и регистрируем новый токен с правамиRead & Write
. Записываем себе username и токен.
- Идём на Gitlab в наше репо, переходим в раздел
settings/ci_cd/variables
- Добавляем все переменные, необходимые для проекта:
POSTGRES_DB: <название базы данных>
POSTGRES_USER: <имя пользователя базы данных>
POSTGRES_PASSWORD: <пароль для базы данных>
SECRET_KEY: <секретный ключ из настроек Django-приложения>
DEBUG: <оставить пустым, если не хотим, чтобы приложение работало в debug-режиме>
IMAGE: <название репо в dockerhub в формате myusername/myprojectname>
DOCKER_USER: <username из dockerhub>
DOCKER_TOKEN: <токен из dockerhub>
HOST: <зарегистрированное доменное имя в формате test.mysite.ru>
INGRESSIP: <ip созданного ингресс-контроллера instance_group_ingresses_public_ips>
SUBNETID: <id подсети, в которой находится ингресс-контроллер>
Создал директорию ./k8s/helm/
, где создал helm-chart.
Структура чарта:
.
├── k8s
│ └── helm
│ ├── values.yaml
│ ├── Chart.yaml
│ ├── templates
│ │ ├── app.yaml
│ │ ├── app-secrets.yaml
│ │ ├── _common.tpl
│ │ ├── postgres.yaml
│ │ └── postgres-secrets.yaml
В директории ./k8s/helm/templates
созданы манифесты:
- в
app.yaml
: описаны deployment, service и ingress django-приложения - в
postgres.yaml
: описаны deployment, service и PersistentVolumeClaim базы данных - в
app-secrets.yaml
: описаны секреты для app - в
postgres-secrets.yaml
: описаны секреты для postgres
В файле ./k8s/helm/values.yaml
собраны всё необходимые настройки для app и postgres.
Создал файл .gitlab-ci.yml
и описал этапы сборки и деплоя.
В пайплайне используются все созданные ранее переменные.
ВНИМАНИЕ! Все джобы запускаются только из тегов
На этапе сборки происходит логин в наш Dockerhub, сборка образа приложения из Dockerfile (тег подставляется автоматически) и выгрузка готового образа на Dockerhub.
На этапе деплоя происходит запуск команды helm upgrade --install django-release
с автоматической передачей в проект всех необходимых переменных.
- В итоге нужно закоммитить и запушить изменения:
git add . && git commit -m 'some six' && git push
- Затем проставить и запушить тег:
git tag v1.0.23 && git push origin v1.0.23
. Только тогда запустится пайплайн.
Результат выполнения пайплайна в Gitlab:
Результат развёртывания приложения в браузере:
ВНИМАНИЕ! Для администрирования Django-приложения через админ-панель необходимо создать суперпользователя. Для этого на управляющем сервере srv выполняем команды:
- заходим внутрь контейнера:
kubectl exec -it deployment.apps/app-deployment -- sh
- создаём суперпользователя:
python manage.py createsuperuser
- вводим необходимые данные и нажимаем
Ctrl + D
для выхода - теперь можно войти в админ-панель по адресу
http://<your_site>/admin
1 Настройка сборки логов.
Представьте, что вы разработчик, и вам нужно оперативно получать информацию с ошибками работы приложения.
Выберите инструмент, с помощью которого такой функционал можно предоставить. Нужно собирать логи работы пода приложения. Хранить это всё можно либо в самом кластере Kubernetes, либо на srv-сервере.
2 Выбор метрик для мониторинга.
Так, теперь творческий этап. Допустим, наше приложение имеет для нас некоторую важность. Мы бы хотели знать, когда пользователь не может на него попасть — время отклика, сертификат, статус код и так далее. Выберите метрики и инструмент, с помощью которого будем отслеживать его состояние.
Также мы хотели бы знать, когда место на srv-сервере подходит к концу.
Важно! Весь мониторинг должен находиться на srv-сервере, чтобы в случае падения кластера мы все равно могли узнать об этом.
3 Настройка дашборда.
Ко всему прочему хотелось бы и наблюдать за метриками в разрезе времени. Для этого мы можем использовать Grafana и Zabbix — что больше понравилось.
4 Алертинг.
А теперь добавим уведомления в ваш любимый мессенджер. Обязательно протестируйте отправку уведомлений. Попробуйте «убить» приложение самостоятельно, и засеките время от инцидента до получения уведомления. Если время адекватное, то можно считать, что вы справились с этим проектом!
В качестве решения был выбран стэк мониторинга Prometheus + Loki + Grafana + Alertmanager.
Разворачивать будем всё при помощи ролей Ansible.
- На все ноды кластера и сервер srv устанавливается node-exporter, для мониторинга самих хостов.
- На все ноды кластера устанавливается promtail для сбора логов.
- На сервере srv разворачиваются:
- prometheus, grafana - для сбора метрик и их визуализации;
- loki для сбора логов от promtail;
- blackbox - для мониторинга веб страницы с приложением;
- alertmanager и alertmanager-bot для алертинга.
exporters:
- На целевых серверах создается директория
/opt/node-exporter
, в неё копируется dockercompose.yml файл из директорииfiles
роли, далее с помощью docker compose запускаются сервисы node-exporter на хостах.
monitoring:
- На сервере srv создаются поддиректории для будущих сервисов в директории
/opt
. - На сервер srv копируется docker-compose.yml файл, который формируется из шаблона docker-compose-template.j2. Для формирования файла используются переменные зашифрованного с помошью ansible-vault файла
vars/main.yml
, в нём содержится токен бота и id пользователя. - Конфигурация для node-exporters формируется динамически, с помощью шаблона exporters.yml.j2 на основе данных указанных в файле hosts.
- Далее копируются все необходимые файлы конфигураций из директории files, и сервисы запускаются с помощью docker compose.
logging:
- На сервере srv создаётся директория
/opt/promtail
, в неё копируетсяvalues.yml
файл. - Promtail разворачивается с помощью готового helm-чарта из репозитория https://grafana.github.io/helm-charts в отдельном namespace logging.
-
Запускать роли необходимо с сервера srv. Клонируем репозиторий:
git clone https://gitlab.com/andryplekhanov/monitoring.git
и переходим в него:cd monitoring
-
Редактируем файлы:
hosts
, вбиваем приватные адреса нод кластера и сервера srv.roles/logging/files/values.yml
, вбиваем приватный адрес сервера srv.roles/monitoring/files/prometheus.yml
, вбиваем url-адрес своего сайта (строка 19).
-
Редактируем файл roles/monitoring/vars/main.yml командой
ansible-vault edit roles/monitoring/vars/main.yml
Данный файл зашифрован при помощи ansible-vault, пароль -zyHCVr6nWN@n
. Вбиваем данные: id пользователя и токен Telegram-бота. -
Выполняем команду
export ANSIBLE_HOST_KEY_CHECKING=False
, чтобы Ansible не запрашивал подтверждение при подключении к серверам. -
Запускаем поочерёдно три роли:
ansible-playbook -i hosts playbook.yml -t exporters --ask-vault-pass
ansible-playbook -i hosts playbook.yml -t mon --ask-vault-pass
ansible-playbook -i hosts playbook.yml -t log --ask-vault-pass
При каждом запуске необходимо ввести пароль для декрипта файла с переменными
zyHCVr6nWN@n
В итоге имеем:
- Grafana доступна по публичному адресу сервера srv на порту 3000 - http://158.160.102.92:3000/ . Логин и пароль admin и admin.
- Prometheus на том же адресе, на порту 9090 - http://158.160.102.92:9090/
В Prometheus на вкладке "Targets" должны появиться все таргеты со статусом "UP", а на вкладке "Alerts" - правила алертинга.
- Заходим в интерфейс Grafana http://158.160.102.92:3000/ . Логин и пароль admin и admin.
- Добавляем Data source для Prometheus:
http://prometheus:9090/
- Добавляем дашборды:
- импортируем готовый шаблон для node-exporter с id - 1860. В качестве источника указываем Prometheus.
- импортируем готовый шаблон для loki с id - 13639, в качестве источника указываем loki.
- импортируем готовый шаблон для blackbox с id - 7587. В качестве источника указываем Prometheus.
В итоге имеем дашборды со всеми метриками, логи и алертинг: