PuppetをPassengerで動かして大規模サイトに対応させる

大規模サイトでPuppetを運用する場合、複数のノードに同時にmanifestを適用すると思います。しかし、同時接続数5台を超えたあたりからクライアントのリクエストを捌けなくなり適用時にエラーが発生することがよくあります。その場合、同時接続数を減らしたり接続時間をずらしたりして対応していると思います。ただ、そんなのやってられねーって人に、Passengerを使ったパフォーマンスの改善を紹介します。

前提

  • puppet環境は構築されているものとして説明
  • puppet v0.25.x
  • CentOS v5.4
    • yum EPEL repository
  • Ruby v1.8.5
Passengerってなに?

上記で説明されている通りApache等でRubyアプリケーションを動かすための動作環境です。インストールと設定が楽で、RailsにおいてはほとんどApacheの設定だけで動作環境の設定が済んでしまいます。

Rackって?

一言で言うと、RubyアプリケーションのためのWebサーバへのインタフェースらしい

注意事項

上記でも書かれているように、何も考えずrackとpassengerの最新版をインストールしても動作しません。

Ruby v1.8.5(CentOS5系のデフォルトバージョン)では、

Remove rack 1.2.1 first and then install rack 1.1.0. It seems that rack
1.1.0 and passenger 2.2.9 have been the magic combination (at least for me).

  • Gary

って、言ってるのでおとなしくrack v1.1.0とpassenger v2.2.9をインストールしましょう。
Railsアプリケーションを既に動かしている場合は、別のサーバを用意するかした方がいいです。
Ruby v1.8.7系では最新版でも問題なく動作するかもしれません。(未検証)

手順

必要なソフトウエアのインストール
$ sudo yum install httpd httpd-devel ruby-devel rubygems mod_ssl
$ sudo gem rack -v 1.1.0
$ sudo gem Passenger -v 2.2.9
Passenger-Apacheモジュールのビルドとインストール

対話形式なので、指示に従って進めます。

$ sudo passenger-install-apache2-module

途中で必要なパッケージがインストールされていなければ、下記のように親切に指示されますので指示に従ってインストールした後、再実行しましょう。

Installation instructions for required software
* To install Curl development headers with SSL support:
  Please run yum install curl-devel as root.
* To install OpenSSL development headers:
  Please run yum install openssl-devel as root.

Rackの設定

Rack用のディレクトリと設定ファイルを作成します。Puppet v0.25系からはconfig.ruのテンプレートが用意されているのでそれをコピーして使うだけでいいです。

$ mkdir -p /usr/share/puppet/rack/puppetmasterd
$ mkdir /usr/share/puppet/rack/puppetmasterd/public /usr/share/puppet/rack/puppetmasterd/tmp
$ cp /usr/share/puppet/ext/rack/files/config.ru /usr/share/puppet/rack/puppetmasterd/
$ chown puppet /usr/share/puppet/rack/puppetmasterd/config.ru

Apacheの設定

インストール時に指示されたように、passenger-Apacheモジュールの設定を組み込みます。

$ sudo vim /etc/httpd/conf.d/passenger.conf
# passenger.conf
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.2.9/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.2.9
PassengerRuby /usr/bin/ruby

puppetmasterを動かすためのVirtualHostの設定を行います。
SSL証明書ファイルの名前はssl配下のディレクトリに作成されているサーバ用証明書のファイル名に置き換えてください。

$ sudo vim /etc/httpd/conf.d/puppetmaster.conf
# puppetmaster.conf
# Performance
#PassengerPoolIdleTime 300  # default: 300
PassengerUseGlobalQueue on
PassengerMaxPoolSize 60

Listen 8140
<VirtualHost *:8140>

    SSLEngine on
    SSLCipherSuite SSLv2:-LOW:-EXPORT:RC4+RSA
    SSLCertificateFile      /var/lib/puppet/ssl/certs/puppet-001.example.com.pem
    SSLCertificateKeyFile   /var/lib/puppet/ssl/private_keys/puppet-001.example.com.pem
    SSLCertificateChainFile /var/lib/puppet/ssl/certs/ca.pem
    SSLCACertificateFile    /var/lib/puppet/ssl/certs/ca.pem
    # CRL checking should be enabled; if you have problems with Apache complaining about the CRL, disable the next line
    SSLCARevocationFile     /var/lib/puppet/ssl/ca/ca_crl.pem
    SSLVerifyClient optional
    SSLVerifyDepth  1
    SSLOptions +StdEnvVars

    # The following client headers allow the same configuration to work with Pound.
    RequestHeader set X-SSL-Subject %{SSL_CLIENT_S_DN}e
    RequestHeader set X-Client-DN %{SSL_CLIENT_S_DN}e
    RequestHeader set X-Client-Verify %{SSL_CLIENT_VERIFY}e

    PassengerHighPerformance on # DO NOT USE Global config!!(disable mod_rewrite)
    RackAutoDetect On
    RackBaseURI /

    DocumentRoot /usr/share/puppet/rack/puppetmasterd/public/
    CustomLog /puppet/logs/puppet_access_log combined
    ErrorLog /puppet/logs/puppet_error_log

    <Directory /usr/share/puppet/rack/puppetmasterd/>
        Options None
        AllowOverride None
        Order Allow,Deny
        Allow from all
    </Directory>
</VirtualHost>

後はApacheを起動するだけです。

動作確認

クライアントから、puppetd等でアクセスするとpassengerはpuppetmasterのインスタンスを起動し通常通りpuppetmasterにアクセスできるようになります。

$ sudo /usr/sbin/puppetd --verbose --no-daemonize --onetime --noop

サーバで下記のコマンドを実行すると、passengerがpuppetmasterを起動していることを確認できます。

$ sudo passenger-status 
----------- General information -----------
max      = 15
count    = 1
active   = 1
inactive = 0
Waiting on global queue: 0

----------- Domains -----------
/usr/share/puppet/rack/puppetmasterd: 
  PID: 8897    Sessions: 1    Processed: 1       Uptime: 12s

Tips

通常の/etc/init.d/puppetmasterdスクリプトを使用した方法では、/etc/sysconfig/puppetmasterの内容をデーモン実行時のコマンドライン引数として読み込めたのですが、この方法でも同じことが可能です。

config.ruに記述することで実現できます。

# config.ru
# a config.ru, for use with every rack-compatible webserver.
# SSL needs to be handled outside this, though.

# if puppet is not in your RUBYLIB:
# $:.unshift('/opt/puppet/lib')

$0 = "puppetmasterd"
require 'puppet'

# if you want debugging:
# ARGV << "--debug"

ARGV << "--rack"
ARGV << "--confdir=/puppet/etc"
ARGV << "--logdest=/var/log/puppet/puppetmaster.log"

require 'puppet/application/puppetmasterd'
# we're usually running inside a Rack::Builder.new {} block,
# therefore we need to call run *here*.
run Puppet::Application[:puppetmasterd].run

上記の通り、ARGV変数に追加したいオプションを記述するだけです。

終わりに

Passengerを使用することにより、悩みどころだった大規模サイトでのpuppet運用がこれで可能になります。
''passenger-status''や''sudo passenger-memory-stats''を使うことによりモニタリングが可能ですし、
Passengerのチューニング可能でApacheの設定に記述するだけなので、手軽に運用できると思います。