Giter VIP home page Giter VIP logo

otus-administrator-linux-basic-project's Introduction

Проектная работа

Тема: развертывание веб-приложения на базе фреймворка CodeIgniter с балансировкой нагрузки средствами NGinx, применением стэка Apache + PHP + MariaDB, репликацией и резервным копированием базы данных и мониторингом на основе Node Exporter + Prometheus + Grafana.

Ход работы

Работа выполняется на CentOS 7 со следующим набором серверов:

  1. Frontend-сервер на базе Nginx.
  2. Backend-сервера в количестве 2 шт. на базе Apache + PHP.
  3. Сервер баз данных на основе MariaDB.
  4. Сервер репликации базы данных MariaDB с резервным копированием.
  5. Сервер мониторинга на базе Prometheus + Grafana.

Данные сервера развернуты у облачного провайдера с заранее прописанным ключом доступа по SSH для пользователя root. Для настройки серверов используется Ansible.

Для демонстрационных целей выбрано не конкретное веб-приложение, а PHP-фреймворк CodeIgniter. Такой выбор сделан из расчета, что развертывание всех приложений на данной фреймворке будет иметь сходные шаги, а конечной целью является развертывание коммерческого веб-приложения с закрытым исходным кодом на данном фреймворке.

Формирование файла инвентаря

Все сервера были сгруппированы по своему назначению и прописаны в файл hosts для дальнейшего использования с Ansible. Были выделеные следующие группы:

  • webservers - backend-сервера;
  • gluster - сервера, входящие в кластер GlusterFS;
  • dbservers - основной MySQL-сервер, было условлено, что данная группа должна содержать ровно 1 сервер для корректной настройки репликации;
  • dbslaves - реплики основного MySQL-сервера;
  • lbservers - frontend-сервер;
  • monitoring - сервер мониторинга.

Для групп dbservers и dbslaves непосредственно в файле hosts указано значение переменной server_id. Указание данной переменной в общем файле вместо использования hosts_vars позволяет иметь возможность визуального контроля уникальности используемых server_id.

Формирование ролей

Для перечисленных ранее серверов были выделены следующие роли:

  • common - общая для всех серверов роль, выполняющая базовые настройки;
  • base-apache - установка и настройка Apache + PHP;
  • base-db - установка и настройки MariaDB;
  • slave-db - действия по развертыванию реплики MySQL-сервера;
  • master-db - действия по переводу Slave в Master;
  • nginx - установка и настройка балансировщика нагрузки на базе Nginx;
  • web - развертывание веб-приложения из репозитория;
  • web-db - создание базы данных приложения;
  • monitoring - установка и настройка Prometheus + Grafana;
  • monitoring-node - установка экспортеров для Prometheus;
  • gluster - настройка томов GlusterFS и их монтирование.

Данные роли были назначены группам серверов следующим образом:

  • все сервера:
    • common;
    • monitoring-node.
  • dbservers:
    • base-db;
    • master-db;
    • web-db.
  • dbslaves:
    • base-db;
    • slave-db.
  • webservers:
    • base-apache;
    • web.
  • gluster:
    • gluster.
  • lbservers:
    • nginx.
  • monitoring:
    • monitoring.

Роль и группа gluster специально выделены отдельно несмотря на то, что на текущий момент данная группа совпадает с группой webservers с целью возможности развертывания дополнительных серверов в кластере не являющихся при этом веб-серверами. Это позволит, например, развернуть отдельный сервер для резервного копирования пользовательских данных.

Далее рассмотрены ключевые моменты отдельных ролей.

Роль common

Цель данной роли выполнить общие настройки сервера, в частности:

  • установить репозиторий epel-release;
  • разрешить неограниченный доступ к серверам в рамках виртуальной сети, которая выделена в переменную network в файле group_vars/all;
  • отключить SELinux для упрощения развертывания. Ряд ролей уже содержит применение настроек для случая включенного SELinux, но требуется дополнительная работа в данном направлении.

Роль monitoring-node

Данная роль выполняет установку на сервер Node Exporter и сопутствующие настройки:

  • создает пользователя prometheus-exporter для ограничения прав Node Exporter;
  • проверяет наличие уже установленного Node Exporter, чтобы не выполнять повторную установку;
  • при отсутствии Node Exporter на сервере выполняестя копирование инсталляционного скрипта и его запуск;
  • в конечном счете регистрируется юнит systemd и запускается сервис.

Для установки используется шаблон простого скрипта с переменной для версии Node Exporter:

#!/bin/bash

cd /tmp
# Скачаем архив с node exporter
curl -LO https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-amd64.tar.gz
# Распакуем в текущую директорию
tar xzvf node_exporter-{{ node_exporter_version }}.linux-amd64.tar.gz
# Копируем исполняемый файл в общесистемный каталог
cp node_exporter-{{ node_exporter_version }}.linux-amd64/node_exporter /usr/local/bin/

rm -rf node_exporter-{{ node_exporter_version }}.linux-amd64

Минусом такого подхода к проверки наличия Node Exporter является невозможность обновления, посколкьу задача "Check for Node Exporter binary" проверяет лишь наличие исполняемого файла, но не проверяет версию. В итоге изменение переменной с версией не приводит к обновлению Node Exporter. Это задача для дальнейшей проработки.

Роль base-db

Данная роль выполняет установку MariaDB и ее настройку, общую для основного сервера и реплики:

  • импортирует ключ и копирует настройки репозитория указанной в переменных версии MariaDB;
  • устанавливает основные пакеты MariaDB, а также библиотеку Python для работы с MySQL из Ansible;
  • создает конфигурационный файл сервера:
[mysqld]
# set server_id
server-id		        = {{ server_id }}
# optimize memory usage
{% if 'dbservers' in group_names %}
innodb_buffer_pool_size	= {{ (ansible_memtotal_mb * 0.8) | int }}M
{% else %}
innodb_buffer_pool_size	= {{ (ansible_memtotal_mb * 0.5) | int }}M
read_only               = 1
{% endif %}

# set binlog filename prefix
log_bin                 = mysql-bin
# set binlog format
binlog_format           = mixed
# set binlog expire days
expire_logs_days        = {{ mysql_binlog_expire }}
# set compression for binlog
log_bin_compress        = ON

Через переменные задается server_id и параметры двоичного журнала для работы репликации. Также задается объем выделенной оперативной памяти. Для основного сервера выделяется 80% от общего объема, а на репликах - 50%. Это обосновано тем, что на репликах помимо непосредственно работы сервера базы данных будет производится резервное копирование, потенциально с использованием сжатия, что потребует свободной оперативной памяти.

В дальнейшем при определении объема оперативнйо памяти для сервера баз данных стоит учитывать общий объем доступной памяти. Так на системах с малым объемом памяти (< 2 GB) при выделении 80% под сервер базы данных может возникнуть нехватка памяти под ОС.

В продолжение настройки выполняется еще ряд действий:

  • задаются права доступа по-умолчанию для новых файлов и каталогов баз данных путем указания в файле umask.conf. Это необходимо для корректной работы резервного копирования, поскольку по-умолчанию доступ к каталогам баз данных разрешен только пользователю mysql, а для работы резервного копирования также требуется доступ для группы mysql;
  • запускается сервис MariaDB;
  • устанавливается пароль для пользователя root и создается файл конфигурации клиента .my.cnf для системного пользователя root;
  • удаляются тестовые базы данных, анонимные пользователи и удаленный доступ к базе данных от имени пользователя root;
  • создаются пользователи для репликации и резервного копирования с необходимыми правами.

Поскольку пароли для создаваемых пользователей хранятся в переменных, то хранение их в открытом виде не рекомендуется. В связи с этим они были предварительно зашифрованы с применением ansible-vault командами вида:

ansible-vault encrypt_string --ask-vault-password '***' --name 'mysql_root_password'

Роль web-db

Данная роль выполняет развертывание базы данных приложения на основном сервере. Также создается пользователь базы данных приложения согласно соответствующим переменным.

Роль slave-db

В рамках данной роли выполняется 2 основных действия:

  • настройка репликации, если она не была настроена ранее;
  • настройка резервного копирования.

Рассмотрим данные действия подробнее.

Настройка репликации

Перед настройкой репликации проводится проверка текущего состояния репликации. Если репликация уже настроена, то данное действие пропускается. Настройка репликации вынесена в отдельный файл init_replication.yml.

В рамках инициализации репликации выполняются следующие действия:

  • путем делегации действий на основном сервере MariaDB с помощью утилиты mariabackup создается резервная копия с указанием позиции двоичного журнала;
  • данная копия передается на настраиваемую реплику. В данном случае это происходит через локальный компьютер, что, в общем случае, не эффективно, а потому является основанием для дальнейших доработок;
  • полученная резервная копия разворачивается на реплике, настраиваются права доступа к файлам баз данных;
  • запускается процесс репликации с использованием GTID, считанного из файла xtrabackup_binlog_info из состава резервной копии.

Настройка резервного копирования

Для реализации резервного копирования по расписанию создается отдельный пользователь ОС с логином backup, входящий в группу mysql для возможности доступа к файлам БД.

Непосредственно резервное копирование выполняется скриптом mysql_backup.sh, созданном на основании шаблона:

#!/bin/sh

NOW=$(date +"%Y-%m-%d")

find {{ mysql_backup_location }} -maxdepth 1 -ctime +{{ mysql_backup_expire }} -type d -exec rm -rf {} \; \
    && mkdir -p {{ mysql_backup_location }}/${NOW} \
    && mariabackup --backup --target-dir={{mysql_backup_location}}/${NOW} \
    && mariabackup --prepare --target-dir={{mysql_backup_location}}/${NOW}

Данный скрипт помещается в задачу cron с ежедневным выполнением, что позволит иметь полные резервные копии за указанное в переменной mysql_backup_expire количество дней.

Роль master-db

Выполняет перевод slave-сервера в master. Для этого проверяется текущее состояние и, если данный сервер является репликой, то выполняется перевод в master.

Роль base-apache

В рамках данной роли выполняется установка связки Apache + PHP.

Поскольку веб-приложение планируется разворачивать из Git-репозитория, то в рамках файла конфигурации Apache запрещаем доступ к каталогу .git:

<DirectoryMatch "^/.*/\.git/">
    Order deny,allow
    Deny from all
</DirectoryMatch>

Роль web

В рамках данной роли выполняется развертывание веб-приложения с подготовкой конфигурационного файла подключения к базе данных.

Роль nginx

Выполняет установку nginx и добавление ранее настроенных backend-серверов в файл конфигурации:

    upstream backend {
        ip_hash;
    {% for host in groups.webservers %}
        server {{ hostvars[host].ansible_all_ipv4_addresses | ansible.netcommon.ipaddr(network) | first }}:80;
    {% endfor %}
    }

При этом используются внутренние адреса серверов благодаря фильтру ansible.netcommon.ipaddr(network).

Далее выполняется запуск NGinx и прописывается сервис в firewalld для возможности доступа извне.

Роль monitoring

В рамках данной роли выполняется установка и базовая настройка Prometheus и Grafana. Установка Prometheus выполняется по той же схеме, что и Node Exporter - с помощью готового скрипта.

После применения данной роли Grafana доступна на порту 3000 для дальнейшей настройки вручную путем добавления готовых панелей.

В дальнейшем, используя REST API Grafana, можно реализовать полностью автоматизированную настройку путем импорта готовых панелей из JSON.

Роль gluster

В рамках данной роли устаналиваются необходимые пакеты для GlusterFS, создается том с репликацией в рамках группы gluster. Изначально развертывание было реализовано полностью вручную для понимания процесса, после чего была выполнена миграция на использование плагина gluster.gluster.

Особенность ряда задач данной роли в необходимости выполнения только на одном из серверов, для этого использована опция задачи run_once.

Через переменную gluster_userdata определяется местонахождение данных на сервера, а через webapp_userdata - место монтирования на клиенте. При этом если переменная webapp_userdata будет не определена, то и монтирование выполняться не будет.

Настройка серверов

После формирования инвентаря и необходимых ролей достаточно запустить Ansible на выполнение:

ansible-playbook -i hosts site.yml -u root --ask-vault-pass

Далее вводим пароль от защищенных значений и ожидаем завершения работы Ansible. В конечном счете имеем настроенные согласно исходной задаче сервера с развернутым веб-приложением.

Аварийное восстановление

Для аварийного восстановления достаточно запустить пустой сервер с CentOS 7, указать его в файле инвентаря Ansible, после чего повторить запуск Ansible. Данный подход сработает со всеми серверами за исключением основного сервера базы данных, поспольку при обычном запуске там будет развернута чистая БД и будет нарушена репликация.

В случае восстановления основного сервера база данных самый оптимальный вариант - перевод существующего slave-сервера в master. Для этого достаточно в файле инвентаря перенести запись с адресом slave-сервера в группу dbservers.

В дальнейшем можно рассмотреть восстановление основного сервера баз данных из локальной резервной копии, передвая путь к ней из командной строки Ansible, загружая на удаленный сервер и копируя ее в каталог данных MariaDB.

Итоги

Таким образом, на базе Ansible реализовано развертывание полноценной инфраструктуры для веб-приложения с репликацией и резервным копированием базы данных. Аварийное восстановление при этом фактически заключается в повторном запуске Ansible с указанием чистых серверов в файле инвентаря.

В рамках дальнейшей работы над проектом стоит рассмотреть:

  • Использование Terraform для подготовки серверов (проведена первичная работа).
  • Автоматическое формирование файла инвентаря Ansible на основе состояния Terraform.
  • Оптимизацию процесса развертывания реплик базы данных, исключив загрузку резервной копии через локальный компьютер.
  • Использование сжатия и инкрементального резервного копирования базы данных.
  • Использование распределенной ФС (например, GlusterFS) для хранения данных пользователей и синхронизации их между backend-серверами.
  • Развертывание основного сервера базы данных из локальной резервной копии.
  • Автоматизацию настройки Grafana, в т.ч. добавление панелей по средствам API.

otus-administrator-linux-basic-project's People

Contributors

capcom6 avatar

Watchers

 avatar

Forkers

vladik1974

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.