Как мы построили отказоустойчивую open-source-инфраструктуру для управления пользовательскими Linux-устройствами

от автора

Всем привет! Меня зовут Владислав, я руководитель направления развития пользовательских Linux-систем в Т-Банке. Мы работаем над проектом Linux Desktop. 

Проект зародился во времена блокировки иностранного софта. Нам нужен был опенсорсный продукт, который никуда не исчезнет и на закроется. Но прежде чем развивать Linux Desktop, в компании нужно было выбрать систему управления конфигурациями, которая сможет выдержать больше 15 000 хостов. А еще построить инфраструктуру, которая будет отказоустойчивой и не рассыпаться, если один из ЦОДов упадет.

Расскажу, как мы создали инфраструктуру, которая контролирует системы безопасности, магазин приложений, конфигурации ядра и многое другое. А еще такая инфраструктура — запасной аэродром, если вдруг придется отказаться от западного вендора.

Требования к новой системе

Основная идея Linux Desktop в том, чтобы создать свой образ Linux на основе open-source-продуктов, который будет user-friendly для разработчиков и операторов колл-центра и при этом будет соответствовать строгим требованиям безопасности банка.

Мы размышляли, как управлять всем этим парком. Первое, что пришло в голову, — стандартные решения, такие как Ansible, Puppet, SaltStack, Chef. Вариантов много, и каждый из них по своему хорош, но сначала нужно определиться с нашими требованиями.

Мы старались сформулировать требования по аналогии с другими большими устоявшимися MDM-системами: SCCM, Jamf, Intune. Нам нужны:

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

  2. Масштабируемость и отказоустойчивость — эти параметры обязательны.

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

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

  5. Большое сообщество, которое следит за обновлениями и безопасностью.
    Это плюс для любой системы: быстрый выпуск фиксов багов, много разных модулей для удобства управления.

  6. И нужно выбирать то, что нравится, потому что потом самим же с этим работать.

Выбор пал на Puppet, потому что он использует pull-модель и у него свой центр сертификации. Масштабируемость инфраструктуры может быть как горизонтальная, так и вертикальная, что очень удобно. А если рядом установить Foreman, получится полноценная система управления с графическим интерфейсом, и все это в последствии можно кастомизировать под себя.

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

Логичный вопрос: зачем выполнять такой расчет, если Puppet уже все посчитал сам? Доверяй, но проверяй. Тем более что не совсем понятно, как он поведет себя в нашей инфраструктуре.

Вот что получилось в наших расчетах. 

Конфигурации серверов

hostname

cpu

ram

Назначение сервера 

puppet-master.domain.ru

4

8 Gb

Puppet master

puppet-server-01.domain.ru

4

8 Gb

Puppet server

Тестирование нагрузки. Во время тестирования онлайн было 50—80 хостов, и всю нагрузку мы распределили на два сервера.

puppet-server-01.domain.ru: RAM 8 ГБ VCPUs 4 

puppet-server-01 memory

puppet-server-01 memory
puppet-server-01 CPU

puppet-server-01 CPU

puppet-master.domain.ru: RAM 8 ГБ VCPUs 4

puppet-master memory

puppet-master memory
puppet-master CPU

puppet-master CPU

Возьмем среднюю нагрузку на сервер в 75 хостов. 

Посчитаем CPU

avg CPU utilization

puppet-master.domain.ru(1,86) + puppet-server-01.domain.ru(0,92) / 2 = 1,39% 

Получается, что средняя нагрузка на процессор составляет 1,39% от 4 VCPUs при онлайне в 37 хостов.

Считаем половину от 75, потому что происходит балансировка между нодами. 

На 1000 хостов потребление будет примерно 1,5 VCPUs (все расчеты производятся с учетом уже написанных манифестов, модулей и фактов).

Из официальной документации видно, что минимальные требования — от 2 до 4 VCPUs на 1000 хостов.

Берем среднее значение 3 VCPUs на 1000 хостов.

Потом считаем memory

avg Memory utilization

puppet-master.domain.ru(56,21) + puppet-server-01.domain.ru(38,99) / 2 = 47,6%

Получается, что средняя нагрузка на оперативную память составляет 47,6% от 8 Gb при онлайне в 37 хостов.

Считаем половину от 75, потому что происходит балансировка между нодами. 

С учетом того, что JAVA воркеры настроены стандартно, а пополнение хостов происходило постепенно, можно считать расчеты из официальной документации за основу.

На 1000 хостов потребление будет примерно 4—6 Gb. Все расчеты провели с учетом уже написанных манифестов, модулей и фактов.

Получаем, что конфигурация инфраструктуры выглядит так: 

hostname

cpu

ram

Назначение сервера 

puppet-server-01.domain.ru

4

6 Gb

Puppet server

foreman.domain.ru

4

6 Gb

Foreman

puppet-master.domain.ru

4

6 Gb

Puppet master

puppet-proxy-01.domain.ru

4

4 Gb

Proxy

puppet-ca.domain.ru

4

6 Gb

Puppet CA

puppet-server-02.domain.ru

4

6 Gb

Puppet server

puppet-proxy-02.domain.ru

4

4 Gb

Proxy 

Из расчетов видно, что нашей инфраструктуры хватит на 3000 хостов, и мы вынесли отдельно центр сертификации, чтобы не нагружать серверы. Правило хорошего тона — держать центр сертификации отдельно. Proxy-серверы мы настроили так, чтобы они распределяли запросы на подпись сертификатов и запросы на получение конфигураций.

После нехитрых манипуляций получаем вот такую схему:

Схема инфраструктуры

Схема инфраструктуры

Схема инфраструктуры

Ну а теперь, как говорится, следите за руками!

Агент обращается к кластеру Nginx, который выполняет балансировку на уровне L4 и просто перенаправляет запросы на первый или второй прокси-сервер. Прокси располагаются в разных ЦОДах для повышения отказоустойчивости, и мы настраиваем их на распределение запросов в CA и к Puppet-серверу.

CA мы вынесли и создали три независимых друг от друга сервера. При падении любого сервера агенты все равно будут обращаться к другим серверам и получать конфигурацию. Ну а саму конфигурацию мы, как положено, распространяем с помощью Git.

Foreman нужен для удобного управления системами, а для повышения отказоустойчивости мы еще развернули кластер баз данных.

Как все выглядело на практике

Расскажу, как сделать все так красиво. У нас уже был git, мы настроили ci/cd так, чтобы ранер собирал наши манифесты с git и пушил их на все puppet-серверы. При этом мы использовали ansible-контейнер.

Развернули все на Ubuntu 20.04 и настроили /etc/hosts на серверах.  

Начали с puppet-серверов, центра сертификации и foreman — установили puppet на сервера:

  • puppet-master.domain.ru

  • puppet-server-01.domain.ru 

  • puppet-server-02.domain.ru

  • puppet-ca.domain.ru

  • foreman.domain.ru

sudo apt-get -y install ca-certificates cd /tmp && wget https://apt.puppet.com/puppet7-release-focal.deb sudo apt-get install /tmp/puppet7-release-focal.deb sudo apt-get update sudo apt-get install puppetserver

Установка Puppet CA

1. Настраиваем puppet.conf. Редактируем /etc/puppetlabs/puppet/puppet.conf, указываем dns мастера и центра сертификации:

[main] ca_server = puppet-ca.domain.ru certname = puppet-ca.domain.ru server = puppet-master.domain.ru

2. Включаем центр сертификации. Редактируем /etc/puppetlabs/puppetserver/services.d/ca.cfg: 

# To enable the CA service, leave the following line uncommented puppetlabs.services.ca.certificate-authority-service/certificate-authority-service # To disable the CA service, comment out the above line and uncomment the line below #puppetlabs.services.ca.certificate-authority-disabled-service/certificate-authority-disabled-service puppetlabs.trapperkeeper.services.watcher.filesystem-watch-service/filesystem-watch-service

3. Разрешаем подписывать сертификаты master-server:

cp /etc/puppetlabs/puppetserver/conf.d/ca.conf /etc/puppetlabs/puppetserver/conf.d/ca.conf.backup

Редактируем /etc/puppetlabs/puppetserver/conf.d/ca.conf. Такая конфигурация нужна для подписи сертификатов с альтернативными dns-именами. После подписания нод ее нужно вернуть в исходное состояние:

certificate-authority: {     # allow CA to sign certificate requests that have subject alternative names.      allow-subject-alt-names: true       # allow CA to sign certificate requests that have authorization extensions.      allow-authorization-extensions: true       # enable the separate CRL for Puppet infrastructure nodes     # enable-infra-crl: false }

4. Запускаем puppetserver:

sudo systemctl start puppetserver.service

Настройка puppet-master nod

1. Выключаем центр сертификации. Чтобы сервер не участвовал в управлении сертификатами, его нужно отключить.

Редактируем /etc/puppetlabs/puppetserver/services.d/ca.cfg:

# To enable the CA service, leave the following line uncommented #puppetlabs.services.ca.certificate-authority-service/certificate-authority-service # To disable the CA service, comment out the above line and uncomment the line below puppetlabs.services.ca.certificate-authority-disabled-service/certificate-authority-disabled-service puppetlabs.trapperkeeper.services.watcher.filesystem-watch-service/filesystem-watch-service

2. Настройка puppet.conf. Редактируем /etc/puppetlabs/puppet/puppet.conf. Тут нужно чуть-чуть пояснить: чтобы клиент ходил на балансировщик, мы добавили dns балансировщика тоже в dns_alt_names, просто если puppet agent не увидит dns балансировщика в сертификате, то он не пойдет к нему.

[main] dns_alt_names = puppet-master.domain.ru,puppet.domain.ru ca_server = puppet-ca.domain.ru certname = puppet-master.domain.ru server = puppet-master.domain.ru

3. Настройка puppet-nod. Привожу настройку сразу двух нод, потому что они идентичны.

Выключаем центр сертификации. Сервер нужно отключить, чтобы он не участвовал в управлении сертификатами. 

Редактируем /etc/puppetlabs/puppetserver/services.d/ca.cfg:

# To enable the CA service, leave the following line uncommented #puppetlabs.services.ca.certificate-authority-service/certificate-authority-service # To disable the CA service, comment out the above line and uncomment the line below puppetlabs.services.ca.certificate-authority-disabled-service/certificate-authority-disabled-service puppetlabs.trapperkeeper.services.watcher.filesystem-watch-service/filesystem-watch-service

Настройка puppet.conf. Редактируем /etc/puppetlabs/puppet/puppet.conf. То же самое прописываем на второй ноде, только:

[main] dns_alt_names = puppet-master.domain.ru,puppet.domain.ru ca_server = puppet-ca.domain.ru certname = puppet-server-01.domain.ru server = puppet-master.domain.ru

4. Получение сертификатов. Запускаем на нодах puppet-master.domain.ru puppet-server-01.domain.ru puppet-server-02.domain.ru

sudo /opt/puppetlabs/bin/puppet agent -t --waitforcert 10

На ноде СА подписываем все сертификаты puppet-ca.domain.ru

#Проверяем, что сертификаты  /opt/puppetlabs/bin/puppetserver ca sign --all  #Подписываем все сертификаты /opt/puppetlabs/bin/puppetserver ca list --all

Теперь нужно отключить подпись сертификатов с dns_alt_names на puppet-ca.domain.ru

sudo systemctl restart puppetserver.service

Настройка Proxy Nods

Устанавливаем nginx:

sudo apt install nginx sudo nano /etc/nginx/nginx.conf
worker_rlimit_nofile 50000; user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf;    events {         worker_connections 10000; }    http {         sendfile on;         tcp_nopush on;         tcp_nodelay on;         keepalive_timeout 65;         types_hash_max_size 2048;         include /etc/nginx/mime.types;         default_type application/octet-stream;         ssl_protocols SSLv2 TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE         ssl_prefer_server_ciphers on;         access_log /var/log/nginx/access.log;         error_log /var/log/nginx/error.log;         include /etc/nginx/conf.d/*.conf;         include /etc/nginx/sites-enabled/*;              log_format pptsrv '[$time_local]-- ip_client:$remote_addr -> ip_server:$upstream_addr status:$status bytes_client:$bytes_sent';         log_format pptca '[$time_local]-- ip_client:$remote_addr -> ip_server:$upstream_addr status:$status bytes_client:$bytes_sent';          access_log /var/log/nginx/pptsrv-access.log pptsrv;         access_log /var/log/nginx/pptsrv-access.log pptca;          upstream pptsrv {           zone pptsrv 4M;           least_conn;           server ip-server:8140; #puppet-master.domain.ru           server ip-server:8140 weight=5; #puppet-server-01.domain.ru           server ip-server:8140 weight=5; #puppet-server-02.domain.ru         }          upstream pptca {           server ip-server:8140; #puppet-ca.domain.ru         }        server {           listen 8140 ssl proxy_protocol;           server_name puppet-proxy-01.domain.ru           ssl_session_timeout 5m;           ssl_certificate         /etc/puppetlabs/puppet/ssl/certs/puppet-proxy-01.domain.ru.pem;           ssl_certificate_key     /etc/puppetlabs/puppet/ssl/private_keys/puppet-proxy-01.domain.ru.pem;           ssl_client_certificate  /etc/puppetlabs/puppet/ssl/certs/ca.pem;           ssl_verify_client   optional;           ssl_crl                 /etc/puppetlabs/puppet/ssl/crl.pem;          location /puppet/ {           proxy_pass          https://pptsrv;           proxy_redirect off;           proxy_ssl_server_name on;           proxy_ssl_verify on;           proxy_ssl_name puppet.domain.ru; #Тут указываем имя балансировщика. Это нужно для того, чтобы агент понимал, как ему ходить            proxy_ssl_crl /etc/puppetlabs/puppet/ssl/crl.pem;           proxy_ssl_trusted_certificate /etc/puppetlabs/puppet/ssl/certs/ca.pem;           proxy_ssl_certificate /etc/puppetlabs/puppet/ssl/certs/puppet-proxy-01.domain.ru.pem;           proxy_ssl_certificate_key /etc/puppetlabs/puppet/ssl/private_keys/puppet-proxy-01.domain.ru.pem;           proxy_set_headerHost         $http_host;           proxy_set_headerX-Real-IP    $remote_addr;           proxy_set_headerX-Forwarded-For  $proxy_add_x_forwarded_for;         }          location  /puppet-ca/ {           proxy_pass          https://pptca;           proxy_redirect  off;           proxy_set_headerHost         $http_host;           proxy_set_headerX-Real-IP    $remote_addr;           proxy_set_headerX-Forwarded-For  $proxy_add_x_forwarded_for;           proxy_set_headerX-Client-Verify  $ssl_client_verify;           proxy_set_headerX-Client-DN  $ssl_client_s_dn;           proxy_set_headerX-SSL-Subject$ssl_client_s_dn;           proxy_set_headerX-SSL-Issuer $ssl_client_i_dn;           proxy_read_timeout  65;         }     } }

Мы добавили метод балансировки и вес для серверов. Чтобы проверить конфиг, можно использовать команду nginx -t, а чтобы применить конфиг без перезагрузки службы и сервера, используем команду nginx -s reload.

Настройка Foreman

Перед настройкой Foreman советую настроить базу данных, но об этом тут рассказывать не буду. Идем дальше по настройке. 

Устанавливаем репозитории и установщик:

sudo wget https://deb.theforeman.org/foreman.asc -O /etc/apt/trusted.gpg.d/foreman.asc echo "deb http://deb.theforeman.org/ focal 3.10" | sudo tee /etc/apt/sources.list.d/foreman.list echo "deb http://deb.theforeman.org/ plugins 3.10" | sudo tee -a /etc/apt/sources.list.d/foreman.list sudo apt-get update && sudo apt-get -y install foreman-installer puppet-agent

Настраиваем Noda Foreman. Устанавливаем puppet-agent.
Редактируем конфигурацию /etc/puppetlabs/puppet/puppet.conf:

[main] ca_server = puppet-ca.domain.ru certname = foreman.domain.ru server = puppet-master.domain.ru

Установка Foreman отдельно от puppet servers:

foreman-installer \   --puppet-server=false \   --foreman-proxy-puppet=false \   --foreman-proxy-puppetca=false \   --foreman-db-manage=false \   --foreman-db-host=name host DB \   --foreman-db-database=name DB \   --foreman-db-username=name user DB \   --foreman-db-password=pass user DB

Для настройки базы данных:

foreman-rake db:migrate foreman-rake db:seed foreman-rake apipie:cache:index

Noda Puppet-server. После установки Foreman nod нужно запомнить для подключения puppet-server:

-foreman-proxy-oauth-consumer-key -foreman-proxy-oauth-consumer-secret

Команда выполняется на foreman nod, чтобы получись oauth для получения foreman-proxy-oauth-consumer-key и foreman-proxy-oauth-consumer-secret: 

sudo cat /etc/foreman-installer/scenarios.d/foreman-answers.yaml | grep oauth_consumer

Дальше запускаем установку на Puppet-server:

foreman-installer \   --no-enable-foreman \   --no-enable-foreman-plugin-puppet \   --no-enable-foreman-cli \   --no-enable-foreman-cli-puppet \   --enable-puppet \   --puppet-server-ca=false \   --puppet-server-foreman-url=https://foreman.domain.ru \   --enable-foreman-proxy \   --foreman-proxy-puppetca=false \   --foreman-proxy-foreman-base-url=https://foreman.domain.ru \   --foreman-proxy-trusted-hosts=foreman.domain.ru \   --foreman-proxy-oauth-consumer-key=***********************\   --foreman-proxy-oauth-consumer-secret=********************

Обратите внимание, что эта нода ставится без СА

По такой схеме настраивается master и slave server.

6.4 Noda Puppet-CA-server.

Устанавливаем прокси с СА:

foreman-installer \   --no-enable-foreman \   --no-enable-foreman-plugin-puppet \   --no-enable-foreman-cli \   --no-enable-foreman-cli-puppet \   --enable-puppet \   --puppet-server-ca=true \   --puppet-server-foreman-url=https://foreman.domain.ru \   --enable-foreman-proxy \   --foreman-proxy-puppetca=true \   --foreman-proxy-foreman-base-url=https://foreman.domain.ru \   --foreman-proxy-trusted-hosts=foreman.domain.ru \   --foreman-proxy-oauth-consumer-key=**************************\   --foreman-proxy-oauth-consumer-secret=**************************

После установки получите логин и пароль для входа, переходим на https://foreman.domain.ru, логинимся и получаем готовый сервис для работы.

А в итоге

Мы получили отказоустойчивую инфраструктуру, готовую выдержать до 3000 агентов с возможностью масштабирования. Это могут быть как серверы, так и мобильные рабочие станции, контроль распространения манифестов через git, удобное управление парком через Foreman, полный функционал puppet с управлением сертификатами, гибким написанием манифестов и множеством модулей от комьюнити.

P.S.

Кстати, puppet может управлять не только Linux, но и Windows-системами )


ссылка на оригинал статьи https://habr.com/ru/articles/865328/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *