- PVSM.RU - https://www.pvsm.ru -
Сегодня мы поговорим о том, что такое SCM и расскажем несколько историй, через призму которых рассмотрим Ansible, SaltStack, Chef и Puppet, выбрав лучший вариант для конкретной задачи.
В основе материала — расшифровка доклада Андрея Филатова [1], ведущего системного инженера компании EPAM Systems, c нашей октябрьской конференции DevOops 2017.
Что же такое SCM? В первую очередь это штука, которая позволяет нашу инфраструктуру из состояния A при помощи выполнения какого-то кода привести к состоянию Б. Многие разработчики, которые не являются на практике DevOps инженерами, думают, что каким-то «автомагическим» способом что-то происходит на инфраструктуре.
«Автомагический» способ нам реализует SCM (System Configuration Management). Для чего это нужно? В первую очередь для того, чтобы строить повторяемые и консистентные инфраструктуры. SCM хорошо расширяет CI/CD-процессы. Так как это код, его можно хранить в любой системе контроля версий: Git, Mercurial. Его достаточно просто развивать и поддерживать.
Финальное — это замкнутый цикл автоматизации: все можно делать в автоматическом режиме, от создания инфраструктуры до ее развертывания и deployment-а кода.
Рассмотрим наших претендентов. Первый — Ansible. Имеет безагентную архитектуру, если мы говорим об open source-версии, написан на Python, имеет Yaml-подобный DSL, легко расширяемый за счет модулей, написанных на Python, очень простой и легковесный. Ansible имеет самый низкий порог вхождения — вы можете научить кого угодно.
Есть опыт, когда человек, не зная Python, не зная ничего о SCM, вошел в Ansible буквально за два дня и уже начал что-то делать.
Ниже пример ChatOps: нотификатор в Slack. Код на Ansible, кто видел Yaml — ничего нового.
- block:
- name: "SlackNotify : Deploy Start"
local_action:
module: slack
token: "{{ slack_url }}"
attachments:
- title: "Deploy to {{ inventory_hostname }} has been Started"
text: "<!here> :point_up_2:"
color: "#551a8b"
- include: configure.yml
tags:
- configure
- include: remote-fetch.yml
tags:
- remote
- include: assets.yml
Chef — это клиент-серверная архитектура, есть Chef-сервер и Chef-клиент. Конфигурация основана на поиске, написан на Ruby, имеет Ruby DSL. Соответственно, внутри своих cookbook-ов и рецептов вы можете использовать всю мощь Ruby, но я не советую этого делать. У Chef огромное комьюнити и самый большой набор инструментов среди всех SСM. Вот так выглядит код на Chef, это разворачивание Jetty.
#
# Cookbook Name:: dg-app-edl
# Recipe::fe
#
node.normal[:jetty][:home] = "/usr/share/jetty"
node.normal[:jetty][:group] = "deploy"
include_recipe "dg-auth::deploy"
include_recipe "newrelic::repository"
include_recipe "newrelic::server-monitor"
include_recipe "dg-jetty::jetty9"
include_recipe "newrelic::java-agent"
directory "edl" do
action :create
owner
group "deploy"
mode "0775"
path "/usr/share/where/edl"
recursive true
end
SaltStack имеет как безагентную архитектуру, которая работает в push-режиме при помощи Salt-SSH, так и клиент-серверную архитектуру, когда есть Salt-master и Salt-minion. Упор сделан на автоматизацию в реальном времени, имеет из коробки параллельное исполнение всех процессов и написан на Python. Тоже Yaml-подобный язык, код очень похож на Ansible.
#ntp-packages:
pkg.installed:
- pkgs:
- ntp
- ntpdate
#/etc/ntp.conf:
file:
- managed
- source: salt://common/ntpd/ntp.conf
- template: jinja
- mode: 644
#/etc/sysconfig/ntpd:
file:
- managed
- source: salt://common/ntpd/ntpd
- template: jinja
- mode: 644
#ntp-service:
service.running:
- name: ntpd
Последний из наших претендентов — Puppet. Тоже имеет клиент-серверную архитектуру, как Chef, конфигурация основана не на поиске, а на «фактах», которые приходят с Puppet-master-а, написан на Ruby, имеет Ruby-подобный DSL. Но ребята из Puppet не разрешают использовать в своих манифестах чистый код Ruby. Это и плюс, и минус. Вот так выглядит код манифеста на Puppet:
class { 'mysql::server' :
root_password => 'password'
}
mysql::db{ ['test', 'test2', 'test3']:
ensure => present,
charset => 'utf8',
require => Class['mysql::server'],
}
mysql::db{ 'test4':
ensure => present,
charset => 'latin1',
}
mysql::db{ 'test5':
ensure => present,
charset => 'binary',
collate => 'binary',
}
В первую очередь я хотел бы поделиться проектом, который был написан на SaltStack. Это наш предыдущий проект и самая свежая боль, а свежая боль всегда самая больная. Наш заказчик занимается хранением данных — это производство железных серверов для хранения данных на GPFS, GlusterFS, но сборки кастомные. Он пришел к нам со следующими задачами:
У заказчика было несколько требований. В первую очередь, у него огромное количество Python-экспертизы, по факту только C и Python-разработчики. Заказчик сразу сказал: «Мы хотим SaltStack», не оставив выбора.
С чем мы столкнулись? У заказчика в инсталляции есть несколько продуктов, все должны быть c Salt-Master’ами. Но мы столкнулись с проблемой масштабирования Multi-Master-конфигурации. К примеру, у нас в NODЕ Info (состояние конкретного сервера) выбиралось при двухмастерной конфигурации миллисекунды, при трех — уже секунды, а при пяти мы ни разу не дождались завершения операции. MultiMaster хорошая фишка, но масштабируется плохо.
Вторая проблема, с которой мы столкнулись — командная работа: в SaltStack есть Runner и Module. Module — расширение, которое выполняется на Salt Minion, на стороне машины. Runner выполняется на стороне сервера. У нас очень часто возникали баталии: что делать Runner, и что делать Modules.
Затем столкнулись с небольшим сюрпризом от сache.mine:
ime = ImeActions()
id = __grains__['id']
if id == ime.master_id:
ret = __salt__['mine.get'](id, 'ime_actions.make_bfs_uuid')
ime_dict = ret.get(id, None)
if not ime_dict:
try:
result = __salt__['mine.send']('ime_actions.make_bfs_uuid')
except Exeption, e:
log.error("Failed to generate uuid: {0}.".format(str(e)))
result = False
else:
У нас есть утилита, которая написана на C. Мы ее запускаем, она генерирует случайный ID. Он должен быть уникален среди всех участников кластера, соответственно, нам это нужно делать один раз на мастере, и дальше распространять среди машин. Мы для этого использовали cache.mine. Как оказалось, он не переживает перезагрузки.
«Race condition». Параллелизация — хорошо, но в базовой конфигурации state.orchestrate приходит в состояние state.sls is running, если происходят длительные процессы. По таймауту он считает, что State уже выполнился, хотя тот еще выполняется, и пытается запустить следующий. Возникает ошибка. И эта проблема пока ещё не исправлена.
Можно посмотреть на GitHub [2].
Что мы могли использовать, кроме SaltStack?
Заказчик пришел с задачей консолидировать все ресурсы в одном облаке — это был Openstack. До этого все было разбросано: что-то на Rackspace Cloud, что-то на выделенных серверах или своих приватных датацентрах.
Они хотели полностью динамическое управление ресурсами, а также, чтобы их приложения в случае необходимости могли добавить себе мощностей. То есть нужна полная динамическая инфраструктура и полностью динамическое окружение как вверх, так и вниз.
Для того чтобы правильно построить процесс CD, нужна полностью автоматизированная среда. Мы создали для них SDLC — Software Development Lifecycle, и применили его, в том числе, для SCM. У них проходят интеграционные тесты не только приложений, но и инфраструктуры.
Соответственно, когда у нас идет что-то не так, мы должны, как ребята из Netflix, уметь убивать дефективные ресурсы и на их место восстанавливать свежие и гарантированно рабочие.
С какими проблемами мы столкнулись:
Но некоторые операции нужно делать на всем окружении. Соответственно, поиск запускался один раз в самом начале, результат сохранялся в атрибуте, и с помощью Ruby фильтровали результаты: парсили нужные нам кусочки и делали, что было нужно.
if !Chef::Config[:solo]
search(:node, "fqdn:*metro-#{node[:env]}-mongodb*").each do |mongo|
@mongodbs << mongo.fqdn
end
else
@mongodbs = ["lvs-metro-#{node[:env]}-mongodb3001.qa.example.com"]
end
Итог: используйте нейминг-конвенции, запускайте поиск один раз, используйте Ruby для фильтрации нужных результатов.
Что мы можем использовать вместо Chef?
За год-полтора до появления AWS OpsWorks мы хотели создать расширенный Amazon CloudFormation, интегрировав Chef, чтобы ресурсы не только разворачивались, но и настраивались.
Вторая глобальная задача — создание сервис-каталога, чтобы заказчики и пользователи могли при помощи CLI развернуть полностью готовый к использованию например LAMP-стек.
Мы выбрали Chef, но проект должен был поддерживать разные SCM. Мы стартовали со встроенным Chef-Server’ом, а также пользователи могли использовать собственный Chef-Server, который
Для реализации CloudFormation + OpsWork можно использовать любой SCM, подходят все. Для создания каталога — все, кроме SaltStack, хорошо с этим справятся. У SaltStack есть нюансы: найти специалиста, который хорошо знает SaltStack и может создавать сервис и наполнять каталог, крайне сложно.
Это статистика популярности SCM внутри EPAM. SaltStack очень далеко позади. На первом месте Ansible, он самый простой и с низким порогом вхождения. Когда мы пытаемся найти кого-то на рынке со знанием SCM — рынок выглядит примерно так же.
Советы, которые я могу дать при работе с Ansible:
- name: project apt dependencies installed
apt:
name: "{{ item }}"
become: yes
with_items:
- build-essential
- acl
- git
- curl
- gnupg2
- libpcre3-dev
- python-apt
- python-pycurl
- python-boto
- imagemagick
- libmysqlclient-dev # needed for data import
В данном примере мы устанавливаем пакеты, эту схему можно использовать для создания пользователей и тому подобных операций.
- name: create postgresql database
postgresql_db:
name: "{{ database_name }}"
login_host: "{{ database_host }}"
login_user: "{{ database_master_user }}"
login_password: "{{ database_master_password }}"
encoding: "UTF-8"
lc_collate: "en_US.UTF-8"
lc_ctype: "en_US.UTF-8"
template: "template0"
state: present
delegate_to: "{{ groups.pg_servers|random}}"
Это кусок по созданию баз данных. Без последней строчки операция выполнилась бы несколько раз и свалилась на второй попытке создать ту же самую базу данных.
Лично для меня Ansible — фаворит. SaltStack очень хороший, очень гибкий, но требует знания Python, без них SaltStack лучше не использовать. Chef — универсальная серебряная пуля для любых задач и любых масштабов, но требует больших знаний, чем Ansible. А кто использует Puppet — я не знаю. В принципе, он очень похож на Chef, но со своими нюансами.
Минутка рекламы. Если вам понравился этот доклад с конференции DevOops — обратите внимание, что 14 октября в Санкт-Петербурге пройдет новый DevOops 2018 [4], в его программе тоже будет много интересного. На сайте уже есть первые спикеры и доклады.
Автор: ValeriaKhokha
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/konferentsii/285752
Ссылки в тексте:
[1] доклада Андрея Филатова: http://2017.devoops.ru/2017/spb/talks/3qpsghlqlwu6u64c8uqmo4/
[2] посмотреть на GitHub: https://github.com/saltstack/salt/issues/18564
[3] хостится: https://www.reg.ru/?rlink=reflink-717
[4] DevOops 2018: https://devoops.ru/
[5] Источник: https://habr.com/post/416763/?utm_source=habrahabr&utm_medium=rss&utm_campaign=416763
Нажмите здесь для печати.