Puppet — это система управления конфигурациями, написанная на Ruby (по-моему, это недостаток).
Из коробки puppet, а точнее его серверная часть (а он имеет клиент-серверную модель) поставляется с готовым WEBrick сервером. Этот сервер подходит только для «опапечивания» пары виртуалок, но с серьезной нагрузкой он просто не справляется.
Как вариант, можно использовать Passenger + какой-нибудь web server, например Apache, но как показывает практика, эта схема тоже дает сбои.
И тут на сцену выходит Unicorn, он же единорог. Данная статья описывает, как установить и настроить puppet + Unicorn + nginx
Для начала, т.к. речь идет о высоких нагрузках, а если точнее, то о нескольких десятков серверов одновременно получающих конфигурации, состоящие из нескольких сотен ресурсов (бывает и такое), заимейте годный сервер, минимум 12 ядер + пару пар гигабайт оперы, плюс минимум два диска, а лучше ssd. Уже есть? Тогда продолжим.
Установка и настройка проводилась на CentOS, но это непринципиально, подозреваю, что на свою систему вы поставите это без особых трудностей (привет пользователям венды, это не о вас).
Начнем с установки puppetmaster, он же puppet server, nginx, и необходимых пакетов для установки unicorn.
sudo yum -y install puppet-server rubygems gcc make ruby-devel nginx
Когда все установится, ставим его и rack — он создан для обеспечения минимального API для подключения веб-серверов, поддерживающих Ruby.
sudo gem install unicorn rack
Если на сервере нет подключения к интернету, а это нормально, то заранее скачиваем гемы-зависимости (kgio, raindrops) и необходимые гемы отсюда.
Локально установить их можно командой
sudo gem install --local gemfile.gem
Далее копируем конфиг puppet сервера в директорию конфигурации
sudo cp /usr/share/puppet/ext/rack/files/config.ru /etc/puppet/
Cоздаем конфиг для unicorn /etc/puppet/unicorn.conf
worker_processes 24
working_directory "/etc/puppet"
listen '/var/run/puppet/puppetmaster_unicorn.sock', :backlog => 512
timeout 120
pid "/var/run/puppet/puppetmaster_unicorn.pid"
preload_app true
if GC.respond_to?(:copy_on_write_friendly=)
GC.copy_on_write_friendly = true
end
before_fork do |server, worker|
old_pid = "#{server.config[:pid]}.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
end
24 процесса (worker_processes), потому что 24 ядра, измените согласно вашим характеристикам. Проверим, что все работает, для этого запустим unicorn с нашим конфигом
unicorn -c /etc/puppet/unicorn.conf
Должны увидеть что-то, наподобие:
I, [2012-12-01T17:06:10.961269 #3600] INFO -- : Refreshing Gem list
I, [2012-12-01T17:06:12.108620 #3600] INFO -- : unlinking existing socket=/var/run/puppet/puppetmaster_unicorn.sock
I, [2012-12-01T17:06:12.109171 #3600] INFO -- : listening on addr=/var/run/puppet/puppetmaster_unicorn.sock fd=6
I, [2012-12-01T17:06:12.112182 #3604] INFO -- : worker=0 spawned pid=3604
I, [2012-12-01T17:06:12.113449 #3605] INFO -- : worker=1 spawned pid=3605
I, [2012-12-01T17:06:12.113944 #3604] INFO -- : worker=0 ready
I, [2012-12-01T17:06:12.115137 #3605] INFO -- : worker=1 ready
I, [2012-12-01T17:06:12.116153 #3606] INFO -- : worker=2 spawned pid=3606
I, [2012-12-01T17:06:12.116878 #3607] INFO -- : worker=3 spawned pid=3607
I, [2012-12-01T17:06:12.118506 #3606] INFO -- : worker=2 ready
I, [2012-12-01T17:06:12.118879 #3607] INFO -- : worker=3 ready
I, [2012-12-01T17:06:12.119553 #3608] INFO -- : worker=4 spawned pid=3608
I, [2012-12-01T17:06:12.121228 #3609] INFO -- : worker=5 spawned pid=3609
I, [2012-12-01T17:06:12.122360 #3608] INFO -- : worker=4 ready
I, [2012-12-01T17:06:12.122711 #3610] INFO -- : worker=6 spawned pid=3610
I, [2012-12-01T17:06:12.122829 #3609] INFO -- : worker=5 ready
I, [2012-12-01T17:06:12.123426 #3600] INFO -- : master process ready
I, [2012-12-01T17:06:12.124551 #3610] INFO -- : worker=6 ready
I, [2012-12-01T17:06:12.125002 #3611] INFO -- : worker=7 spawned pid=3611
I, [2012-12-01T17:06:12.126546 #3611] INFO -- : worker=7 ready
Прерываем нажатием Ctrl+C и двигаемся дальше.
Создаем /etc/init.d/puppet-unicorn
#!/bin/bash
# unicorn-puppet
# chkconfig: - 98 02
lockfile=/var/lock/puppetmaster-unicorn
pidfile=/var/run/puppet/puppetmaster_unicorn.pid
RETVAL=0
DAEMON=/usr/bin/unicorn
DAEMON_OPTS="-D -c /etc/puppet/unicorn.conf"
start() {
$DAEMON $DAEMON_OPTS
RETVAL=$?
[ $RETVAL -eq 0 ] && touch "$lockfile"
echo
return $RETVAL
}
stop() {
kill `cat $pidfile`
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f "$lockfile"
return $RETVAL
}
restart() {
stop
sleep 1
start
RETVAL=$?
echo
[ $RETVAL -ne 0 ] && rm -f "$lockfile"
return $RETVAL
}
condrestart() {
status
RETVAL=$?
[ $RETVAL -eq 0 ] && restart
}
status() {
ps ax | egrep -q "unicorn (worker|master)"
RETVAL=$?
if [ $RETVAL -eq 0 ];
then echo "Running"
else echo "Stopped"
fi
return $RETVAL
}
usage() {
echo "Usage: $0 {start|stop|restart|status|condrestart}" >&2
return 3
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
condrestart)
condrestart
;;
status)
status
;;
*)
usage
;;
esac
exit $RETVAL
И конечно же делаем его исполняемым.
Пора настраивать nginx:
sudo cat > /etc/nginx/conf.d/puppet-unicorn
upstream puppetmaster_unicorn {
server unix:/var/run/puppet/puppetmaster_unicorn.sock fail_timeout=0;
}
server {
listen 8140;
ssl on;
ssl_session_timeout 5m;
ssl_certificate /var/lib/puppet/ssl/certs/puppet.cloud.local.pem;
ssl_certificate_key /var/lib/puppet/ssl/private_keys/puppet.cloud.local.pem;
ssl_client_certificate /var/lib/puppet/ssl/ca/ca_crt.pem;
ssl_ciphers SSLv2:-LOW:-EXPORT:RC4+RSA;
ssl_verify_client optional;
root /usr/share/empty;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Client-Verify $ssl_client_verify;
proxy_set_header X-Client-DN $ssl_client_s_dn;
proxy_set_header X-SSL-Issuer $ssl_client_i_dn;
proxy_read_timeout 120;
location / {
proxy_pass http://puppetmaster_unicorn;
proxy_redirect off;
}
}
^C
Не забудьте настроить количество worker_processes для nginx.
Теперь можно запускать puppet-unicorn, но для начала нужно убедиться что остановлен puppetmaster:
sudo service puppetmaster stop
Стоп, забыл про одну мелочь: нужно сгенерировать сертификат, если вы не запускали puppetmaster. Обратите внимание, что если вы используете один сертификат на несколько puppet серверов (балансировка например), то желательно указывать их имена при генерации сертификата.
sudo puppet cert generate puppet.cloud.local --dns_alt_names=server-1.local,server-2.local
Хотя все зависит от того, кто выступает Certificate Authority.
Вроде все готово, перепроверьте на всякий /etc/puppet/puppet.conf , чтоб там стоял правильный ca_server в секции master.
Запускаем:
sudo service puppet-unicorn start
sudo service nginx start
И не забываем поправить автозагрузку.
sudo chkconfig puppetmaster off
sudo chkconfig puppet-unicorn on
sudo chkconfig nginx on
24 ядерный сервер может единовременно обслуживать более 100 машин, время применения манифестов было около 100 секунд.
Т.е. если размазать выполнение puppet на час, то он справится и с 1000 машинами, а может быть и больше. Время покажет.
Спасибо за внимание.