Что такое ChatOps?
ChatOps предоставляет контекст работы, который вы уже делаете, в разговорах, которые вы ведете
ChatOps по-прежнему остается свежим и необычным в мире DevOps, когда работа переходит в общий чат. Вы можете запускать команды непосредственно из чата, и все в чате могут видеть историю выполняемой команды, делать то же самое, взаимодействовать друг с другом и даже учиться. Информация и процесс принадлежат всей команде, это приносит много преимуществ.nnВы можете приступить к выполнению таких операций, как развертывание кода или серверов предоставления ресурсов из чата, просмотр графиков из инструментов мониторинга, отправка SMS, контроль ваших кластеров или просто запуск простых команд оболочки. ChatOps может представлять собой высокоуровневое представление вашего действительно сложного процесса CI / CD ,упрощая общение в чатом, например !deploy
. Этот подход делает чудеса для повышения наглядности и уменьшения сложности в процессе развертываний.n
Расширенные возможности ChatOps
StackStorm — это проект OpenSource, специально ориентированный на автоматизацию событий ChatOps.Платформа поддерживает множество инструментов DevOps, таких как управление конфигурацией, мониторинг, оповещение, графическое отображение и т. д., что позволяет вам управлять всем из одного центра управления.Это идеальный инструмент для ChatOps, предоставляющий возможность создавать и автоматизировать любые мыслимые рабочие процессы и управлять любыми наборами инструментов непосредственно из чата.nnStackStorm имеет возможность интеграции с Ansible и множество расширенных функций ChatOps в версиях платформы 1.0 , 1.2 и 1.4, чтобы помочь вам в реальной работе, а не просто отображать забавные фотографии котенка из чата. Ниже я расскажу, как сделать ChatOps и Ansible возможным с помощью платформы StackStorm.n
Кстати, StackStorm as Ansible является декларативным, написанным на Python и использующим YAML + Jinja.
План
В этом уроке мы собираемся сначала установить управляющую машину Ubuntu 14, которая будет обрабатывать нашу систему ChatOps. Затем настроим платформу StackStorm, включая пакет интеграции Ansible. Наконец, мы подключим систему с Slack и покажем некоторые простые, но реальные примеры использования Ansible непосредственно из чата интерактивным способом.nnИтак, давайте начнем и убедитесь, что мы близки к технологической сингулярности , предоставив root доступ к ботам чата и позволяя им управлять нашими 100 + серверами и кластерами.n
Шаг 0. Подготовьте Slack
Как уже говорилось, давайте использовать Slack.com для чата. Зарегистрируйтесь в Slack, если у вас ее еще нет. Включите интеграцию Hubot в настройках.n
Hubot — бот-движок GitHub, созданный для ChatOps.
nКак только вы закончите, у вас будет API-токен:n
HUBOT_SLACK_TOKEN=xoxb-5187818172-I7wLh4oqzhAScwXZtPcHyxCu
Затем мы сконфигурируем всю платформу StackStorm, покажем некоторые полезные примеры, а также разрешим создавать собственные команды ChatOps.nn
n
Легенький режим!
Для тех, кто ленив (большинство DevOps), вот брандмауэр-репо, которое устанавливает все необходимые инструменты в простых сценариях, подготовив платформу для написания команд ChatOps в Slack chat: https://github.com/StackStorm/showcase-ansible-chatopsn
# replace with your tokennexport HUBOT_SLACK_TOKEN=xoxb-5187818172-I7wLh4oqzhAScwXZtPcHyxCungit clone https://github.com/StackStorm/showcase-ansible-chatops.gitncd showcase-ansible-chatopsnnvagrant up
Для тех, кто интересуется деталями — перейдем к ручному режиму и идем дальше.n
Шаг 1. Установите StackStorm
Это действительно так просто, одна команда:n
curl -sSL https://stackstorm.com/packages/install.sh | sudo bash -- --user=demo --password=demo
Этот однострочный интерфейс предназначен только для демонстрационных целей, для развертывания prod вы должны использовать доступные ansible playbooks для установки st2.
Шаг 2. Установите Ansible Integration pack
Идея интеграции пакетов в StackStorm заключается в том, что они соединяют систему с внешними инструментами или службами. Нам нужен пакет Ansible:n
st2 pack install ansible
Помимо пакета Ansible Integration , он устанавливает существующие двоичные файлы в Python virualenv, расположенный в /opt/stackstorm/virtualenvs/ansible/bin
.nn
n
Шаг 3. Настройка ChatOps
Теперь вам нужно настроить файл /opt/stackstorm/chatops/st2chatops.env
в соответствии с вашими потребностями. Для этого стоит взглянуть на все переменные, но сначала убедитесь, что вы редактируете следующие envs:n
# Bot namenexport HUBOT_NAME=stanleynexport HUBOT_ALIAS='!'nn# StackStorm API keyn# Use: `st2 apikey create -k` to generaten# Replace with your key (!)nexport ST2_API_KEY="123randomstring789"nn# ST2 AUTH credentialsn# Replace with your username/password (!)nexport ST2_AUTH_USERNAME="demo"nexport ST2_AUTH_PASSWORD="demo"nn# Configure Hubot to use Slacknexport HUBOT_ADAPTER="slack"nn# Replace with your token (!)nexport HUBOT_SLACK_TOKEN="xoxb-5187818172-I7wLh4oqzhAScwXZtPcHyxCu"
st2chatops
чтобы применить изменения, и все готово к работе:n
sudo service st2chatops restart
n
Шаг 4. Первый ChatOps
На этом этапе вы должны увидеть Stanley bot в чате. Пригласите его в свой канал Slack:n
/invite @stanley
Получить список доступных команд:
n
n
n
n
n
n
!help
Бьюсь об заклад, вы полюбите shipit
:
n
n
n
n
n
n
!ship it
После игры с существующими командами, давайте продолжим с чем-то серьезным.nn
n
n
n
n
n
n
Шаг 5. Создание собственных команд ChatOps
Одной из функций StackStorm является возможность создания псевдонимов команд, что упрощает работу с ChatOps. Вместо того, чтобы писать длинную команду, вы можете просто привязать ее к чему-то более дружественному и понятному, простому.nnДавайте создадим собственный пакет StackStorm, который будет содержать все необходимые команды. Шаблон пакета StackStorm псевдонимов aliases/ansible.yaml
со следующим содержимым:n
---nname: "chatops.ansible_local"naction_ref: "ansible.command_local"ndescription: "Run Ansible command on local machine"nformats:n - display: "ansible <command>"n representation:n - "ansible {{ args }}"nresult:n format: |n Ansible command `{{ execution.parameters.args }}` result: {~}n {% if execution.result.stderr %}*Stdout:* {% endif %}n ```{{ execution.result.stdout }}```n {% if execution.result.stderr %}*Stderr:* ```{{ execution.result.stderr }}```{% endif %}n extra:n slack:n color: "{% if execution.result.succeeded %}good{% else %}danger{% endif %}"
n
n
n
!pack install https://github.com/armab/st2_chatops_aliases
Теперь мы можем запускать простую команду непосредственно из Slack chat:n
!ansible "uname -a"
n
n
n
n
n
nКоторая на низком уровне эквивалентена:n
/opt/stackstorm/virtualenvs/ansible/bin/ansible all --connection=local --args='uname -a' --inventory-file='127.0.0.1,'n
nНо давайте рассмотрим более полезные примеры, демонстрирующие преимущества интерактивности ChatOps.n
Пример №1: получить статус сервера
У Ansible есть простой модуль ping, который просто соединяется с указанными узлами и возвращает успех pong
.Простой, но мощный пример, чтобы понять, состояние серверов прямо из чата в считанные секунды, без входа в терминал.nnЧтобы сделать это, нам нужно создать еще одно action
для нашего пакета, в котором выполняется реальные action alias
команды и action alias
которые является просто синтаксическим синонимами, Реализуем возможным в ChatOps:n
!status 'web'
Действия actions/server_status.yaml
:n
---nname: server_statusndescription: Show server status by running ansible ping ad-hoc commandnrunner_type: local-shell-cmdnentry_point: ""nenabled: truenparameters:n sudo:n description: "Run command with sudo"n type: booleann immutable: truen default: truen kwarg_op:n immutable: truen cmd:n description: "Command to run"n type: stringn immutable: truen default: "/opt/stackstorm/virtualenvs/ansible/bin/ansible {{hosts}} --module-name=ping"n hosts:n description: "Ansible hosts to ping"n type: stringn required: true
Псевдонимов действий aliases/server_status.yaml
:
n
n
n
n
n
n
---nname: chatops.ansible_server_statusnaction_ref: st2_chatops_aliases.server_statusndescription: Show status for hosts (ansible ping module)nformats:n - display: "status <hosts>"n representation:n - "status {{ hosts }}"n - "ping {{ hosts }}"nresult:n format: |n Here is your status for `{{ execution.parameters.hosts }}` host(s): {~}n ```{{ execution.result.stdout }}```n extra:n slack:n color: "{% if execution.result.succeeded %}good{% else %}danger{% endif %}"n fields:n - title: Aliven value: "{{ execution.result.stdout|regex_replace('(?!SUCCESS).', '')|wordcount }}"n short: truen - title: Deadn value: "{{ execution.result.stdout|regex_replace('(?!UNREACHABLE).', '')|wordcount }}"n short: truen footer: "{{ execution.id }}"n footer_icon: "https://stackstorm.com/wp/wp-content/uploads/2015/01/favicon.png"
nУбедитесь, что вы настроили хосты в файле Ansible inventory /etc/ansible/hosts
.nnПосле внесенных изменений не забудьте переустановить отредактированный пакет из чата (замените его на ваш репозиторий github):n
!pack install https://github.com/armab/st2_chatops_aliases
Очень удобно, что вы можете сохранить всю конфигурацию команды ChatOps в удаленном репо, как пакет StackStorm, и перезагрузить его после редактирования.nn
n
n
n
n
n
nДавайте получим статус сервера:nnЭто действительно мощно, любой может запустить без доступа к серверу! При таком подходе сотрудничество, деплой и работу вокруг инфраструктуры можно выполнять из любого места в чате: находитесь ли вы в офисе или работаете удаленно (некоторые из нас могут работать непосредственно с пляжа).n
Пример №2: перезапустить службы
У вас были ситуации, когда простой перезапуск службы может решить проблему? Не идеальный способ фиксации сбоя, но иногда вам просто нужно быстро решить проблему. Давайте напишем команду ChatOps, которая перезапускает определенные службы на определенных хостах.nnМы хотим сделать что-то вроде этого:n
!service restart "rabbitmq-server" on "mq"
nВ ранее созданных пакетах StackStorm добавим actions/service_restart.yaml
:n
---nname: service_restartndescription: Restart service on remote hostsnrunner_type: local-shell-cmdnentry_point: ""nenabled: truenparameters:n sudo:n description: "Run command with sudo"n type: booleann immutable: truen default: truen kwarg_op:n immutable: truen cmd:n description: "Command to run"n type: stringn immutable: truen default: "/opt/stackstorm/virtualenvs/ansible/bin/ansible {{hosts}} --become --module-name=service --args='name={{service_name}} state=restarted'"n hosts:n description: "Ansible hosts"n type: stringn required: truen service_name:n description: "Service to restart"n type: stringn required: true
aliases/service_restart.yaml
:n
n
n
---nname: chatops.ansible_service_restartnaction_ref: st2_chatops_aliases.service_restartndescription: Restart service on remote hostsnformats:n - display: "service restart <service_name> on <hosts>"n representation:n - "service restart {{ service_name }} on {{ hosts }}"nresult:n format: |n Service restart `{{ execution.parameters.service_name }}` on `{{ execution.parameters.hosts }}` host(s): {~}n {% if execution.result.stderr %}n *Exit Status*: `{{ execution.result.return_code }}`n *Stderr:* ```{{ execution.result.stderr }}```n *Stdout:*n {% endif %}n ```{{ execution.result.stdout }}```n extra:n slack:n color: "{% if execution.result.succeeded %}good{% else %}danger{% endif %}"n fields:n - title: Restartedn value: "{{ execution.result.stdout|regex_replace('(?!SUCCESS).', '')|wordcount }}"n short: truen - title: Failedn value: "{{ execution.result.stdout|regex_replace('(?!(FAILED|UNREACHABLE)!).', '')|wordcount }}"n short: truen footer: "{{ execution.id }}"n footer_icon: "https://stackstorm.com/wp/wp-content/uploads/2015/01/favicon.png"
n
n
nnИ знаешь, что? Благодаря мобильному клиенту Slack вы можете запускать эти команды чата и со своего мобильного телефона!n
Пример №3: Получить в настоящее время MySQL-запросы
Мы хотим, чтобы простая команда slack запрашивала список процессов mysql с сервера db:n
!show mysql processlist
Действие actions/mysql_processlist.yaml
:
n
n
n
n
n
n
---nname: mysql_processlistndescription: Show MySQL processlistnrunner_type: local-shell-cmdnentry_point: ""nenabled: truenparameters:n sudo:n immutable: truen default: truen kwarg_op:n immutable: truen cmd:n description: "Command to run"n type: stringn immutable: truen default: "/opt/stackstorm/virtualenvs/ansible/bin/ansible {{ hosts }} --become --become-user=root -m shell -a \"mysql --execute='SHOW PROCESSLIST;' | expand -t 10\""n hosts:n description: "Ansible hosts"n type: stringn default: db
aliases/mysql_processlist.yaml
:n
n
n
---nname: chatops.mysql_processlistnaction_ref: st2_chatops_aliases.mysql_processlistndescription: Show MySQL processlistnformats:n - display: "show mysql processlist <hosts=db>"n representation:n - "show mysql processlist {{ hosts=db }}"n - "show mysql processlist on {{ hosts=db }}"nresult:n format: |n {% if execution.status == 'succeeded' %}MySQL queries on `{{ execution.parameters.hosts }}`: ```{{ execution.result.stdout }}```{~}{% else %}n *Exit Code:* `{{ execution.result.return_code }}`n *Stderr:* ```{{ execution.result.stderr }}```n *Stdout:* ```{{ execution.result.stdout }}```n {% endif %}
hosts
необязательным (по умолчанию — db
), поэтому эти команды эквивалентны:n
n
n
nВаш администратор базы данных будет счастлив!n
Пример №4: получить статистику HTTP nginx
Мы хотим показать коды состояния HTTP, сортировать их по поступлению, чтобы понять, сколько 200
или 50x
есть на определенных серверах:n
!show nginx stats on 'web'
Фактическое действие, выполняющее actions/http_status_codes.yaml
команды actions/http_status_codes.yaml
:
n
n
n
n
n
n
---nname: http_status_codesndescription: Show sorted http status codes from nginx logsnrunner_type: local-shell-cmdnentry_point: ""nenabled: truenparameters:n sudo:n immutable: truen default: truen kwarg_op:n immutable: truen cmd:n description: "Command to run"n type: stringn immutable: truen default: "/opt/stackstorm/virtualenvs/ansible/bin/ansible {{hosts|replace('http://','')}} --become -m shell -a \"awk '{print \\$9}' /var/log/nginx/access.log|sort |uniq -c |sort -k1,1nr 2>/dev/null|column -t\""n hosts:n description: "Ansible hosts"n type: stringn required: true
aliases/http_status_codes.yaml
n
n
n
---nname: chatops.http_status_codesnaction_ref: st2_chatops_aliases.http_status_codesndescription: Show sorted http status codes from nginx on hostsnformats:n - display: "show nginx stats on <hosts>"n representation:n - "show nginx stats on {{ hosts }}"nresult:n format: "```{{ execution.result.stdout }}```"
n
n
nnТеперь чат больше похож на центр управления. Вы можете делать что-то на своих хостах из чата, и каждый может видеть результат!n
Пример №5: Патч безопасности
Представьте, что вы должны исправить еще одну критическую уязвимость, такую как Shellshock . Нам нужно обновить bash
на всех машинах с помощью Ansible. Вместо того, чтобы запускать его как специальную команду, давайте playbooks/update_package.yaml
сделаем красиво playbooks/update_package.yaml
:n
---n- name: Update package on remote hosts, run on 25% of servers at a timen hosts: "{{ hosts }}"n serial: "25%"n become: Truen become_user: rootn tasks:n - name: Check if Package is installedn command: dpkg-query -l {{ package }}n register: is_installedn failed_when: is_installed.rc > 1n changed_when: nonn - name: Update Package only if installedn apt: name={{ package }}n state=latestn update_cache=yesn cache_valid_time=600n when: is_installed.rc == 0
Вы можете видеть, что переменные {{ hosts }}
и {{ package }}
в playbook вводятся снаружи, см. Действия StackStorm action actions/update_package.yaml
:n
---nname: update_packagendescription: Update package on remote hostsnrunner_type: local-shell-cmdnentry_point: ""nenabled: truenparameters:n sudo:n immutable: truen default: truen kwarg_op:n immutable: truen timeout:n default: 6000n cmd:n description: "Command to run"n immutable: truen default: "/opt/stackstorm/virtualenvs/ansible/bin/ansible-playbook /opt/stackstorm/packs/${ST2_ACTION_PACK_NAME}/playbooks/update_package.yaml --extra-vars='hosts={{hosts|replace('http://','')}} package={{package}}'"n hosts:n description: "Ansible hosts"n type: stringn required: truen package:n description: "Package to upgrade"n type: stringn required: true
n
n
naliases/update_package.yaml
:n
---nname: chatops.ansible_package_updatenaction_ref: st2_chatops_aliases.update_packagendescription: Update package on remote hostsnformats:n - display: "update <package> on <hosts>"n representation:n - "update {{ package }} on {{ hosts }}"n - "upgrade {{ package }} on {{ hosts }}"nresult:n format: |n Update package `{{ execution.parameters.package }}` on `{{ execution.parameters.hosts }}` host(s): {~}n {% if execution.result.stderr %}n *Exit Status*: `{{ execution.result.return_code }}`n *Stderr:* ```{{ execution.result.stderr }}```n *Stdout:*n {% endif %}n ```{{ execution.result.stdout }}```n extra:n slack:n color: "{% if execution.result.succeeded %}good{% else %}danger{% endif %}"n fields:n - title: Updated nodesn value: "{{ execution.result.stdout|regex_replace('(?!changed=1).', '')|wordcount }}"n short: truen - title: Executed inn value: ":timer_clock: {{ execution.elapsed_seconds | to_human_time_from_seconds }}"n short: truen footer: "{{ execution.id }}"n footer_icon: "https://stackstorm.com/wp/wp-content/uploads/2015/01/favicon.png"
n
n
n
nБольшая часть нашей работы, как инженеров DevOps, — это оптимизировать процессы, упрощая жизнь разработчиков, улучшая сотрудничество в команде, диагностировать проблемы быстрее, автоматизируя среду и привнося нужные инструменты, чтобы сделать компанию успешной.nChatOps решает это на совершенно новом эффективном уровне!nnЭто простые примеры. Более сложные ситуации, когда несколько инструментов DevOps привязаны к динамическим рабочим процессам, будут рассмотрены в будущих статьях. Именно здесь StackStorm демонстрирует свою супермощность, принимая решения о том, что делать в зависимости от ситуации: управляемая событиями архитектура, такая как системы самовосстановления.n
Хотите упростить работу? Обращайтесь [email protected]
n
n