Upload
alexey-remnev
View
65
Download
1
Embed Size (px)
Citation preview
Ansibleв мире меняющихся требований
Малиновский Дмитрий
Проект
↳ Высоконагруженная RTB-система
↳ Appnode - Java, Glassfish
↳ DB - Aerospike
↳ Baremetal серверы
↳ Удаленная команда сисадминов
↳ production: 5 Appnode + 1 Aerospike, ~50k rps
↪ integration
↳ Деплой одного adserver > 30 минут
↪ Каждый раз все зависимости скачивались заново↪ копировались на все машины↪ Ansible использовался только как обертка над ssh
↳ Деплой сложен, сборка tar.gz со всеми зависимостями (java, glassfish,…)
↳ Тяжело менять/добавлять компоненты деплоя
Что было
↳ production: 2 кластера из 5 Appnode + 1 Aerospike, ~125k rps
↪ integration↪ qa↪ performance
↳ Деплой одного adserver < 2 минут
↳ Деплой с помощью RPM пакетов
↳ Очень просто адаптировать деплой
Что стало?
↳ Частые изменения окружений:↪ смена ip, hostname↪ новые окружения: perf, stg, qa, …
↳ Рефакторинг:↪ file-based configuration -> zookeeper↪ Glassfish -> netty
↳ Удаленная команда с доступом на prod↳ Бизнес-цели:
↪ интеграция с новыми партнерами↪ zero-downtime deployment
Проблемы
Ansibleto the rescue
or not
Что такое Ansible?
↳ agentless cm+orchestration+deployment tool
↪ python↪ ssh↪ ***magic***
↳ Easy to start
↳ Hard to master
↳ bit.ly/ansiblestart
Установка
На управляющем хосте$ pip install ansible
На управляемые хосты ничего устанавливать не надо!
bit.ly/ansiblebest
Задание списка управляемых хостов
↳ Текстовый файл (inventory)↳ Скрипт
↪ Cobbler↪ Digital Ocean↪ EC2↪ OpenStack↪ Vagrant↪ многие другие
bit.ly/ansiblebest
Inventory
[appnode]
host1
host2 ansible_ssh_port=1234
[db]
host3
Inventory-файл по-умолчанию: /etc/ansible/hostsДругие inventory-файлы можно указывать с помощью$ANSIBLE_HOSTS и опции -i
bit.ly/ansiblebest
Variables[appnode]
host1 timeout=50
host2 ansible_ssh_port=1234
[appnode:vars]
timeout = 1000
bit.ly/ansiblebest
Variablesgroup_vars/main.yml
appnode.yml
db.yml
host_vars/main.yml
host1.yml
host2.yml
host3.yml
bit.ly/ansiblebest
FactsПеременные, определенные на управляемых хостах
↳ ansible_architecture: x86_64
↳ ansible_devices: [{“sda”: {...}}, {“sdb”: {...}}]
↳ ansible_distribution: Ubuntu
↳ ansible_os_family: Debian
↳ ansible_processor_count: 8
bit.ly/ansiblebest
Modules
↳ template: отрендерить шаблон и положить на управляемый хост
↳ copy: скопировать файл на управляемый хост
↳ git: управление копией репозитория
↳ archive: упаковка и распаковка архивов
↳ shell: исполнение произвольных команд
↳ Всего более 250 модулей
bit.ly/ansiblebest
Команда ansibleПозволяет выполнить простую задачу на группах серверов$ ansible appnode -m pinghost1 | success >> { "changed": false, "ping": "pong"}
host2 | success >> { "changed": false, "ping": "pong"}
bit.ly/ansiblebest
Команда ansible$ ansible appnode -m service -a “name=nginx state=restarted”host1 | success >> { "changed": True,
"name": "nginx",
"state": "restarted",}host2 | success >> { "changed": True,
"name": "nginx",
"state": "restarted",}
bit.ly/ansiblebest
Playbook
---
- hosts: appnode
tasks:
- service: name=nginx state=started
$ ansible-playbook playbook.yml
bit.ly/ansiblebest
Include
---
- hosts: appnode
tasks:
- include: path/to/other/tasks.yml
roles:
- role: appnode
- include: otherplaybook.yml
bit.ly/ansiblebest
Handlers---
- hosts: appnode
handlers:
- name: restart nginx
service: name=nginx state=restarted
tasks:
- template: src=appnode.j2 dest=/etc/nginx/conf.d/appnode.conf
notify: restart nginx
bit.ly/ansiblebest
Register & when---
- hosts: appnode
tasks:
- stat: path=/var/lib/redis/mydb.aof
register: mydbst
- shell: echo ‘mydb.aof exists`
when: mydbst.stat.exists
bit.ly/ansiblebest
Шаблонизатор: jinja2---
- hosts: appnode
vars:
servicename: appnode
workdir: /home/app
user: app
group: app
tasks:
- service: name={{ servicename }} state=started
- file: path={{ workdir }} owner={{ user }} group={{ group }}
bit.ly/ansiblebest
Role---
- hosts: appnode
roles:
- role: appnode
roles/appnode/
tasks/main.yml
defaults/...
vars/...
files/...
templates/...
handlers/...
bit.ly/ansiblebest
Окружения
inventory/
production
integration
qa
performance
$ ansible-playbook -i inventory/production deploy.yml
Окружения: проблемы
↳ Список серверов “захардкожен” в inventory↪ политика именования веток в deploy-репозитории - по версиям
↳ ini-like формат inventory не позволяет хранить сложные структуры в переменных, что приводит к
inventory/production/hosts
group_vars/
↳ Отсутствие single point of truth↪ salt-master/chef-server/puppet-server↪ aws: 169.254.169.254
Переменные: проблемы
↳ Существует 15(!) способов определить переменную↳ yaml + jinja = боль
↪ name: {{ othervar }} # ka-boom!↪ name: ‘{{ othervar }}’
↳ Нельзя просто создать факт в playbook↪ set_fact создает временную переменную↪ Официальный ответ - создавать файл в /etc/ansible/facts.d
Решения:↳ Локализовывать переменные в месте их использования↳ Переменные, зависящие от окружения выносить в inventory↳ Сложные структуры использовать по минимуму
Переменные: проблемы
↳ inventory↪ host key=value↪ [group:vars]
↳ inventory/group_vars↳ inventory/host_vars↳ group_vars↳ host_vars↳ register↳ include_vars module
↳ playbook↪ vars↪ vars_files
↳ role/defaults↳ role/vars↳ set_fact module↳ facts↳ include: tasks.yml key: value
Playbook: проблемы
↳ ansible-playbook -i prod deploy.yml --tags appnode илиansible-playbook -i prod appnode.yml --tags deploy?
↳ Директива hosts, привязывающая действия к хостам = нет универсальных playbook-ов
↳ Как часть задач из одного playbook включить в другой playbook?Решения:↳ Минимизация playbook-ов:
↪ включать только роли↳ Каждый playbook делает одно простое действие
↪ появление обертокansible-playbook -i inventory/prod deploy.yml --tags glassfish,appnpdedeploy prod glassfish,appnode
Role: проблемы
↳ По документации, роль - способ выделения абстракций (app, db, balancer)
↳ Фактически - возможность задавать относительные пути↪ template: src=/path/to/templates/mytmpl.j2↪ template: src=mytmpl.j2
↳ Для разрешения сложных зависимостей между ролями приходится изобретать велосипед
Решения:↳ Отходить от “best practices”:
↪ roles/appnode/{tasks,templates,files,...}↪ roles/appnode/build/{tasks,templates,files,...}
roles/appnode/install/{tasks,templates,files,...}roles/appnode/configure/{tasks,templates,files,...}
Customizing work with git
↳ git: repo=git://ourrepo branch=changeset-123 больше не работает :(↪ git module вытягивает только refs/heads и refs/tags↪ changeset-123 == refs/changeset/123
↳ git fetch ssh://gerrit/repo refs/changeset/123 && git checkout FETCH_HEAD
↳ shell: to the rescue!
Ansible: backwards compatibility
↳ Обновление с 1.5.4 на 1.7.x поломало модуль copy
↳ include role with_items: deprecated & unsupported
↪ “потому что мы не можем загрузить все созданные переменные”
Заключение↳ Ansible - чаще обертка над bash+pssh, чем CM tool↳ Понятия часто расходятся с реальностью↳ Сложно разработать процесс, не укладывающийся в
рамки “best practices”Тем не менее,↳ “it works”↳ проблемы решаемы в обозримое время↳ структура, продуманная один раз, применима для
(почти) любых новых проектов↳ админы любят :)
Спасибо за внимание!Вопросы?