Роллинг обновление с марионеткой, ансайлом или тканью
У меня есть несколько серверов Jetty с loadbalancer перед ними. Теперь я хочу обновить свое приложение без простоев. Когда один причал выходит из строя и перестает быть доступным, балансировщик нагрузки автоматически удаляет его из списка, поэтому проблема не в этом.
Основная проблема заключается в том, чтобы избежать простоев: поэтому я должен убедиться, что одновременно запускается только один причал, или убедиться, что хотя бы N причалов находятся в сети!
В данный момент я использую простой сценарий bash, в котором мне нужно дождаться ручного возвращения одного причала, чтобы снова подключиться к нему, а затем перезапустить следующий и так далее.
Теперь bash не очень оптимален для такого рода вещей, и я надеюсь, что есть инструменты, которые лучше подходят для автоматизации всей задачи. Например, я мог бы использовать простой URL-адрес ping http://jetty-number-n.com/ping
который отвечает ОК (200), если n-й причал в сети.
Как я мог решить эту задачу и с помощью какого инструмента?
Благодаря @ceejayoz я нашел актуальное обновление для ansible. Но это все еще неоптимально, так как мне нужно установить фиксированное время ожидания.
5 ответов
Это довольно легко с Ansible. Грубый псевдо-ANSIBLE Playbook:
---
- hosts: your_server_group
sudo: yes
serial: 1
tasks:
- shell: reboot now
- wait_for: port=22
Соль имеет удобный пакетный вариант.
salt -G 'os:RedHat' --batch-size 25% service.restart jetty
Перезапускайте сервис Jetty одновременно на 25% серверов RedHat.
salt -N group1 -b 2 system.restart
Перезапустите серверы в заранее определенной "group1", по 2 за раз.
Я сейчас использую Puppet на работе, но, как ответил первый постер, это не похоже на идеальное первое задание для Puppet. Я не могу говорить с ansible (хотя я хочу начать испытывать это).
Puppet больше ориентирован на развертывание изменений / перезапуск систем одновременно - демон Puppet запускается на каждом клиенте и проверяет центральный сервер с запланированным интервалом (по умолчанию каждые полчаса). Если вы хотите нарушить планирование по умолчанию, вы обычно используете другой механизм для вызова puppet.
Если вы согласны с одновременным перезапуском, перезапуск службы является вопросом определения манифеста с
file { 'your_war_file.war':
ensure => file,
source => "puppet:///...",
}
service { 'jetty':
subscribe => File['your_war_file.war'],
hasrestart => True,
}
директив ресурсов, затем выталкивают манифест и позволяют Puppet делать свое дело. Это предполагает, что вы в порядке с вызовом
/etc/init.d/jetty restart
что может или не может быть приемлемым или даже возможным.
Вы также можете определить свои собственные типы ресурсов для этого, что определенно выходит за рамки простой задачи кукол впервые.
Посетите http://forge.puppetlabs.com/, чтобы узнать, решил ли кто-нибудь еще подобную проблему.
Задача, которую вы хотите выполнить, может быть выполнена с помощью ansible, и определенно может быть выполнена с помощью Puppet. Я собираюсь сосредоточиться на том, как сделать это с помощью марионетки.
Вы можете развернуть ваши WAR-файлы в Jetty, используя puppet, используя обычный ресурс "file" и определенный ресурс, который вы инициализируете для каждого приложения.
Puppet будет загружен с указанного вами URL-адреса (на вашем Puppet Master). Jetty может повторно развернуть файлы WAR без перезапуска, если время изменения файла WAR изменяется. Так что, если ваш манифест создает копию в $JETTY_HOME/webapps
это должно быть автоматически подобрано Джетти. Таким образом (или касаясь context.xml) вам не нужно перезапускать Jetty вручную.
Чтобы загрузить файл WAR с вашего Puppet Master в каталог приложений, вам потребуется следующий манифест (заменяющий $JETTY_HOME):
define jetty::deployment($path) {
notice("Deploying ${name} to http://$hostname:${appserver-jetty::port}/"),
include jetty,
file { "$JETTY_HOME/webapps/${name}.war":
owner => 'root',
source => $path,
}
}
и вам нужно дать указание вашим узлам получать определенную версию вашего приложения один за другим (после того, как вы убедитесь, что оно успешно запущено на одном из узлов). Это можно сделать с помощью ENC (классификатор внешних узлов) или, если вы не используете ENC, изменив раздел site.pp для каждого узла (или группы узлов):
node jetty-node1 {
jetty::deployment { "servlet":
path => '/srv/application/Servlet-1.2.3.war'
}
},
node jetty-node2 {
jetty::deployment { "servlet":
path => '/srv/application/Servlet-2.0.1.war'
}
}
include jetty
Эта линия необходима только в том случае, если вы хотите управлять своей конфигурацией Jetty с помощью команды puppet, например. https://github.com/maestrodev/puppet-jetty и этому определенному ресурсу нужна переменная appserver-jetty::$port. В этом примере показан самый простой способ, которым вы можете точно контролировать, какая версия приложения обслуживается каким узлом. Таким образом, вы можете создать сценарий развертывания на основе ваших проверок работоспособности и развернуть его на узле 2 только после того, как узел 1 успешно запустит новую версию.
Этот пример только для демонстрации концепции.
Возможно, вы захотите проверить эти дополнительные ресурсы для получения дополнительной информации и идей: о перезагрузке контекстов: https://stackoverflow.com/questions/13965643/auto-reloading-war-in-jetty-standalone
Это для развертывания и управления Tomcat, но идеи (и манифесты) похожи: http://www.tomcatexpert.com/blog/2010/04/29/deploying-tomcat-applications-puppet
Это, IMO, лучшая альтернатива прямому копированию файлов WAR - использование собственных пакетов (например, RPM) для развертывания вашего приложения: http://www.slideshare.net/actionjackx/automated-java-deployments-with-rpm
У Puppet есть понятия " Услуги и заказ". Но кукла работает на одном сервере. Так что у него нет понимания других систем, на которых он работает.
Если вы хотите использовать Puppet, вы можете иметь его, чтобы на одном главном сервере управления был скрипт инициализации для управления службами каждого сервера. Таким образом, скрипт init запускает перезапуск на каждом сервере и возвращает код состояния. Вы можете сделать это и связать каждый сервисный перезапуск с этого одного сервера и заказать, создать цепочку или уведомить и подписаться, чтобы перейти к следующему.
Вы также можете написать пользовательскую библиотеку для puppet, которая будет рассматривать один сервер как главный управляющий сервер, но вместо использования сценариев инициализации. Он может использовать пользовательскую библиотеку ruby для управления службами каждого сервера. Это немного сложнее в настройке, но может работать.