{"id":21175554,"url":"https://github.com/capcom6-learning/otus-administrator-linux-basic-project","last_synced_at":"2026-04-27T00:32:06.063Z","repository":{"id":114529500,"uuid":"355937124","full_name":"capcom6-learning/otus-administrator-linux-basic-project","owner":"capcom6-learning","description":"Проектная работа по курсу \"Администратор Linux. Basic\" на портале OTUS.","archived":false,"fork":false,"pushed_at":"2021-05-10T05:45:07.000Z","size":100,"stargazers_count":0,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-27T03:03:08.446Z","etag":null,"topics":["ansible","mariadb","prometheus-grafana","slave-db","slave-master"],"latest_commit_sha":null,"homepage":"","language":"Jinja","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/capcom6-learning.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-08T14:21:05.000Z","updated_at":"2024-10-04T03:22:51.000Z","dependencies_parsed_at":"2023-06-08T18:45:30.316Z","dependency_job_id":null,"html_url":"https://github.com/capcom6-learning/otus-administrator-linux-basic-project","commit_stats":null,"previous_names":["capcom6-learning/otus-administrator-linux-basic-project"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/capcom6-learning/otus-administrator-linux-basic-project","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capcom6-learning%2Fotus-administrator-linux-basic-project","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capcom6-learning%2Fotus-administrator-linux-basic-project/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capcom6-learning%2Fotus-administrator-linux-basic-project/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capcom6-learning%2Fotus-administrator-linux-basic-project/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/capcom6-learning","download_url":"https://codeload.github.com/capcom6-learning/otus-administrator-linux-basic-project/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capcom6-learning%2Fotus-administrator-linux-basic-project/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32318417,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"ssl_error","status_checked_at":"2026-04-26T23:26:25.802Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","mariadb","prometheus-grafana","slave-db","slave-master"],"created_at":"2024-11-20T16:59:52.171Z","updated_at":"2026-04-27T00:32:06.048Z","avatar_url":"https://github.com/capcom6-learning.png","language":"Jinja","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Проектная работа\n\nТема: развертывание веб-приложения на базе фреймворка CodeIgniter с балансировкой нагрузки средствами NGinx, применением стэка Apache + PHP + MariaDB, репликацией и резервным копированием базы данных и мониторингом на основе Node Exporter + Prometheus + Grafana.\n\n# Ход работы\n\nРабота выполняется на CentOS 7 со следующим набором серверов:\n\n1. Frontend-сервер на базе Nginx.\n2. Backend-сервера в количестве 2 шт. на базе Apache + PHP.\n3. Сервер баз данных на основе MariaDB.\n4. Сервер репликации базы данных MariaDB с резервным копированием.\n5. Сервер мониторинга на базе Prometheus + Grafana.\n\nДанные сервера развернуты у облачного провайдера с заранее прописанным ключом доступа по SSH для пользователя root. Для настройки серверов используется Ansible.\n\nДля демонстрационных целей выбрано не конкретное веб-приложение, а PHP-фреймворк CodeIgniter. Такой выбор сделан из расчета, что развертывание всех приложений на данной фреймворке будет иметь сходные шаги, а конечной целью является развертывание коммерческого веб-приложения с закрытым исходным кодом на данном фреймворке.\n\n## Формирование файла инвентаря\n\nВсе сервера были сгруппированы по своему назначению и прописаны в файл `hosts` для дальнейшего использования с Ansible. Были выделеные следующие группы:\n\n* webservers - backend-сервера;\n* gluster - сервера, входящие в кластер GlusterFS;\n* dbservers - основной MySQL-сервер, было условлено, что данная группа должна содержать ровно 1 сервер для корректной настройки репликации;\n* dbslaves - реплики основного MySQL-сервера;\n* lbservers - frontend-сервер;\n* monitoring - сервер мониторинга.\n\nДля групп `dbservers` и `dbslaves` непосредственно в файле `hosts` указано значение переменной server_id. Указание данной переменной в общем файле вместо использования `hosts_vars` позволяет иметь возможность визуального контроля уникальности используемых server_id.\n\n## Формирование ролей\n\nДля перечисленных ранее серверов были выделены следующие роли:\n\n* common - общая для всех серверов роль, выполняющая базовые настройки;\n* base-apache - установка и настройка Apache + PHP;\n* base-db - установка и настройки MariaDB;\n* slave-db - действия по развертыванию реплики MySQL-сервера;\n* master-db - действия по переводу Slave в Master;\n* nginx - установка и настройка балансировщика нагрузки на базе Nginx;\n* web - развертывание веб-приложения из репозитория;\n* web-db - создание базы данных приложения;\n* monitoring - установка и настройка Prometheus + Grafana;\n* monitoring-node - установка экспортеров для Prometheus;\n* gluster - настройка томов GlusterFS и их монтирование.\n\nДанные роли были назначены группам серверов следующим образом:\n\n* все сервера:\n    * common;\n    * monitoring-node.\n* dbservers:\n    * base-db;\n    * master-db;\n    * web-db.\n* dbslaves:\n    * base-db;\n    * slave-db.\n* webservers:\n    * base-apache;\n    * web.\n* gluster:\n    * gluster.\n* lbservers:\n    * nginx.\n* monitoring:\n    * monitoring.\n\nРоль и группа `gluster` специально выделены отдельно несмотря на то, что на текущий момент данная группа совпадает с группой `webservers` с целью возможности развертывания дополнительных серверов в кластере не являющихся при этом веб-серверами. Это позволит, например, развернуть отдельный сервер для резервного копирования пользовательских данных.\n\nДалее рассмотрены ключевые моменты отдельных ролей.\n\n### Роль common\n\nЦель данной роли выполнить общие настройки сервера, в частности:\n\n* установить репозиторий epel-release;\n* разрешить неограниченный доступ к серверам в рамках виртуальной сети, которая выделена в переменную `network` в файле `group_vars/all`;\n* отключить SELinux для упрощения развертывания. Ряд ролей уже содержит применение настроек для случая включенного SELinux, но требуется дополнительная работа в данном направлении.\n\n### Роль monitoring-node\n\nДанная роль выполняет установку на сервер Node Exporter и сопутствующие настройки:\n\n* создает пользователя prometheus-exporter для ограничения прав Node Exporter;\n* проверяет наличие уже установленного Node Exporter, чтобы не выполнять повторную установку;\n* при отсутствии Node Exporter на сервере выполняестя копирование инсталляционного скрипта и его запуск;\n* в конечном счете регистрируется юнит systemd и запускается сервис.\n\nДля установки используется шаблон простого скрипта с переменной для версии Node Exporter:\n\n```bash\n#!/bin/bash\n\ncd /tmp\n# Скачаем архив с node exporter\ncurl -LO https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-amd64.tar.gz\n# Распакуем в текущую директорию\ntar xzvf node_exporter-{{ node_exporter_version }}.linux-amd64.tar.gz\n# Копируем исполняемый файл в общесистемный каталог\ncp node_exporter-{{ node_exporter_version }}.linux-amd64/node_exporter /usr/local/bin/\n\nrm -rf node_exporter-{{ node_exporter_version }}.linux-amd64\n```\n\nМинусом такого подхода к проверки наличия Node Exporter является невозможность обновления, посколкьу задача \"Check for Node Exporter binary\" проверяет лишь наличие исполняемого файла, но не проверяет версию. В итоге изменение переменной с версией не приводит к обновлению Node Exporter. Это задача для дальнейшей проработки.\n\n### Роль base-db\n\nДанная роль выполняет установку MariaDB и ее настройку, общую для основного сервера и реплики:\n\n* импортирует ключ и копирует настройки репозитория указанной в переменных версии MariaDB;\n* устанавливает основные пакеты MariaDB, а также библиотеку Python для работы с MySQL из Ansible;\n* создает конфигурационный файл сервера:\n\n```conf\n[mysqld]\n# set server_id\nserver-id\t\t        = {{ server_id }}\n# optimize memory usage\n{% if 'dbservers' in group_names %}\ninnodb_buffer_pool_size\t= {{ (ansible_memtotal_mb * 0.8) | int }}M\n{% else %}\ninnodb_buffer_pool_size\t= {{ (ansible_memtotal_mb * 0.5) | int }}M\nread_only               = 1\n{% endif %}\n\n# set binlog filename prefix\nlog_bin                 = mysql-bin\n# set binlog format\nbinlog_format           = mixed\n# set binlog expire days\nexpire_logs_days        = {{ mysql_binlog_expire }}\n# set compression for binlog\nlog_bin_compress        = ON\n```\n\nЧерез переменные задается server_id и параметры двоичного журнала для работы репликации. Также задается объем выделенной оперативной памяти. Для основного сервера выделяется 80% от общего объема, а на репликах - 50%. Это обосновано тем, что на репликах помимо непосредственно работы сервера базы данных будет производится резервное копирование, потенциально с использованием сжатия, что потребует свободной оперативной памяти.\n\nВ дальнейшем при определении объема оперативнйо памяти для сервера баз данных стоит учитывать общий объем доступной памяти. Так на системах с малым объемом памяти (\u003c 2 GB) при выделении 80% под сервер базы данных может возникнуть нехватка памяти под ОС.\n\nВ продолжение настройки выполняется еще ряд действий:\n\n* задаются права доступа по-умолчанию для новых файлов и каталогов баз данных путем указания в файле `umask.conf`. Это необходимо для корректной работы резервного копирования, поскольку по-умолчанию доступ к каталогам баз данных разрешен только пользователю mysql, а для работы резервного копирования также требуется доступ для группы mysql;\n* запускается сервис MariaDB;\n* устанавливается пароль для пользователя root и создается файл конфигурации клиента `.my.cnf` для системного пользователя root;\n* удаляются тестовые базы данных, анонимные пользователи и удаленный доступ к базе данных от имени пользователя root;\n* создаются пользователи для репликации и резервного копирования с необходимыми правами.\n\nПоскольку пароли для создаваемых пользователей хранятся в переменных, то хранение их в открытом виде не рекомендуется. В связи с этим они были предварительно зашифрованы с применением ansible-vault командами вида:\n\n```bash\nansible-vault encrypt_string --ask-vault-password '***' --name 'mysql_root_password'\n```\n\n### Роль web-db\n\nДанная роль выполняет развертывание базы данных приложения на основном сервере. Также создается пользователь базы данных приложения согласно соответствующим переменным.\n\n### Роль slave-db\n\nВ рамках данной роли выполняется 2 основных действия:\n\n* настройка репликации, если она не была настроена ранее;\n* настройка резервного копирования.\n\nРассмотрим данные действия подробнее.\n\n#### Настройка репликации\n\nПеред настройкой репликации проводится проверка текущего состояния репликации. Если репликация уже настроена, то данное действие пропускается. Настройка репликации вынесена в отдельный файл `init_replication.yml`.\n\nВ рамках инициализации репликации выполняются следующие действия:\n\n* путем делегации действий на основном сервере MariaDB с помощью утилиты mariabackup создается резервная копия с указанием позиции двоичного журнала;\n* данная копия передается на настраиваемую реплику. В данном случае это происходит через локальный компьютер, что, в общем случае, не эффективно, а потому является основанием для дальнейших доработок;\n* полученная резервная копия разворачивается на реплике, настраиваются права доступа к файлам баз данных;\n* запускается процесс репликации с использованием GTID, считанного из файла `xtrabackup_binlog_info` из состава резервной копии.\n\n#### Настройка резервного копирования\n\nДля реализации резервного копирования по расписанию создается отдельный пользователь ОС с логином backup, входящий в группу mysql для возможности доступа к файлам БД.\n\nНепосредственно резервное копирование выполняется скриптом `mysql_backup.sh`, созданном на основании шаблона:\n\n```bash\n#!/bin/sh\n\nNOW=$(date +\"%Y-%m-%d\")\n\nfind {{ mysql_backup_location }} -maxdepth 1 -ctime +{{ mysql_backup_expire }} -type d -exec rm -rf {} \\; \\\n    \u0026\u0026 mkdir -p {{ mysql_backup_location }}/${NOW} \\\n    \u0026\u0026 mariabackup --backup --target-dir={{mysql_backup_location}}/${NOW} \\\n    \u0026\u0026 mariabackup --prepare --target-dir={{mysql_backup_location}}/${NOW}\n```\n\nДанный скрипт помещается в задачу cron с ежедневным выполнением, что позволит иметь полные резервные копии за указанное в переменной `mysql_backup_expire` количество дней.\n\n### Роль master-db\n\nВыполняет перевод slave-сервера в master. Для этого проверяется текущее состояние и, если данный сервер является репликой, то выполняется перевод в master.\n\n### Роль base-apache\n\nВ рамках данной роли выполняется установка связки Apache + PHP.\n\nПоскольку веб-приложение планируется разворачивать из Git-репозитория, то в рамках файла конфигурации Apache запрещаем доступ к каталогу `.git`:\n\n```conf\n\u003cDirectoryMatch \"^/.*/\\.git/\"\u003e\n    Order deny,allow\n    Deny from all\n\u003c/DirectoryMatch\u003e\n```\n\n### Роль web\n\nВ рамках данной роли выполняется развертывание веб-приложения с подготовкой конфигурационного файла подключения к базе данных.\n\n### Роль nginx\n\nВыполняет установку nginx и добавление ранее настроенных backend-серверов в файл конфигурации:\n\n```conf\n    upstream backend {\n        ip_hash;\n    {% for host in groups.webservers %}\n        server {{ hostvars[host].ansible_all_ipv4_addresses | ansible.netcommon.ipaddr(network) | first }}:80;\n    {% endfor %}\n    }\n```\n\nПри этом используются внутренние адреса серверов благодаря фильтру `ansible.netcommon.ipaddr(network)`.\n\nДалее выполняется запуск NGinx и прописывается сервис в firewalld для возможности доступа извне.\n\n### Роль monitoring\n\nВ рамках данной роли выполняется установка и базовая настройка Prometheus и Grafana. Установка Prometheus выполняется по той же схеме, что и Node Exporter - с помощью готового скрипта.\n\nПосле применения данной роли Grafana доступна на порту 3000 для дальнейшей настройки вручную путем добавления готовых панелей.\n\nВ дальнейшем, используя REST API Grafana, можно реализовать полностью автоматизированную настройку путем импорта готовых панелей из JSON.\n\n### Роль gluster\n\nВ рамках данной роли устаналиваются необходимые пакеты для GlusterFS, создается том с репликацией в рамках группы `gluster`. Изначально развертывание было реализовано полностью вручную для понимания процесса, после чего была выполнена миграция на использование плагина `gluster.gluster`.\n\nОсобенность ряда задач данной роли в необходимости выполнения только на одном из серверов, для этого использована опция задачи `run_once`.\n\nЧерез переменную `gluster_userdata` определяется местонахождение данных на сервера, а через `webapp_userdata` - место монтирования на клиенте. При этом если переменная webapp_userdata будет не определена, то и монтирование выполняться не будет.\n\n## Настройка серверов\n\nПосле формирования инвентаря и необходимых ролей достаточно запустить Ansible на выполнение:\n\n```bash\nansible-playbook -i hosts site.yml -u root --ask-vault-pass\n```\n\nДалее вводим пароль от защищенных значений и ожидаем завершения работы Ansible. В конечном счете имеем настроенные согласно исходной задаче сервера с развернутым веб-приложением.\n\n## Аварийное восстановление\n\nДля аварийного восстановления достаточно запустить пустой сервер с CentOS 7, указать его в файле инвентаря Ansible, после чего повторить запуск Ansible. Данный подход сработает со всеми серверами за исключением основного сервера базы данных, поспольку при обычном запуске там будет развернута чистая БД и будет нарушена репликация.\n\nВ случае восстановления основного сервера база данных самый оптимальный вариант - перевод существующего slave-сервера в master. Для этого достаточно в файле инвентаря перенести запись с адресом slave-сервера в группу `dbservers`.\n\nВ дальнейшем можно рассмотреть восстановление основного сервера баз данных из локальной резервной копии, передвая путь к ней из командной строки Ansible, загружая на удаленный сервер и копируя ее в каталог данных MariaDB.\n\n# Итоги\n\nТаким образом, на базе Ansible реализовано развертывание полноценной инфраструктуры для веб-приложения с репликацией и резервным копированием базы данных. Аварийное восстановление при этом фактически заключается в повторном запуске Ansible с указанием чистых серверов в файле инвентаря.\n\nВ рамках дальнейшей работы над проектом стоит рассмотреть:\n\n- [x] Использование Terraform для подготовки серверов (проведена первичная работа).\n- [ ] Автоматическое формирование файла инвентаря Ansible на основе состояния Terraform.\n- [ ] Оптимизацию процесса развертывания реплик базы данных, исключив загрузку резервной копии через локальный компьютер.\n- [ ] Использование сжатия и инкрементального резервного копирования базы данных.\n- [x] Использование распределенной ФС (например, GlusterFS) для хранения данных пользователей и синхронизации их между backend-серверами.\n- [ ] Развертывание основного сервера базы данных из локальной резервной копии.\n- [ ] Автоматизацию настройки Grafana, в т.ч. добавление панелей по средствам API.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapcom6-learning%2Fotus-administrator-linux-basic-project","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcapcom6-learning%2Fotus-administrator-linux-basic-project","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapcom6-learning%2Fotus-administrator-linux-basic-project/lists"}