RedmineをCentOS 6上で動かすーUnicornとNginx編¶
- 目次
- RedmineをCentOS 6上で動かすーUnicornとNginx編
はじめに¶
RedmineをCentOS 6上で動かすためのセットアップメモです。
Ruby on Railsアプリケーションを実行するアプリケーションサーバーとしてUnicorn、WebサーバーとしてNginxを組み合わせた環境を構築します。
まず、動作環境を述べます。次にRedmineを動かすのに必要となるRubyおよびMySQL(MariaDB)のインストールを行います。そして、Redmine(本体)のインストールとRedmine組み込みのWEBrickでの確認を行います。それからUnicornのセットアップと確認を行います。最後にNginxのセットアップと確認を行います。
動作環境¶
ハードウェア構成¶
AMD A10-6800K CPUと16GBメモリのPC上の仮想化ゲスト上で動かします。
ホストのハードウェア仕様は自作PC-F2A85Vを参照。
ゲストの(仮想)ハードウェアの仕様は次のとおりです。
CPUとメモリは、動かしながら様子を見て増加させていくため、初期は少ない値としています。
項目 | 内容 | 備考 |
---|---|---|
仮想化ホストOS | CentOS 6.5 64bit版 | |
仮想化ソフトウェア | OS標準搭載KVM | |
仮想CPU数 | 1 | 必要に応じて順次増加 |
メモリ | |
必要に応じて順次増加 |
ディスクイメージ | qcow2 | 場合によってRAW(スパースなし)に変更 |
ファイルシステム | ext4 |
ソフトウェア構成¶
項目 | 使用ソフトウェア | 備考 |
---|---|---|
OS | CentOS 6.5 64bit版 | |
Redmine | Redmine 2.5.1 | |
Ruby | Ruby 2.1.2 | CentOS 6標準の1.8.7は性能的に厳しいので最新版に差し替え |
RDBMS | MariaDB 5.5 | CentOS 6標準のMySQL 5.1は古いので、CentOS 7で標準搭載のMariaDBに差し替え |
Rackサーバー | Unicorn | |
Webサーバー | Nginx 1.6.0 | |
rubyのバージョンについて¶
Redmine公式ページのインストールガイド には、サポートしているrubyのバージョンが次のように記載されています。
ruby 1.8.7, 1.9.2, 1.9.3, 2.0.0, jruby-1.7.6
最新版を使うときはオウンリスクでとなります。
ruby 2.1.1は互換性を損なう変更(Hash#reject の不具合)があり、Railsアプリケーションが影響を受けるので使用しません。
CentOS 6の必要なパッケージをインストール¶
Redmineをインストールし動かすにあたり必要となるCentOS 6パッケージをインストールします。
Rubyのインストール¶
CentOS 6に標準搭載されるRubyはバージョンが1.8.7とRedmineの動作条件には辛うじて含まれるものの古いためパフォーマンスに難があります。そこで、Rubyの新しいバージョン2.1.2に差し替えます。
Ruby 2.1.2のCentOS 6用RPMパッケージを作成しインストールします。CentOS 6用にRubyのRPMを作成する方法については次を参照ください。作成したRPMパッケージは本プロジェクトの[ファイル]に添付しています。EPELリポジトリを参照する設定をyumに追加¶
~$ sudo rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
ruby 2.1.2のインストール¶
上述で作成したRPMパッケージをマシン上に持ってきてyum localinstallコマンドでインストールしました。
~$ sudo yum localinstall ruby-2.1.2-1.el6.x86_64.rpm
- 既にrubyパッケージがインストールされていると、うまくアップデートできないかもしれません。そのときは一旦古いrubyをアンインストールしてから新しいrubyをインストールします。
その他パッケージのインストール¶
CentOS 6のyumリポジトリおよびEPELリポジトリから必要なパッケージをインストールします。
$ sudo yum groupinstall "Development Tools" : $ sudo yum install openssl-devel readline-devel zlib-devel curl-devel libyaml-devel : $ sudo yum install ImageMagick ImageMagick-devel :
Redmineのセットアップ¶
インストール方針¶
Redmineは、基本的にはデータベースアプリケーションです。データベースはデータが蓄積されるにつれパフォーマンスが低下していきます。逆に初期の空っぽに近い状態では遅いデータベース(SQLite)を使っていても性能差を体感することはありません。なので、安直に試していいと思って運用を開始してしまうと、長く運用され蓄積が増えていった将来にデータベースの性能で泣かされかねません。ここはしっかり構築しておきたい点です。
また、RedmineのプログラムはRubyですが、これはメモリをけっこう喰いますので、メモリを十分用意しておくのが大切です。運用を始めてまだそれほどデータが蓄積されていないのに異様に重い、応答に時間がかかる、といった場合、物理メモリが欠乏してスワップに入っていることがよくあります。経験的には、物理メモリ2GBでは頻繁にスワップに陥り、3GBで時々発生、4GBではたまに発生、といった感じでしょうか。大規模に使うともっと多く必要かと思います。
MariaDBのインストール¶
Redmineがサポートしているデータベースは、MySQL 5.0以降、PostgreSQL 8.2以降、Microsoft SQLServer 2008以降、SLQite 3です。
この中でMySQLはRedmineとの連携の実績も多く、チューニングをはじめとした情報が豊富です。CentOS 6は標準でMySQL 5.1を搭載していますが、今ではちょっと(大分)古くなっています。新しいバージョンのMySQL 5.6を使おうかと思っていましたが、先日リリースされたRed Hat Enterprise Linux 7ではMySQL 5.5からフォークしたMaria DB 5.5が標準搭載されているので、今回はMariaDB 5.5を使うことにします。いずれCentOS 7にしたときはMariaDB 5.5を使うことになりますので。
yumリポジトリにMariaDBを追加しMariaDBパッケージをインストール¶
MariaDBはCentOS 6向けにyumリポジトリを提供しているので、これを追加します。
https://downloads.mariadb.org/mariadb/repositories/
このページから、OS(Linuxディストリビューション)にCentOS、リリースにCentOS 6(64bit)、MariaDBのバージョンに5.5を選択すると、yumリポジトリ設定内容が表示されます。これをファイルに写して作成します。
- /etc/yum.repos.d/MariaDB.repo
# MariaDB 5.5 CentOS repository list - created 2014-06-26 11:57 UTC # http://mariadb.org/mariadb/repositories/ [mariadb] name = MariaDB baseurl = http://yum.mariadb.org/5.5/centos6-amd64 gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1
~$ sudo yum install MariaDB-server MariaDB-devel
MariaDB設定¶
設定ファイルは、/etc/my.cnfではなく、/etc/my.cnf.d/mysql-clients.cnfと/etc/my.cnf.d/server.cnfとに分けて記述します。/etc/my.cnfもありますが、ここには/etc/my.cnf.d(の下にあるファイル)をインクルードする指示が書かれています。
まずはテーブルの言語がlatin1にならないようにutf8設定を追加¶
- /etc/my.cnf.d/server.cnf
[mysqld] character-set-server = utf8
- /etc/my.cnf.d/mysql-clients.cnf
[mysql] default-character-set = utf8 show-warnings
MariaDBの起動¶
MariaDBパッケージをインストールすると、service名はmysqlで登録されます。chkconfigで自動起動設定済みです。
~$ sudo service mysql start Starting MySQL.. SUCCESS! ~$
軽く動作確認メモ¶
status内容¶
statusの実行結果を次に示します。
MariaDB [(none)]> status -------------- mysql Ver 15.1 Distrib 5.5.38-MariaDB, for Linux (x86_64) using readline 5.1 Connection id: 3 Current database: Current user: root@localhost SSL: Not in use Current pager: stdout Using outfile: '' Using delimiter: ; Server: MariaDB Server version: 5.5.38-MariaDB MariaDB Server Protocol version: 10 Connection: Localhost via UNIX socket Server characterset: utf8 Db characterset: utf8 Client characterset: utf8 Conn. characterset: utf8 UNIX socket: /var/lib/mysql/mysql.sock Uptime: 8 min 30 sec Threads: 2 Questions: 53 Slow queries: 0 Opens: 17 Flush tables: 2 Open tables: 42 Queries per second avg: 0.103 -------------- MariaDB [(none)]>
デフォルトのデータベースエンジンを調べる¶
show enginesの実行結果を次に示します。
MariaDB [none]> show engines; +--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+ | Engine | Support | Comment | Transactions | XA | Savepoints | +--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+ | CSV | YES | CSV storage engine | NO | NO | NO | | MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO | | MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO | | BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO | | MyISAM | YES | MyISAM storage engine | NO | NO | NO | | InnoDB | DEFAULT | Percona-XtraDB, Supports transactions, row-level locking, and foreign keys | YES | YES | YES | | ARCHIVE | YES | Archive storage engine | NO | NO | NO | | FEDERATED | YES | FederatedX pluggable storage engine | YES | NO | YES | | PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO | | Aria | YES | Crash-safe tables with MyISAM heritage | NO | NO | NO | +--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+ 10 rows in set (0.00 sec)
パラメータの一覧とデフォルト値¶
~$ mysqld --verbose --help
結果は長いのでほんの一部だけ抜粋しますが、コマンドラインでのパラメータ指定方法、現在の設定値が一覧表示されます。
character-set-client-handshake TRUE collation-server utf8_general_ci connect-timeout 10 datadir /var/lib/mysql/ default-storage-engine InnoDB innodb-additional-mem-pool-size 8388608 innodb-buffer-pool-size 134217728 innodb-flush-method (No default value) innodb-log-buffer-size 8388608 innodb-log-file-size 5242880 innodb-log-files-in-group 2
MariaDB接続ユーザー"root"のパスワード設定¶
インストール直後はMariaDBのrootユーザーにパスワードが設定されていません。userテーブルでデフォルトで作成されているユーザーとホスト、パスワードを見てみます。
インストール直後のuserテーブルの内容を次に示します。
$ mysql -uroot Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 5 Server version: 5.5.38-MariaDB MariaDB Server Copyright (c) 2000, 2014, Oracle, Monty Program Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> SET PASSWORD FOR root@localhost=PASSWORD('mypassword'); Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> SELECT user,host,password FROM mysql.user; +------+-----------+----------+ | user | host | password | +------+-----------+----------+ | root | localhost | | | root | nostrum | | | root | 127.0.0.1 | | | root | ::1 | | | | localhost | | | | nostrum | | +------+-----------+----------+ 6 rows in set (0.00 sec) MariaDB [(none)]>
MariaDBは、ユーザーとホストの組み合わせで権限制御が行われます。
rootユーザーが4レコードありますが、これはMySQLにどう接続してくるかによって使い分けられます。
localhostと127.0.0.1は同じように思いますが異なります。localhostはUNIXソケット、127.0.0.1はTCP/IPの接続になるらしいです。::1はTCP/IPv6です。
userが空なのは匿名ユーザーです。
まず、rootユーザー4レコードにパスワードを設定します。
MariaDB [(none)]> UPDATE mysql.user SET password = PASSWORD('mypassword') WHERE user = 'root'; Query OK, 4 rows affected (0.00 sec) Rows matched: 4 Changed: 4 Warnings: 0 MariaDB [(none)]> SELECT user,host,password FROM mysql.user; +------+-----------+-------------------------------------------+ | user | host | password | +------+-----------+-------------------------------------------+ | root | localhost | *FABE5482D5AADF36D028AC443D117BE1180B9725 | | root | nostrum | *FABE5482D5AADF36D028AC443D117BE1180B9725 | | root | 127.0.0.1 | *FABE5482D5AADF36D028AC443D117BE1180B9725 | | root | ::1 | *FABE5482D5AADF36D028AC443D117BE1180B9725 | | | localhost | | | | nostrum | | +------+-----------+-------------------------------------------+ 6 rows in set (0.00 sec) MariaDB [(none)]> FLUSH PRIVILEGES; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]>
Redmine本体のインストール¶
RedmineはRedmineを実行するためには、Redmine本体のほかにRedminが使用している各種Rubyモジュール(ライブラリ集、rubyではgemパッケージと呼ぶ)が必要です。Ruby on RailsもRubyモジュールです。Rubyモジュールは、bundlerという仕組みを使ってインストールします。
Rubyモジュールは、システム共通の場所に入れるかRedmine固有の場所に入れるかの選択肢がありますが、トラブルを避けるためRedmine固有の場所にインストールします。
Redmine本体の入手と展開¶
Redmine公式サイトのダウンロードページ より最新安定版(Latest stable releases)をダウンロードします。2014-06-28時点でVer.2.5.1が最新です。
ダウンロードしたRedmine本体を展開します。インストールディレクトリは/var/lib/の下にredmine-<バージョン番号>となるよう展開し、シンボリックリンクファイル/var/lib/redmineを使用するredmineのディレクトリを指すように作成します。
~$ cd /var/lib lib$ sudo tar xzf ~/install/redmine-2.5.1.tar.gz lib$ sudo ln -s redmine-2.5.1 redmine lib$ ls -l : lrwxrwxrwx. 1 root root 13 6月 27 21:04 2014 redmine -> redmine-2.5.1 drwxrwxr-x. 16 1000 1000 4096 3月 30 01:56 2014 redmine-2.5.1 :
Redmineのデータベース設定¶
/var/lib/redmine/config/database.ymlを作成します。Redmineにはサンプルとしてdatabase.yml.sampleが含まれているので、このサンプルからMySQL用の設定を抜き出し修正するとよいでしょう。
production:
adapter: mysql2
database: redmine
host: localhost
username: redmine
password: mypassword
encoding: utf8
- サンプルにはproduction以外にdevelopment、testの設定がありますが、通常productionのみ使用するので設定はproductionだけ記述します。
- adapterはMariaDB(MySQL)5.5の場合はmysql2を指定します。
- databaseは、MariaDB上でRedmineのテーブルを収容するデータベース名を指定します。ここで指定した名称のデータベースをMariaDB上に作成します。
- encodingはMariaDBの設定に合わせてutf8とします。
~$ mysql -uroot -p Enter password: MariaDB [(none)]> CREATE DATABASE redmine; Query OK, 1 row affected (0.00 sec) MariaDB [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | redmine | | test | +--------------------+ 5 rows in set (0.00 sec) MariaDB [(none)]>
- hostは、Redmineから使用するMariaDBが動いているホストを指定します。通常同じマシン上でRedmineとMariaDBを動かすのでUNIXソケットを使うlocalhostとします。
- usernameとpasswordは、RedmineからMariaDBに接続するときに使用するMariaDBのユーザー・パスワードです。ここで指定したユーザー・パスワードをMariaDBに作成し、先に作成したredmineデータベースの管理権限を付与します。
MariaDB [(none)]> GRANT ALL ON redmine.* TO 'redmine'@'localhost' IDENTIFIED BY 'mypassword' WITH GRANT OPTION; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]>
- ALLはALL PRIVILEGESと同義です。UNIXソケットを使って接続するのでホスト名はlocalhostとしています。WITH GRANT OPTIONを指定するとそのユーザーが持つ権限範囲以内の権限を他のユーザーに付与できます。
メール設定¶
/var/lib/redmine/config/configuration.ymlを作成します。Redmineにはサンプルとしてconfiguration.yml.sampleが含まれているので、このサンプルから設定を抜き出し修正するとよいでしょう。
今回はメールサーバーをローカルとして使用します。
# Simple SMTP server at localhost
production:
email_delivery:
delivery_method: :smtp
smtp_settings:
address: "localhost"
port: 25
Rubyモジュール群のインストール¶
Redmine本体が依存するRubyモジュール群をインストールします。Rubyモジュールのインストールには、rubyのbundlerを使用します。
bundlerのインストール¶
bundlerもRubyモジュール(gemパッケージ)です。これはシステム共通場所にインストールします。
システム共通にインストールされているgemパッケージを一覧します。
~$ gem list *** LOCAL GEMS *** bigdecimal (1.2.4) io-console (0.4.2) json (1.8.1) minitest (4.7.5) psych (2.0.5) rake (10.1.0) rdoc (4.1.0) test-unit (2.1.2.0) ~$
bundlerはないので、インストールします。
~$ sudo gem install bundler --no-rdoc --no-ri Fetching: bundler-1.6.3.gem (100%) Successfully installed bundler-1.6.3 1 gem installed ~$
bundlerモジュールのドキュメントをローカルでは参照しないので--no-rdocと--no-riを指定しました。
これでbundlerを使用できるようになったので、Redmineが必要とするRubyパッケージ群をインストールします。
Redmineが依存するRubyパッケージ群のインストール¶
Redmineが依存するRubyパッケージは、Redmineのインストールディレクトリ下のvender/bundlerを指定し、そこへインストールします。
~$ cd /var/lib/redmine-2.5.1 redmine-2.5.1$ sudo bundle install --path vendor/bundler --without development test :
Redmineの初期化¶
Redmine本体および依存するRubyモジュールのインストールが終わったら、Redmineの初期化を行います。
セッションデータ暗号化の鍵生成¶
改ざん防止のため、セッションデータを格納するクッキーを暗号化する鍵をランダムに生成します。
redmine-2.5.1$ sudo bundle exec rake generate_secret_token
- 注記)インストール手順書等でrake xxx となっているコマンドは、Rubyモジュール群をRedmine固有のディレクトリにインストールした場合は、bundle exec rake xxx のようにbundle execをつけて実行する必要があります。
データベースのスキーマを構築¶
Redmineが使用するデータベースにスキーマを構築します。
redmine-2.5.1$ sudo bundle exec rake db:migrate RAILS_ENV=production :
MariaDBに入ってテーブル一覧を確認します。
~$ mysql -uredmine -p Enter password: MariaDB [(none)]> use redmine Database changed MariaDB [redmine]> show tables; +-------------------------------------+ | Tables_in_redmine | +-------------------------------------+ | attachments | | auth_sources | | boards | | changes | | changeset_parents | | changesets | | changesets_issues | | comments | | custom_fields | | custom_fields_projects | | custom_fields_roles | | custom_fields_trackers | | custom_values | | documents | | enabled_modules | | enumerations | | groups_users | | issue_categories | | issue_relations | | issue_statuses | | issues | | journal_details | | journals | | member_roles | | members | | messages | | news | | open_id_authentication_associations | | open_id_authentication_nonces | | projects | | projects_trackers | | queries | | queries_roles | | repositories | | roles | | schema_migrations | | settings | | time_entries | | tokens | | trackers | | user_preferences | | users | | versions | | watchers | | wiki_content_versions | | wiki_contents | | wiki_pages | | wiki_redirects | | wikis | | workflows | +-------------------------------------+ 50 rows in set (0.00 sec) MariaDB [(none)]>
Redmine内蔵WebサーバーWEBrickによる動作確認¶
Redmineには内蔵のWebサーバーWEBrickがあるので、Redmine単独での起動確認をWEBrickで行います。
なお、WEBrickは開発・テスト用であり、運用には耐えられません。
まず、iptablesを停止しファイアウォールの影響を除外します。
redmine-2.5.1$ sudo service iptables stop iptables: チェインをポリシー ACCEPT へ設定中filter [ OK ] iptables: ファイアウォールルールを消去中: [ OK ] iptables: モジュールを取り外し中: [ OK ]
WEBrickを実行します。
redmine-2.5.1$ sudo ruby script/rails server webrick -e production => Booting WEBrick => Rails 3.2.17 application starting in production on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server [2014-06-28 03:22:21] INFO WEBrick 1.3.1 [2014-06-28 03:22:21] INFO ruby 2.1.2 (2014-05-08) [x86_64-linux-gnu] [2014-06-28 03:22:21] INFO WEBrick::HTTPServer#start: pid=4957 port=3000
Webブラウザを立ち上げ、Redmineを動かしているマシンにポート3000でアクセスします。
うまくいっていれば、WebブラウザにRedmineの画面が表示され、WEBrickを起動したコンソールにアクセスメッセージが表示されます。
Started GET "/" for 192.168.1.38 at 2014-06-28 03:23:20 +0900 Processing by WelcomeController#index as HTML Current user: anonymous Rendered welcome/index.html.erb within layouts/base (41.7ms) Completed 200 OK in 186.0ms (Views: 67.7ms | ActiveRecord: 21.8ms)
WEBrickを停止します。WEBrickを起動したコンソールでCtrl-Cを入力します。
^C[2014-06-28 03:24:09] INFO going to shutdown ... [2014-06-28 03:24:09] INFO WEBrick::HTTPServer#start done. Exiting redmine-2.5.1$
Unicornのセットアップ¶
Rubyアプリケーションを動かすアプリケーションサーバー(Rackサーバー)のUnicornをセットアップします。
Unicornのインストール¶
UnicornはRubyモジュール(gem)として提供されるので、bundlerでインストールします。
Redmineをインストールしたディレクトリ下(例:/var/lib/redmine-2.5.1)に、Gemfile.localというファイルを作成し、そこに以下を記述します。
gem "unicorn"
Redmineをインストールしたディレクトリで bundle update を実行します。
redmine-2.5.1$ sudo bundle update Fetching gem metadata from https://rubygems.org/......... Fetching additional metadata from https://rubygems.org/.. Resolving dependencies... Using rake 10.1.1 Using i18n 0.6.9 : Installing kgio 2.9.2 Using mysql2 0.3.16 Using net-ldap 0.3.1 Using ruby-openid 2.3.0 Using rack-openid 1.4.2 Using rails 3.2.17 Installing raindrops 0.13.0 Using redcarpet 2.3.0 Using rmagick 2.13.2 Installing unicorn 4.8.3 Your bundle is updated! Gems in the groups development and test were not installed. redmine-2.5.1$
インストール後の単独起動確認¶
コマンドラインからUnicornを起動してRedmineの動作を確認します。
ipdtablesサービスが稼動していたら一旦停止させておきます。
redmine-2.5.1$ sudo bundle exec unicorn_rails -l 8081 -E production I, [2014-06-28T13:57:45.681407 #1692] INFO -- : listening on addr=0.0.0.0:8081 fd=9 I, [2014-06-28T13:57:45.681687 #1692] INFO -- : worker=0 spawning... I, [2014-06-28T13:57:45.682839 #1692] INFO -- : master process ready I, [2014-06-28T13:57:45.684321 #1695] INFO -- : worker=0 spawned pid=1695 I, [2014-06-28T13:57:45.684552 #1695] INFO -- : Refreshing Gem list I, [2014-06-28T13:57:50.476651 #1695] INFO -- : worker=0 ready
これでWebブラウザからポート8081で接続し動作確認をします。
コマンドラインオプションは次です。
--listen -l [アドレス:]ポート ソケットのエンドポイントを指定 --config-file -c ファイル 設定ファイルを指定 -D デーモンプロセス起動指定 -E <RAILS_ENV> production等を指定
Unicornプロセスに対する制御¶
ちょっと難しいのがUnicornのプロセス制御です。Unicornは、マスタープロセス1つにワーカープロセスが複数という構成です。
終了方法¶
- フォアグラウンドプロセスとして起動した場合、Ctrl-Cで停止します。
- デーモンプロセスとして起動した場合、シグナルINT(強制終了)またはQUIT(グレースフル停止)をマスタープロセスに送ります。
- シグナルINT: ワーカープロセスを即終了させて自らも終了
- シグナルQUIT: ワーカープロセスがリクエストの処理を終えるまで待って終了
- そのほか
- シグナルWINCH: ワーカープロセスをグレースフルに停止しますが自らは終了しません
- シグナルTTIN: ワーカープロセスを1つ増やします
- シグナルTTOU: ワーカープロセスを1つ減らします
再起動方法¶
デーモンプロセスに対する設定ファイル再読み込みトリガーはシグナルHUPをマスタープロセスに送ります。このとき、preload_appがfalseだとアプリケーションプログラムも再読み込みされますが、preload_appがtrueだと再読み込みされません。
シグナルUSR2を使うと、古いマスタープロセスは新しいプロセスを作ってソケットを引継ぎます。古いプロセスはそのまま残っています。pidファイルは新プロセスの値に書き換えられます。古いpidファイルは.oldbinの拡張子が付いたファイルに変更されます。preload_appがtrueのときにアプリケーションプログラムを再読み込みするにはこのシグナルUSR2を使います。
シグナルUSR2を送っただけでは古いマスタープロセスとその配下のワーカープロセスは終了しないので、シグナルUSR2を送ったあとに古いマスタープロセスに対してシグナルQUITを送るとよいのかと思います。
実験:usr2で3つ以上のマスタープロセスは起動しない¶
最初にデーモン起動し、シグナルUSR2を送ると新しいマスタープロセスとそのワーカープロセス群が生成されました。
続いて新しいマスタープロセスにシグナルUSR2を送ってもさらに新しいマスタープロセスは生成されませんでした。
古いマスタープロセスをシグナルINTを送って終了させたあと、残ったマスタープロセスにシグナルUSR2を送ったところ、さらに新しいマスタープロセスとワーカープロセスが生成されました。
マスタープロセスのプロセスIDを調べる¶
次のように調べます。
$ pgrep -f 'unicorn_rails master' 3783 $
Unicornの設定¶
Redmineインストールディレクトリ下のconfigディレクトリに、unicorn.rbというファイル名で設定を記述します。
Unicorn起動時にオプションで設定ファイルを指定します。
公式サイトの解説ページ(次のURL)
http://unicorn.bogomips.org/Unicorn/Configurator.html
Redmine用Unicorn設定例¶
自宅サイトで検証中のunicorn.rbを添付します。Unicornのワーカープロセスをroot権限ではなくredmineユーザー権限で動かすように設定を記述しています。
unicorn.rb
この設定ファイルを使う場合は、CentOS上でユーザーredmineを作成しておきます。
~$ sudo useradd redmine
Redmine以下のディレクトリ・ファイルの所有者をredmineユーザーに変更します。
~$ cd /var/lib/redmine-2.5.1 redmine-2.5.1$ sudo chown -R redmine.redmine .
Unicornの設定項目メモ¶
unicorn.rbの設定内容についてのメモです。
worker_processes¶
応答性を良好に保つには、コア数以上のワーカーを指定します。ただし、仮想化環境ではCPU使用率とメモリ使用量を見ながらワーカー数を許容範囲まで増やします。
listen¶
リクエストを受け付けるプロトコルとポート、オプション設定を指定します。
UNIXドメインソケットの場合の例
listen "/tmp/unicorn_redmine.sock", :backlog => 64
TCPソケットの場合の例
listen 8080, :tcp_nopush => true
- 複数のプロトコルを列挙することで複数のプロトコル・ポートを扱うことができます。
- backlogは、workerが作業中でもコネクションのリクエストを受理して待機しておくことができる個数で、デフォルトは1024です。例えば1件平均30msで捌く処理に対して1000個バックログによる待ちがあると、新たにリクエストした処理は結果が返るまで30秒間待たされることになります。それだったらコネクションを受け付けずにエラーにした方がよいということがあります。参考までに自宅で運用しているRedmineのログからCompleted行にある処理時間の平均は約100msでした。
- tcp_nopushは、TCP_CORK(Linux)を制御します。デフォルトはfalseです。trueにすると、TCPフレームの断片が小出しに送られることを抑止するので、リモートにあるNginxのタスクを早めに起こさずにすませます。
timeout¶
workerがこの秒数以上処理に費やすとプロセスを落とします。デフォルトは60秒です。大抵の処理はずっと短いので60秒は大きすぎる値ですが、中に時間のかかる処理があれば処理時間に応じて値を増やします。
Redmineでは、大きなサイズの添付ファイルのアップロード・ダウンロードが該当します。Redmineの添付ファイルサイズ上限のファイルを実際にアップロード・ダウンロードさせてかかる時間を計測し、それを許容できる処理時間を設定します。
ここで設定するunicornのタイムアウト値とNginxのタイムアウト値が不整合だとかなり怪しい挙動となりますので、両者のタイムアウト値を整合させるようにしてください(unicornのタイムアウト値+αをnginxのタイムアウト値にする、αは1ないし2秒程度、等)。
pid¶
unicornを起動したときにそのプロセスIDを記録しておくファイルを指定します。
例を次に示します。
pid "tmp/pids/unicorn.pid"
stderr_path、stdout_path¶
Redmineインストールディレクトリ下のlogディレクトリの中にログファイルを生成します。
stderr_path 'log/unicorn.stderr.log' stdout_path 'log/unicorn.stdout.log'
preload_app¶
trueに設定すると、マスタープロセス起動時にアプリケーションをロードし、ワーカープロセスをフォークするとアプリケーションが実行可能となります。複数ワーカープロセスでコードを共有するため、メモリ使用効率もよくなります。デメリットは、ワーカープロセスを再起動してもアプリケーションはロードされない点です。
before_fork¶
ワーカープロセスをforkする前にマスタープロセスによって呼ばれます。
after_fork¶
ワーカープロセスがforkされた後に呼び出されます。
ENV["HOME"]¶
rootユーザーで稼動するマスタープロセスがredmineユーザーで稼動するワーカープロセスを生成したときに、環境変数HOMEはrootユーザーのままとなっています。この状況でRedmineでsubversionを使用していると、次のエラーメッセージが多数出力されます。
svn: 警告: ファイル '/root/.subversion/servers' を開けません: 許可がありません
そこで、after_forkの処理ブロックの中に環境変数HOMEをredmineユーザーのホームディレクトリを指定する記述を入れます。
参考にしたブログ
Unicornのサービス化(起動終了制御)¶
Unicornの起動・終了をCentOSのサービスとして管理できるようにします。
/etc/init.dの下にサービス制御ファイルunicornを作成します。
unicornサービスファイル例¶
インターネット上で見つけたunicornサービスファイルです。本ページに添付しています。コマンド | 内容 |
---|---|
start | unicorn起動 |
stop | シグナルQUIT送信 |
force-stop | シグナルTERM送信 |
restart | シグナルUSR2送信し、5秒待って古いマスタープロセスにシグナルQUIT送信 |
reload | |
upgrade | シグナルUSR2送信 |
rotate | シグナルUSR1送信 |
ファイルの配置とサービスへの登録¶
~$ sudo cp unicorn /etc/init.d ~$ sudo chkconfig -add unicorn ~$ sudo chkconfig unicorn on
Redmineアプリケーションパスの設定¶
/etc/unicorn/redmine.conf
RAILS_ENV=production RAILS_ROOT=/var/lib/redmine
シンボリックリンク /var/lib/redmine を作成します。
~$ link -s /var/lib/redmine-2.5.1 /var/lib/redmine
サービスの起動¶
~$ sudo service unicorn start /var/lib/redmine: Starting ~$ ps aux|grep [u]nicorn |awk '{print $1, $2, $11, $12}' root 2506 unicorn_rails master redmine 2511 unicorn_rails worker[0] redmine 2513 unicorn_rails worker[1] redmine 2516 unicorn_rails worker[2] ~$
Webブラウザから、ポート8282に接続して確認します。
ファイアウォール(iptables)が稼動していると通らないので、一時停止しておきます。
サービスの終了¶
~$ sudo service unicorn stop /var/lib/redmine: Stopping ~$ ps aux|grep [u]nicorn |awk '{print $1, $2, $11, $12}' ~$
サービスの再起動¶
~$ sudo service unicorn start /var/lib/redmine: Starting ~$ ps aux|grep [u]nicorn |awk '{print $1, $2, $11, $12}' root 2548 unicorn_rails master redmine 2553 unicorn_rails worker[0] redmine 2555 unicorn_rails worker[1] redmine 2558 unicorn_rails worker[2] ~$ sudo service unicorn restart /var/lib/redmine: Killing old master 2548 ~$ ps aux|grep [u]nicorn |awk '{print $1, $2, $11, $12}' root 2574 unicorn_rails master redmine 2580 unicorn_rails worker[0] redmine 2582 unicorn_rails worker[1] redmine 2585 unicorn_rails worker[2]
Nginxのセットアップ¶
WebサーバーのNginxをセットアップします。
Nginx公式ページ(日本語)
CentOS 6向けには、EPELリポジトリにNginx 1.0のRPMが置かれています。2014-06現在の最新版は1.6なのでかなりの年代物といえます。最新版はNginx公式サイトのリポジトリでRPMが提供されています。今回はNginxの公式サイトで提供される安定版の最新版である1.6をインストールすることにします。
標準のhttpd(Apache)を停止させるかデフォルトポート番号を80以外に変更¶
今回はRedmineのアクセスで使うNginxを80ポートで使用します。そこで、CentOS 6のhttpd(Apache)が80ポートで動かないように、httpdをサービス起動から除外する、アンインストールする、あるいはhttpdのポート番号を80以外に変更するかの処置をしておきます。
- httpdをアンインストールする
~$ sudo yum erase httpd
- httpdをサービス起動から除外する
~$ sudo chkconfig -del httpd
- httpdのポート番号を80以外に変更する
/etc/httpd/conf/httpd.confServerName www.torutk.com:8086 Listen 8086
yumリポジトリにNginxを追加しNginxパッケージをインストール¶
NginxはCentOS 6向けにyumリポジトリを提供しているので、これを追加します。
Pre-Build Packages for Stable version
このページの"CentOS 6"のリンクをコピーし、以下のように実行します。
~$ sudo rpm -ivh http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm
すると、/etc/yum.repos.d/nginx.repoが追加されました。内容は次のとおりです。
# nginx.repo [nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/6/$basearch/ gpgcheck=0 enabled=1
nginxをインストールします。
~$ sudo yum install nginx
インストールされたファイルは次のとおりです。
~$ rpm -ql nginx /etc/logrotate.d/nginx /etc/nginx /etc/nginx/conf.d /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/example_ssl.conf /etc/nginx/fastcgi_params /etc/nginx/koi-utf /etc/nginx/koi-win /etc/nginx/mime.types /etc/nginx/nginx.conf /etc/nginx/scgi_params /etc/nginx/uwsgi_params /etc/nginx/win-utf /etc/rc.d/init.d/nginx /etc/sysconfig/nginx /usr/sbin/nginx /usr/share/nginx /usr/share/nginx/html /usr/share/nginx/html/50x.html /usr/share/nginx/html/index.html /var/cache/nginx /var/log/nginx ~$
インストール完了時点で、サービスがchkconfigに登録されています。
~$ chkconfig --list nginx nginx 0:off 1:off 2:on 3:on 4:on 5:on 6:off ~$
Nginxの設定¶
Nginxの設定は、/etc/nginx/nginx.conf と、そこからインクルードしている/etc/nginx/conf.d/*.conf とから成ります。
デフォルトのnginx.conf¶
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; }
- worker_processesは1ですが、1つのワーカープロセスでworker_connectionsに定義されている数(ここでは1024)までのリクエストを扱えるので、十分かもしれません。
デフォルトのdefault.conf¶
インストール時に /etc/nginx/conf.d/default.conf が置かれています。
server { listen 80; server_name localhost; #charset koi8-r; #access_log /var/log/nginx/log/host.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }
ポート80でデフォルトのサーバーが定義されています。Redmineでポート80を使用するので、このファイルを削除またはリネームしておきます。
~$ sudo mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.orig
Redmine用の設定ファイル¶
/etc/nginx/conf.d/redmine.conf を新規作成します。
本ページに添付しています。
redmine.conf
upstream unicorn-redmine { server unix:/tmp/unicorn_redmine.sock; }
- リバースプロキシの上流サイトとしてUnicornを指定します。同一マシン上でUnicornとNginxを動かす場合は、UNIXドメインソケットで接続可能です。Unicornで指定したUNIXドメインソケットのパスを指定します。
server { listen 80; server_name www.torutk.com;
- ポート番号 80 で受け入れるようにします。サーバー名はDNS名を指定しました。
root /var/lib/redmine/public;
- Redmineの静的コンテンツのルートディレクトリを指定します。
client_max_body_size 640M;
- クライアントからのリクエストの本体サイズの最大値で、これを超えると413エラーを返します。デフォルトは1MBと小さいため、Redmineの添付ファイルのアップロードの最大サイズに合わせて大きくします。
location / { try_files $uri/index.html $uri.html $uri @app; }
- URIが/(ルート)で始まるもの(実質すべて)は、そのURIに対応するファイルがあるかを試し、あればそれを、なければ@app(後述)に処理を委譲します。
location @app { proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_connect_timeout 60; proxy_read_timeout 60; proxy_send_timeout 600; proxy_pass http://unicorn-redmine; }
- proxy_redirectは、上位サーバー(Unicorn)から受け取ったLocationおよびRefreshヘッダーの書き換えを抑止します。
- proxy_set_headerは、リバースプロキシ経由でクライアントのIPアドレスを上位サーバー(Unicorn)に渡すヘッダーに格納します。
- タイムアウトは長めにとっています(ファイルのアップロード・ダウンロード等に対応)
- proxy_passは、upstreamで定義した"unicorn-redmine"へプロキシします。
error_page 500 502 503 504 /500.html;
- 上位サーバー(Unicorn)がリクエストに対して応答できないときに、エラードキュメントを指定します。既にドキュメントルートに/var/lib/redmine/publicを指定しているので、/500.htmlはRedmineの500.htmlを指しています。
ファイアウォール(iptables)でポート80を許可する¶
動作確認時はファイアウォール(iptables)を停止させていましたが、本番稼動ではファイアウォールを動作させてポート80を許可する設定をしておきます。
現状のiptables内容を確認します。
~$ sudo iptables -vL --line Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 1309 111K ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED 2 0 0 ACCEPT icmp -- any any anywhere anywhere 3 0 0 ACCEPT all -- lo any anywhere anywhere 4 5 268 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:ssh 5 217 18374 REJECT all -- any any anywhere anywhere reject-with icmp-host-prohibited Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 REJECT all -- any any anywhere anywhere reject-with icmp-host-prohibited Chain OUTPUT (policy ACCEPT 1395 packets, 1114K bytes) num pkts bytes target prot opt in out source destination ~$
- 外部からの着信は、Chain INPUTのルールが適用されます。
- (1) セッション確立済みのパケット(ESTABLISHED)や確立済みプロトコルに関連したパケット(RELATED)の受信を許可
- (2) ICMPパケットの受信は許可
- (3) ループバックインタフェース(ローカルホスト)の受信は許可
- (4) TCPでポート22(ssh)宛の新規接続を許可
- (5) 以上に合致しないパケットの受信は拒絶
(4)のルールに倣って、TCPでポート80(http)宛の新規接続を許可を(5)の前に追加します。
~$ sudo iptables -I INPUT 5 -m state --state NEW -m tcp -p tcp --dport http -j ACCEPT ~$ sudo iptables -vnL --line Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 1684 136K ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 2 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 3 0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 4 5 268 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22 5 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:80 6 220 18947 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited Chain OUTPUT (policy ACCEPT 5 packets, 728 bytes) num pkts bytes target prot opt in out source destination
コマンドで追加しただけでは再起動時に反映されないので保存します。
~$ sudo service iptables save iptables: ファイアウォールのルールを /etc/sysconfig/iptable[ OK ]中: ~$
その他Nginxの設定¶
SSL設定¶
SELinuxの設定¶
あれ、SELinuxが有効(Enforcing)だがRedmineが動いている¶
そういえば、セットアップ作業を通じてSELinuxを制御していないのを思い出し、SELinuxの設定を確認してみました。
~$ getenforce Enforcing
お、Enforcingのままでも稼動しています。
SubversionおよびGitとの連携¶
SubversionおよびGitへのアクセスで使用するユーザー認証は、SubversionおよびGit側ではなくRedmineのユーザー認証でまかないます。その場合、SubversionおよびGitへのアクセスはapache httpサーバーが前提となります。
SubversionとRedmineの認証連携¶
Subversion 1.8のインストール¶
- CentOS 6でsubversionのバージョンを上げる
CentOS 6の標準搭載Subversionは、バージョンが1.6.11と今では古いので、バージョン1.8を別にインストールします。ここの記述に沿って、subversion、httpd、mod_dav_svnをインストールします。 - Subversion
Subversionのバージョンと機能については、ここにメモを記載しました。
Nginxがポート80を使用しているので、apacheは80以外のポートを使用します。
- /etc/httpd/conf/httpd.conf の修正
@@ -133,7 +133,7 @@ # prevent Apache from glomming onto all bound IP addresses (0.0.0.0) # #Listen 12.34.56.78:80 -Listen 80 +Listen 8086 # # Dynamic Shared Object (DSO) Support
SELinuxが有効(Enforced)のときは、ポート番号を変更した後httpdの起動で失敗します。
$ sudo service httpd start httpd を起動中: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.1.11 for ServerName (13)Permission denied: make_sock: could not bind to address [::]:8086 (13)Permission denied: make_sock: could not bind to address 0.0.0.0:8086 no listening sockets available, shutting down Unable to open logs
そのときは、SELinuxのhttp_port_t に使用したいポート番号を追加します。
~$ sudo semanage port -l | grep http http_cache_port_t tcp 3128, 8080, 8118, 8123, 10001-10010 http_cache_port_t udp 3130 http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000 pegasus_http_port_t tcp 5988 pegasus_https_port_t tcp 5989 ~$
semanageコマンドがなければ、CentOS 6標準パッケージのpolicycoreutils-pythonをインストールします。
~$ sudo semanage port -a -t http_port_t -p tcp 8086 ~$ sudo semanage port -l|grep http_port http_port_t tcp 8086, 80, 81, 443, 488, 8008, 8009, 8443, 9000 pegasus_http_port_t tcp 5988
iptablesで8086ポートを開通します。
認証連携に必要なパッケージのインストール¶
- mod_perl
~$ sudo yum install mod_perl
- perlモジュール群(1)
~$ sudo yum install perl-LDAP perl-Params-Validate perl-Module-Runtime \ perl-Module-Implementation perl-Class-Accessor perl-Class-Data-Inheritable \ perl-Crypt-PasswordMD5 perl-Test-Simple
- DB連携モジュール(MySQL/MariaDB)
~$ sudo yum install perl-DBD-MySQL
- perl-Authen-Simpleモジュール
$ sudo yum install --enablerepo=epel-testing perl-Authen-Simple
- perl-Authen-Simple-LDAPモジュール
CentOS 6でPerl-Authen-Simple-LDAPのRPMパッケージを作るに添付したRPMパッケージ"perl-Authen-Simple-LDAP-0.3-1.el6.noarch.rpm"をダウンロードしインストールします。
Redmine.pmのインストール¶
Redmineに附属するRedmine.pmをperlの検索パスにシンボリックリンクします。
~$ sudo ln -s /var/lib/redmine/extra/svn/Redmine.pm /usr/lib64/perl5/vendor_perl/Apache2/Redmine.pm
httpd用設定ファイルの作成¶
/etc/httpd/conf.d/subversion.conf
LoadModule dav_svn_module modules/mod_dav_svn.so LoadModule authz_svn_module modules/mod_authz_svn.so PerlLoadModule Apache2::Redmine PerlLoadModule Authen::Simple::LDAP PerlLoadModule IO::Socket::SSL <Location /svn> DAV svn LimitXMLRequestBody 0 SVNPathAuthz off SVNParentPath /var/lib/svn/ AuthType Basic AuthName "Redmine" Require valid-user PerlAccessHandler Apache::Authn::Redmine::access_handler PerlAuthenHandler Apache::Authn::Redmine::authen_handler RedmineDSN "DBI:mysql:database=redmine;host=localhost" RedmineDbUser "redmine" RedmineDbPass "mypassword" </Location>
subversionリポジトリの作成¶
Redmineとの認証連携をする場合、subversionのリポジトリには命名規約があります。
- 書式
<redmineプロジェクト識別子>[.<拡張子>]
- Subversionリポジトリ名は、Redmineプロジェクト識別子に一致させる
- あるいは、Redmineプロジェクト識別子にピリオドを付加しその後ろに任意の文字列を追加する
subversionリポジトリは、apacheユーザー権限でアクセスできるようにします。
subversionリポジトリ作成¶
$ sudo svnadmin create /var/lib/svn/eval-perf.nolla $ sudo chown -R apache.apache /var/lib/svn
ポート80でsubversionを受ける¶
諸般の事情でポート80でsubversionへのアクセスを受けたい場合、Nginx側にリバースプロキシ設定を追加します。
- /etc/nginx/conf.d/redmine.conf に追記
server { : location /svn { proxy_pass http://localhost:8086; } : }
GitとRedmineの認証連携¶
Git 1.9のインストール¶
- CentOS 6でgitのバージョンを上げる
CentOS 6の標準搭載Gitは、バージョンが1.7.1と古い上基本的なバグもあって使いづらいので、バージョン1.9を別にインストールします。このページの記載に沿ってgitをインストールします。今回、先に上述のとおりWANdiscoのsubversionをインストールしているので、このページの依存関係解決の暫定処置を実施する必要があります。
その他必要なパッケージのインストール¶
SubversionとRedmineの認証連携でインストールしたものと同じものが必要となります。
httpd用設定ファイルの作成¶
/etc/httpd/conf.d/git.conf
PerlLoadModule Apache2::Redmine PerlLoadModule Authen::Simple::LDAP SetEnv GIT_PROJECT_ROOT /var/lib/git SetEnv GIT_HTTP_EXPORT_ALL SetEnv REMOTE_USER=$REDIRECT_REMOTE_USER ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/ <LocationMatch /git/> PerlAccessHandler Apache::Authn::Redmine::access_handler PerlAuthenHandler Apache::Authn::Redmine::authen_handler AuthType Basic AuthName Git RedmineDSN "DBI:mysql:database=redmine;host=localhost" RedmineDbUser "redmine" RedmineDbPass "mypassword" RedmineGitSmartHttp yes Require valid-user </LocationMatch>
gitリポジトリの作成¶
Redmineとの認証連携をする場合、gitリポジトリには命名規約があります。
- 書式
<redmineプロジェクト識別子>[.<拡張子>]
- gitリポジトリ名はRedmineプロジェクト識別子に一致させる
- あるいは、Redmineプロジェクト識別子にピリオドを付加しその後ろに任意の文字列を追加する
gitリポジトリは、apacheユーザー権限でアクセスできるようにします。
gitリポジトリの基点作成例¶
$ sudo mkdir /var/lib/git
SELinux有効下ではhttpdからの読み書きができるように設定します。
$ sudo semanage fcontext -a -t httpd_sys_content_t '/var/lib/git' $ sudo restorecon -R /var/lib/git
gitリポジトリの作成例¶
$ cd /var/lib/git $ sudo git init --bare --shared eval-perf.yksi $ cd eval-perf.yksi/ $ sudo git update-server-info $ sudo mv hooks/post-update.sample hooks/post-update $ sudo git config http.receivepack true $ cd .. $ sudo chown -R apache.apache .
ポート80でgitを受ける¶
諸般の事情でポート80でgitへのアクセスを受けたい場合、Nginx側にリバースプロキシ設定を追加します。
- /etc/nginx/conf.d/redmine.conf に追記
server { : location /git { proxy_pass http://localhost:8086; } : }
トラブルシューティング¶
巨大なファイルをアップロードするとエラーになりその後Redmineが著しく重い¶
巨大な(GB超)ファイルをアップロードすると、Unicornのワーカープロセスの1つのメモリ使用量(RSS)が一気に増大し、NoMemoryErrorを出して失敗します。さらに、そのUnicornのワーカープロセスが残ったままになって以降Redmineが重くて使い物にならなくなります。
なお、1GB超のファイルをダウンロードしてみたところ、Unicornのワーカプロセスのメモリ使用量に変化は見受けられませんでした。
エラー状況¶
1.1GBのファイルを添付したところ、Internal Server Errorが発生しました。
- /var/lib/redmine/log/production
NoMemoryError (failed to allocate memory): app/controllers/attachments_controller.rb:85:in `upload'
- top
Mem: 1020384k total, 956516k used, 63868k free, 4196k buffers Swap: 1048568k total, 403008k used, 645560k free, 17800k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 3316 redmine 20 0 1479m 754m 1440 S 0.0 75.7 0:02.41 ruby 1132 mysql 20 0 705m 29m 432 S 0.0 3.0 1:57.70 mysqld 3303 root 20 0 342m 27m 912 S 0.0 2.7 0:03.90 ruby 3313 redmine 20 0 342m 26m 780 S 0.0 2.7 0:00.04 ruby 3311 redmine 20 0 346m 26m 800 S 0.0 2.6 0:00.42 ruby 3350 postfix 20 0 81788 3332 2480 S 0.0 0.3 0:00.01 pickup 3349 nginx 20 0 45580 1788 448 S 0.0 0.2 0:00.00 nginx 3347 root 20 0 45212 1204 292 S 0.0 0.1 0:00.00 nginx
topの状況から、unicornのワーカープロセスの1つがファイルアップロード処理を実行している過程でメモリをどんどん喰っていき、これ以上メモリを取れずにエラーになったようです。
物理メモリを増強して再現確認¶
物理メモリを1GBから2GBに増強してもう一度同じファイルを添付してみました。
結果は添付に成功しました。
- top
Mem: 1922524k total, 1805328k used, 117196k free, 4456k buffers Swap: 1048568k total, 408452k used, 640116k free, 398316k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1270 redmine 20 0 2045m 1.2g 3348 S 0.0 65.5 0:06.48 ruby 1138 mysql 20 0 705m 27m 5024 S 0.3 1.5 0:02.39 mysqld 1259 root 20 0 440m 27m 3244 S 0.0 1.5 0:02.85 ruby 1267 redmine 20 0 445m 26m 2816 S 0.0 1.4 0:00.34 ruby 1265 redmine 20 0 445m 26m 2756 S 0.0 1.4 0:00.34 ruby 1388 root 20 0 98.0m 2928 2896 S 0.0 0.2 0:00.08 sshd
しかし、添付ファイルのサイズとほぼ同じ常駐メモリを喰っているunicornワーカープロセスが残っています。このままではワーカープロセスが次々肥大化しいずれはNoMemoryErrorが発生します。
解決策その1)unicorn-worker-killer¶
本格的なWebサーバーやアプリケーションサーバーは、リクエスト数やメモリ使用量が閾値を超えるとプロセスを再起動する「リサイクル」の仕組みがあるそうです。
Unicornにはリサイクルの仕組みはないのですが、Unicorn Worker Killer というRubyパッケージがあります。これはUnicornワーカープロセスに対するリクエスト数あるいはメモリ使用量を監視し閾値を超えたら終了させることができます。
参考資料のUnicornにunicorn-worker-killerへのリンクを掲載しています。
インストール¶
Unicorn Worker Killerのgemファイルをインストールします。
/var/lib/redmine/Gemfiles.localに次を追記します。
gem "unicorn-worker-killer"
bundle updateを実行します。
~$ cd /var/lib/redmine redmine$ sudo bundle update Fetching gem metadata from https://rubygems.org/......... Fetching additional metadata from https://rubygems.org/.. Resolving dependencies... Using rake 10.1.1 : Installing unicorn-worker-killer 0.4.2 Your bundle is updated! Gems in the groups development and test were not installed. ~$
/var/lib/redmine/config.ru に追記します。
--- config.ru.1 2014-03-30 01:56:42.000000000 +0900
+++ config.ru 2014-06-30 16:42:50.642004774 +0900
@@ -1,4 +1,13 @@
# This file is used by Rack-based servers to start the application.
+# Unicorn self-process killer
+require 'unicorn/worker_killer'
+
+# Max requests per worker
+use Unicorn::WorkerKiller::MaxRequests, 3072, 4096
+
+# Max memory size (RSS) per worker
+use Unicorn::WorkerKiller::Oom, (192*(1024**2)), (256*(1024**2))
+
require ::File.expand_path('../config/environment', __FILE__)
run RedmineApp::Application
Unicornを再起動¶
~$ sudo service unicorn restart
再度大きなファイルをアップロードすると、unicornワーカープロセスのRSSが1.2GBに達します。
その後、いくつかRedmineのページを開きリクエストを繰り返していると、unicornの標準エラー出力に次のメッセージが表示され、メモリ肥大したワーカープロセスがkillされ、新たにワーカープロセスが立ち上がりました。
/var/lib/redmine/log/unicorn.stderr.log
W, [2014-06-30T17:06:50.549746 #1623] WARN -- : #<Unicorn::HttpServer:0x000000024c6628>: worker (pid: 1623) exceeds memory limit (1308868608 bytes > 202455902 bytes) W, [2014-06-30T17:06:50.549839 #1623] WARN -- : Unicorn::WorkerKiller send SIGQUIT (pid: 1623) alive: 1199 sec (trial 1) I, [2014-06-30T17:06:50.899445 #1609] INFO -- : reaped #<Process::Status: pid 1623 exit 0> worker=2 I, [2014-06-30T17:06:51.077862 #1699] INFO -- : worker=2 ready
Unicorn Worker Killerは、メモリ使用量のチェックをデフォルトではリクエストが16回発生する都度行います。
この後のtopの状況は次です。
Mem: 1922524k total, 601884k used, 1320640k free, 11528k buffers Swap: 1048568k total, 202740k used, 845828k free, 180676k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1619 redmine 20 0 451m 103m 3328 S 0.0 5.5 0:01.60 ruby 1617 redmine 20 0 445m 96m 3416 S 0.0 5.1 0:01.41 ruby 1138 mysql 20 0 705m 30m 5920 S 0.0 1.6 0:07.20 mysqld 1699 redmine 20 0 437m 29m 2100 S 0.0 1.6 0:00.04 ruby 1609 root 20 0 437m 10m 5424 S 0.0 0.6 0:03.50 ruby 1641 root 20 0 98.0m 3956 2996 S 0.0 0.2 0:00.11 sshd
SELinux設定のトラブルシュート¶
Can't open file '/var/lib/svn/repoa/db/txn-current-cock': Permission denied¶
SELinuxで/var/lib/svn以下のディレクトリにApache httpdサーバーがアクセスできる許可がないため発生します。
/var/lib/svn ---> unconfined_u:object_r:var_lib_t:s0
httpdサーバーが読み書きする場所には、httpd_sys_content_t を設定しておきます。
~$ sudo semanage fcontext -a -t httpd_sys_content_t '/var/lib/svn(/.*)?' ~$ sudo restorecon -R /var/lib/svn
bundle install/updateでSSLエラー¶
とある環境でbundle updateしたところ次のエラーがでました。
Gem::RemoteFetcher::FetchError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
gemパッケージのリポジトリサーバーとSSL通信する際に、gemパッケージのリポジトリサーバーから取得したSSL証明書の正当性を証明できないためにエラーとなっています。このエラーメッセージはWeb上にあちこちで言及されています。
rubyが使用する認証局証明書は次で確認できます。
$ ruby -ropenssl -e 'puts OpenSSL::X509::DEFAULT_CERT_FILE' /etc/pki/tls/cert.pem $
ファイアウォールがある環境¶
社内イントラネット上のサーバーからファイアウォールを介してインターネットにgemパッケージを取りに行くときに、httpsプロトコルのプロキシーがらみで起きたようです。
サーバー証明書のチェックを無効にしての回避方法があります。
gem(bundle)実行ユーザーのホームディレクトリに.gemrc
ファイルを作成し、中に次を記述します。
:ssl_verify_mode: 0
- sudoコマンドでgem (bundle)を実行するときは、
/root/.gemrc
に配置
参考資料¶
Redmine¶
インストール関係¶
Unicorn¶
- unicorn-worker-killer
メモリ使用量が閾値を超えたらワーカープロセスをkillする
Nginx¶
- nginx入門 第10回静岡ITPro勉強会インフラ部
設定ファイルの記述解説多い - 書籍 マスタリングNginx