Статьи

Нет простоя развертывания с Capistrano, Thin и nginx

Как я уже упоминал пару недель назад, я работал над учебником о том, как продумывать проблемы на графиках, и, поскольку это приложение для Sinatra, я подумал, что thin будет неплохим выбором для веб-сервера . В моей первоначальной настройке у меня был следующий конфигурационный файл nginx, который использовался для прокси-запросов на thin:

/etc/nginx/sites-available/thinkingingraphs.conf

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
upstream thin {
  server 127.0.0.1:3000;
}
 
server {
  listen       80 default;
  server_name _;
  charset utf-8;
 
  rewrite  ^\/status(.*)$  $1 last;
 
  gzip  on;
  gzip_disable "MSIE [1-6]\.(?!.*SV1)";
  gzip_types       text/plain application/xml text/xml text/css application/x-javascript application/xml+rss text/javascript application/json;
 
  gzip_vary on;
 
  access_log  /var/www/thinkingingraphs/shared/log/nginx_access.log;
  error_log  /var/www/thinkingingraphs/shared/log/nginx_error.log;
 
  root   /var/www/thinkingingraphs/current/public;
 
  location / {
    proxy_pass http://thin;
  }
 
  error_page  404              /404.html;
  error_page   500 502 503 504  /500.html;
}

У меня был сценарий выскочка, который запустил тонкий сервер …

/etc/init/thinkingingraphs.conf

1
2
3
4
5
6
7
script
  export RACK_ENV=production
  export RUBY=ruby
 
  cd /var/www/thinkingingraphs/current
  exec su -s /bin/sh vagrant -c '$RUBY -S bundle exec thin -p 3000 start >> /var/www/thinkingingraphs/current/log/production.log 2>&1'
end script

… А затем я использовал следующий скрипт capistrano, чтобы останавливать и запускать сервер всякий раз, когда я развертывал новую версию приложения:

конфиг / deploy.rb

01
02
03
04
05
06
07
08
09
10
namespace :deploy do
  task(:start) {}
  task(:stop) {}
 
  desc "Restart Application"
  task :restart do
    sudo "stop thinkingingraphs || echo 0"
    sudo "start thinkingingraphs"
  end
end

Проблема с этим подходом состоит в том, что некоторые запросы получают код ответа 502 при его перезапуске:

1
$ bundle exec cap deploy
1
2
3
4
5
6
7
$ while true; do curl -w %{http_code}:%{time_total} http://localhost/ -o /dev/null -s; printf "\n"; sleep 0.5; done
 
200:0.076
200:0.074
200:0.095
502:0.003
200:0.696

Я хотел попробовать сделать сценарий развертывания без простоев и наткнулся на пару постов, которые помогли мне понять, как это сделать. Первым шагом было убедиться, что у меня запущено более одного тонкого экземпляра, чтобы запросы могли отправляться одному из других во время перезапуска. Я создал следующий файл конфигурации:

/etc/thin/thinkingingraphs.yml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
chdir: /var/www/thinkingingraphs/current
environment: production
address: 0.0.0.0
port: 3000
timeout: 30
log: log/thin.log
pid: tmp/pids/thin.pid
max_conns: 1024
max_persistent_conns: 100
require: []
wait: 30
servers: 3
daemonize: true
onebyone: true

Одним из других свойств, которые нам нужно установить, является «onebyone», что означает, что при перезапуске thin он будет удалять тонкие экземпляры по одному за раз. Это означает, что один из двух других может обрабатывать входящие запросы. Мы установили количество серверов равным 3, что увеличит скорость вращения трех экземпляров на портах 3000, 3001 и 3002. Я изменил свой сценарий выгрузки, чтобы он выглядел так:

/etc/init/thinkingingraphs.conf

1
2
3
4
5
6
7
script
  export RACK_ENV=production
  export RUBY=ruby
 
  cd /var/www/thinkingingraphs/current
  exec su -s /bin/sh vagrant -c '$RUBY -S bundle exec thin -C /etc/thin/thinkingingraphs.yml start >> /var/www/thinkingingraphs/current/log/production.log 2>&1'
end script

Мне также пришлось изменить скрипт capistrano, чтобы он вызывал «тонкий перезапуск» вместо остановки и запуска сценария upstart:

конфиг / deploy.rb

1
2
3
4
5
6
7
8
9
namespace :deploy do
  task(:start) {}
  task(:stop) {}
 
  desc "Restart Application"
  task :restart do
    run "cd #{current_path} && bundle exec thin restart -C /etc/thin/thinkingingraphs.yml"
  end
end

Наконец, мне пришлось внести некоторые изменения в файл конфигурации nginx, чтобы отправлять запросы другим тонким экземплярам, ​​если первая попытка не удалась (из-за перезапуска), используя метод proxy_next_upstream :

/etc/nginx/sites-available/thinkingingraphs.conf

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
upstream thin {
  server 127.0.0.1:3000 max_fails=1 fail_timeout=15s;
  server 127.0.0.1:3001 max_fails=1 fail_timeout=15s;
  server 127.0.0.1:3002 max_fails=1 fail_timeout=15s;
}
 
server {
  listen       80 default;
  server_name _;
  charset utf-8;
 
  rewrite  ^\/status(.*)$  $1 last;
 
  gzip  on;
  gzip_disable "MSIE [1-6]\.(?!.*SV1)";
  gzip_types       text/plain application/xml text/xml text/css application/x-javascript application/xml+rss text/javascript application/json;
 
  gzip_vary on;
 
  access_log  /var/www/thinkingingraphs/shared/log/nginx_access.log;
  error_log  /var/www/thinkingingraphs/shared/log/nginx_error.log;
 
  root   /var/www/thinkingingraphs/current/public;
 
  location / {
    proxy_pass http://thin;
    proxy_next_upstream error timeout http_502 http_503;
  }
 
  error_page  404              /404.html;
  error_page   500 502 503 504  /500.html;
}

Мы также внесли изменения в наше вышестоящее определение для запросов прокси к одному из тонких экземпляров, которые будут работать. При развертывании приложения теперь нет простоев:

1
$ bundle exec cap deploy
1
2
3
4
5
6
7
8
$ while true; do curl -w %{http_code}:%{time_total} http://localhost/ -o /dev/null -s; printf "\n"; sleep 0.5; done
 
200:0.094
200:0.095
200:0.082
200:0.102
200:0.080
200:0.081

Единственная проблема заключается в том, что выскочка теперь, похоже, утратила контроль над тонкими процессами, и из того, что я могу сказать, нет мастер-процесса, на который выскочка могла бы получить дескриптор, поэтому я не уверен, как подключить это.

Справка: без перерывов в работе с capistrano, Thin и nginx от нашего партнера по JCG Марка Нидхэма в блоге Марка Нидхэма .