RedmineをCentOS 7上で動かすーUnicornとNginx編¶
- 目次
- RedmineをCentOS 7上で動かすーUnicornとNginx編
はじめに¶
RedmineをCentOS 7で動かすセットアップメモです。
RedmineをCentOS 6上で動かすーUnicornとNginx編の環境でのCentOS 7版です。
もちろんSELinuxは"Enforcing"です。
動作環境¶
ハードウェア構成¶
AMD A10-6800K CPUと16GBメモリのPC上の仮想化ゲスト上で動かします。
ホストのハードウェア仕様は自作PC-F2A85Vを参照。
ゲストの(仮想)ハードウェアの仕様は次のとおりです。
CPUとメモリは、動かしながら様子を見て増加させていくため、初期は少ない値としています。
項目 | 内容 | 備考 |
---|---|---|
仮想化ホストOS | CentOS 7.0 64bit版 | |
仮想化ソフトウェア | OS標準搭載KVM | |
仮想ゲストCPU数 | 1 | 必要に応じて順次増加 |
仮想ゲストメモリ | 1024MB | 必要に応じて順次増加 |
ディスクイメージ | qcow2 | 場合によってRAW(スパースなし)に変更 |
ソフトウェア構成¶
項目 | 使用ソフトウェア | 備考 |
---|---|---|
OS | CentOS 7.0 64bit版 | |
Redmine | Redmine 3.0.0 | |
Ruby | Ruby 2.0.0 | CentOS 7標準 |
RDBMS | MariaDB 5.5 | CentOS 7標準 |
Rackサーバー | Unicorn | |
Webサーバー | Nginx 1.7.3 | |
CentOS 7の必要なパッケージをインストール¶
Redmineをインストールし動かすのに必要となるCentOS 7のパッケージをインストールします。
開発ツール等¶
~$ sudo yum groupinstall "Development Tools" : ~$ sudo yum install openssl-devel readline-devel zlib-devel curl-devel libyaml-devel ImageMagick ImageMagick-devel :
MariaDB¶
MariaDBのCentOS 7標準パッケージインストール¶
~$ sudo yum install mariadb-server mariadb-devel :
MariaDBの設定¶
MariaDBは、/etc/my.cnf から、/etc/my.cnd.d/* をインクルードするようになりました。
サーバー用なので、各種設定は、/etc/my.cnf.d/の中に記載します。
- /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
チューニング設定例(4GBメモリサーバー機)¶
メモリ4GB搭載環境で、Redmine側に3GBを割り付けて、残り1GBをMariaDBに割り振る想定でのパラメータを追記します。
- /etc/my.cnf.d/server.cnf
[mysqld] character-set-server = utf8 innodb_buffer_pool_size = 512M innodb_log_file_size = 128M read_buffer_size = 2M
MariaDBの起動¶
CentOS 7からサービス(デーモン)の起動終了はsystemctlコマンドで行います。
~$ sudo systemctl start mariadb.service
~$ systemctl status mariadb mariadb.service - MariaDB database server Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled) Active: active (running) since 土 2014-07-12 21:42:13 JST; 45min ago Main PID: 15320 (mysqld_safe) CGroup: /system.slice/mariadb.service tq15320 /bin/sh /usr/bin/mysqld_safe --basedir=/usr mq15490 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysq...
- .serviceは省略可能なようです
CentOS 7からサービス(デーモン)の自動起動設定はsystemctlコマンドで行います。
MariaDBを自動起動する設定
~$ sudo systemctl enable mariadb.service ln -s '/usr/lib/systemd/system/mariadb.service' '/etc/systemd/system/multi-user.target.wants/mariadb.service'
コンソールクライアントでMariaDBに接続します。コマンドはなぜかmysqlです。
~$ mysql -uroot Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 3 Server version: 5.5.37-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)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | +--------------------+ 4 rows in set (0.00 sec) MariaDB [(none)]> status -------------- mysql Ver 15.1 Distrib 5.5.37-MariaDB, for Linux (x86_64) using readline 5.1 Connection id: 3 Current database: mysql Current user: root@localhost SSL: Not in use Current pager: stdout Using outfile: '' Using delimiter: ; Server: MariaDB Server version: 5.5.37-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: 59 min 51 sec Threads: 1 Questions: 45 Slow queries: 0 Opens: 15 Flush tables: 2 Open tables: 41 Queries per second avg: 0.012 -------------- MariaDB [(none)]> show engines; +--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+ | Engine | Support | Comment | Transactions | XA | Savepoints | +--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+ | InnoDB | DEFAULT | Percona-XtraDB, Supports transactions, row-level locking, and foreign keys | YES | YES | YES | | CSV | YES | CSV storage engine | NO | NO | NO | | MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO | | BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO | | MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO | | PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO | | ARCHIVE | YES | Archive storage engine | NO | NO | NO | | MyISAM | YES | MyISAM storage engine | NO | NO | NO | | FEDERATED | YES | FederatedX pluggable storage engine | YES | NO | YES | | Aria | YES | Crash-safe tables with MyISAM heritage | NO | NO | NO | +--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+ 10 rows in set (0.00 sec) MariaDB [none]>
インストール直後はMariaDBのrootユーザーにパスワードが設定されていないので、パスワードを設定しておきます。インストール直後のユーザー一覧は次のとおりです。
MariaDB [(none)]> SELECT user,host,password FROM mysql.user; +------+-----------+----------+ | user | host | password | +------+-----------+----------+ | root | localhost | | | root | avelo | | | root | 127.0.0.1 | | | root | ::1 | | | | localhost | | | | avelo | | +------+-----------+----------+ 6 rows in set (0.00 sec)
rootユーザーはhostごとに計4つ存在します。それぞれにパスワードを設定します。
MariaDB [none]> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('magdala'); Query OK, 0 rows affected (0.00 sec) MariaDB [none]> SET PASSWORD FOR 'root'@'avelo' = PASSWORD('magdala'); Query OK, 0 rows affected (0.00 sec) MariaDB [none]> SET PASSWORD FOR 'root'@'127.0.0.1' = PASSWORD('magdala'); Query OK, 0 rows affected (0.00 sec) MariaDB [none]> SET PASSWORD FOR 'root'@'::1' = PASSWORD('magdala'); Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> SELECT user,host,password FROM mysql.user; +------+-----------+-------------------------------------------+ | user | host | password | +------+-----------+-------------------------------------------+ | root | localhost | *XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | | root | avelo | *XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | | root | 127.0.0.1 | *XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | | root | ::1 | *XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | | | localhost | | | | avelo | | +------+-----------+-------------------------------------------+ 6 rows in set (0.00 sec)
Ruby¶
~$ sudo yum install ruby ruby-devel
CentOS 7では、ruby 2.0.0がベースラインとなっています。
Redmineのインストール¶
RedmineはRedmineを実行するためには、Redmine本体のほかにRedminが使用している各種Rubyモジュール(ライブラリ集、rubyではgemパッケージと呼ぶ)が必要です。Ruby on RailsもRubyモジュールです。Rubyモジュールは、bundlerという仕組みを使ってインストールします。
Rubyモジュールは、システム共通の場所に入れるかRedmine固有の場所に入れるかの選択肢がありますが、トラブルを避けるためRedmine固有の場所にインストールします。
Redmine本体の入手と展開¶
Redmine公式サイトのダウンロードページ より最新安定版(Latest stable releases)をダウンロードします。2015-02-24時点でVer.3.0.0が最新です。
ダウンロードしたRedmine本体を展開します。インストールディレクトリは/var/lib/の下にredmine-<バージョン番号>となるよう展開し、シンボリックリンクファイル/var/lib/redmineを使用するredmineのディレクトリを指すように作成します。
~$ cd /var/lib lib$ sudo tar xzf ~/redmine-3.0.0.tar.gz lib$ sudo ln -s redmine-3.0.0/ redmine lib$ ls -l : lrwxrwxrwx. 1 root root 14 7月 13 05:14 redmine -> redmine-3.0.0/ drwxrwxr-x. 16 1000 1000 4096 7月 6 21:44 redmine-3.0.0
Redmineのデータベース設定¶
データベース設定ファイル(database.yml)の作成¶
/var/lib/redmine/config/database.yml
を編集します。Redmineにはサンプルとしてdatabase.yml.sampleが含まれているので、このサンプルからMySQL用の設定を抜き出し修正するとよいでしょう。MariaDBはMySQL用の設定を使用できます。production:
adapter: mysql2
database: redmine
host: localhost
username: redmine
password: xxxxxxxx
encoding: utf8
- サンプルにはproduction以外にdevelopment、testの設定がありますが、通常productionのみ使用するので設定はproductionだけ記述します。
- adapter項はMariaDB(MySQL)5.5の場合はmysql2を指定します。
- database項はMariaDB上でRedmineのテーブルを収容するデータベース名を指定します。
- username項はMariaDBのデータベースに接続するMariaDBのユーザー名を指定します。
- password項はusernameで指定したMariaDBのユーザーのパスワードを指定します。
- encoding項はMariaDBで使用する文字エンコーディングを指定します。通常utf8です。
MariaDBのデータベースユーザーのパスワードを記述しているのでパーミッションを厳しく設定しておきます。
~$ sudo chmod 600 /var/lib/redmine/config/database.yml
MariaDB上にRedmine用のデータベースと接続用ユーザーを作成¶
database.ymlのdatabase項に指定したMariaDB上でRedmineのテーブルを収容するデータベースをMariaDB上に作成します。
~$ mysql -uroot -p Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 8 Server version: 5.5.37-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)]> 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)
database.ymlのusername項とpassword項に指定したユーザーをMariaDB上に作成します。
MariaDB [(none)]> GRANT ALL ON redmine.* TO 'redmine'@'localhost' IDENTIFIED BY 'xxxxxxxx' WITH GRANT OPTION; Query OK, 0 rows affected (0.00 sec)
- RedmineからMariaDBへは同じマシン上でUNIXソケットを使って接続するのでホスト名はlocalhostとしています。
- WITH GRANT OPTIONを指定するとそのユーザーが持つ権限範囲以内の権限を他のユーザーに付与できます。
Redmineのメール接続設定¶
設定ファイル(configuration.yml)の作成¶
Redmineにはサンプルとしてconfiguration.yml.sampleが含まれているので、このサンプルから設定を抜き出し修正するとよいでしょう。
今回はメールサーバーをローカルとして使用します。
/var/lib/redmine/config/configuration.yml
を作成します。
production: email_delivery: delivery_method: :smtp smtp_settings: address: "localhost" port: 25
上記例では記載していませんが、メールサーバによってはパスワードを記述するのでパーミッションを厳しく設定しておきます。
~$ sudo chmod 600 /var/lib/redmine/config/configuration.yml
Redmineユーザーの作成¶
Redmineを動かすときのユーザー権限として、Linuxにredmineユーザーを作成します。展開したRedmineディレクトリ以下の所有権をredmineユーザーに変更します。
~$ sudo useradd redmine ~$ sudo passwd redmine ユーザー redmine のパスワードを変更。 新しいパスワード: : ~$ cd /var/lib/redmine redmine$ sudo chown -R redmine.redmine .
Rubyモジュール群のインストール¶
Redmine本体が依存するRubyモジュール群をインストールします。Rubyモジュールのインストールには、rubyのbundlerを使用します。
bundlerのインストール¶
bundlerもRubyモジュール(gemパッケージ)です。これはシステム共通場所にインストールします。
システム共通にインストールされているgemパッケージを一覧します。
$ gem list *** LOCAL GEMS *** bigdecimal (1.2.0) io-console (0.4.2) json (1.7.7) psych (2.0.0) rdoc (4.0.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を指定し、そこへインストールします。
ユーザーredmineで以下を実行します。
~$ cd /var/lib/redmine redmine$ bundle install --path vendor/bundler --without development test Fetching gem metadata from https://rubygems.org/......... Fetching additional metadata from https://rubygems.org/.. Resolving dependencies... Installing rake 10.1.1 :
Redmineの初期化¶
Redmine本体および依存するRubyモジュールのインストールが終わったら、Redmineの初期化を行います。
セッションデータ暗号化の鍵生成¶
改ざん防止のため、セッションデータを格納するクッキーを暗号化する鍵をランダムに生成します。
redmineユーザーで以下を実行します。
redmine$ bundle exec rake generate_secret_token
- 注記)bundlerでRedmine固有ディレクトリ(--path vendor/bundler)にRubyモジュールをインストールしたので、rakeコマンドを実行する際はbundle exec rake xxx のようにbundle execをつけて実行する必要があります。
データベースのスキーマを構築¶
Redmineが使用するデータベースにスキーマを構築します。
redmineユーザーで以下を実行します。
redmine$ bundle exec rake db:migrate RAILS_ENV=production :
MariaDBに入ってテーブル一覧を確認します。
redmine$ mysql -uredmine -p Enter password: XXXXXXXX Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 10 Server version: 5.5.37-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)]> USE redmine Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A 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)
Redmine内蔵WebサーバーWEBrickによる動作確認¶
Redmineには内蔵のWebサーバーWEBrickがあるので、Redmine単独での起動確認をWEBrickで行います。
なお、WEBrickは開発・テスト用であり、運用には耐えられません。
WEBrick動作確認のためファイアウォールでポート3000を一時的に許可します。
~$ sudo firewall-cmd --add-port=3000/tcp success
WEBrickを実行します。redmineユーザーで以下を実行します。
redmine]$ ruby script/rails server webrick -e production => Booting WEBrick => Rails 3.2.19 application starting in production on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server [2014-07-13 07:31:54] INFO WEBrick 1.3.1 [2014-07-13 07:31:54] INFO ruby 2.0.0 (2013-11-22) [x86_64-linux] [2014-07-13 07:31:54] INFO WEBrick::HTTPServer#start: pid=9370 port=3000
Webブラウザを立ち上げ、Redmineを動かしているマシンにポート3000でアクセスします。
うまくいっていれば、WebブラウザにRedmineの画面が表示され、WEBrickを起動したコンソールにアクセスメッセージが表示されます。
Started GET "/" for 192.168.1.33 at 2014-07-13 07:50:44 +0900 Processing by WelcomeController#index as HTML Current user: anonymous Rendered welcome/index.html.erb within layouts/base (31.2ms) Completed 200 OK in 237.2ms (Views: 92.1ms | ActiveRecord: 25.5ms)
WEBrickを停止します。WEBrickを起動したコンソールでCtrl-Cを入力します。
^C[2014-07-13 07:56:22] INFO going to shutdown ... [2014-07-13 07:56:22] INFO WEBrick::HTTPServer#start done. Exiting redmine$
Unicornのセットアップ¶
Rubyアプリケーションを動かすアプリケーションサーバー(Rackサーバー)のUnicornをセットアップします。
Unicornのインストール¶
UnicornはRubyモジュール(gem)として提供されるので、bundlerでインストールします。
Redmineをインストールしたディレクトリ下(例:/var/lib/redmine)に、Gemfile.localというファイルを作成し、そこに以下を記述します。
gem "unicorn"
Redmineをインストールしたディレクトリで bundle update を実行します。
redmine$ bundle update : Installing kgio 2.9.2 : Installing raindrops 0.13.0 : Installing unicorn 4.8.3 Your bundle is updated! Gems in the groups development and test were not installed.
インストール後の単独起動確認¶
コマンドラインからUnicornを起動してRedmineの動作を確認します。
先にWEBrick確認時に一時的にファイアウォールにあけたポート3000を使用します。
redmine$ bundle exec unicorn_rails -l 3000 -E production I, [2014-07-13T08:25:53.245083 #9802] INFO -- : listening on addr=0.0.0.0:3000 fd=9 I, [2014-07-13T08:25:53.245344 #9802] INFO -- : worker=0 spawning... I, [2014-07-13T08:25:53.246279 #9802] INFO -- : master process ready I, [2014-07-13T08:25:53.247224 #9805] INFO -- : worker=0 spawned pid=9805 I, [2014-07-13T08:25:53.247358 #9805] INFO -- : Refreshing Gem list I, [2014-07-13T08:25:55.514811 #9805] INFO -- : worker=0 ready
これでWebブラウザからポート3000で接続し動作確認をします。
参考)コマンドラインオプションは次です。
--listen -l [アドレス:]ポート ソケットのエンドポイントを指定 --config-file -c ファイル 設定ファイルを指定 -D デーモンプロセス起動指定 -E <RAILS_ENV> production等を指定
Unicornプロセスに対する制御¶
ちょっと難しいのがUnicornのプロセス制御です。Unicornは、マスタープロセス1つにワーカープロセスが複数という構成です。
終了方法¶
- フォアグラウンドプロセスとして起動した場合、Ctrl-Cで停止します。
- デーモンプロセスとして起動した場合、シグナルINT(強制終了)またはQUIT(グレースフル停止)をマスタープロセスに送ります。
- シグナルINT: ワーカープロセスを即終了させて自らも終了
再起動方法¶
デーモンプロセスに対する設定ファイル再読み込みトリガーはシグナルHUPをマスタープロセスに送ります。このとき、preload_appがfalseだとアプリケーションプログラムも再読み込みされますが、preload_appがtrueだと再読み込みされません。
シグナルUSR2を使うと、古いマスタープロセスは新しいプロセスを作ってソケットを引継ぎます。古いプロセスはそのまま残っています。pidファイルは新プロセスの値に書き換えられます。古いpidファイルは.oldbinの拡張子が付いたファイルに変更されます。preload_appがtrueのときにアプリケーションプログラムを再読み込みするにはこのシグナルUSR2を使います。
シグナルUSR2を送っただけでは古いマスタープロセスとその配下のワーカープロセスは終了しないので、シグナルUSR2を送ったあとに古いマスタープロセスに対してシグナルQUITを送るとよいのかと思います。
- シグナルQUIT: ワーカープロセスがリクエストの処理を終えるまで待って終了
- そのほか
- シグナルWINCH: ワーカープロセスをグレースフルに停止しますが自らは終了しません
- シグナルTTIN: ワーカープロセスを1つ増やします
- シグナルTTOU: ワーカープロセスを1つ減らします
マスタープロセスのプロセスIDを調べる¶
次のように調べます。
$ pgrep -f 'unicorn_rails master' 3783 $
Unicornの設定¶
RedmineをCentOS 6上で動かすーUnicornとNginx編ページのUnicornの設定項を参照
Unicornのサービス化(起動終了制御)¶
CentOS 7から、サービスの仕組みが変わったので、サービス起動ファイルもCentOS 7用に作成し直します。
Systemd用のUnicornサービス定義ファイルの作成¶
- /usr/lib/systemd/system/redmine-unicorn.service
[Unit] Description=Redmine Unicorn Server After=mariadb.service [Service] WorkingDirectory=/var/lib/redmine Environment=RAILS_ENV=production SyslogIdentifier=redmine-unicorn PIDFile=/var/lib/redmine/tmp/pids/unicorn.pid ExecStart=/usr/local/bin/bundle exec "unicorn_rails -c config/unicorn.rb -E production" ExecStop=/usr/bin/kill -QUIT $MAINPID ExecReload=/bin/kill -USR2 $MAINPID [Install] WantedBy=multi-user.target
サービス起動順序に注意¶
CentOS 7から、OS起動時のサービス立ち上げは、並行して実行されるようになりました。
Redmine(Unicorn)は、起動時にデータベースに接続できないとエラー終了してしまいます。
そこで、[Unit]セクションにAfterで、mariadb.serviceが実行されてからredmine-unicorn.serviceが起動されるよう順序を指定します。
Unicornのサービス起動確認¶
~$ sudo systemctl start redmine-unicorn.service ~$ sudo systemctl status redmine-unicorn.service redmine-unicorn.service - Redmine Unicorn Server Loaded: loaded (/etc/systemd/system/redmine-unicorn.service; disabled) Active: active (running) since 日 2014-07-13 13:23:02 JST; 4min 21s ago Main PID: 10117 (ruby) CGroup: /system.slice/redmine-unicorn.service tq10117 unicorn_rails master -c /var/lib/redmine/config/unicorn.rb... tq10122 unicorn_rails worker[0] -c /var/lib/redmine/config/unicorn... tq10125 unicorn_rails worker[1] -c /var/lib/redmine/config/unicorn... mq10127 unicorn_rails worker[2] -c /var/lib/redmine/config/unicorn... 7月 13 13:23:02 avelo systemd[1]: Starting Redmine Unicorn Server... 7月 13 13:23:02 avelo systemd[1]: Started Redmine Unicorn Server. 7月 13 13:26:55 avelo systemd[1]: Started Redmine Unicorn Server.
ファイアウォールのポート8282を一時的に開放
~$ sudo firewall-cmd --add-port=8282/tcp success
リモートからブラウザでポート8282にアクセスしてRedmineが利用できることを確認します。
Systemdに自動起動登録¶
~$ sudo systemctl enable redmine-unicorn.service ln -s '/etc/systemd/system/redmine-unicorn.service' '/etc/systemd/system/multi-user.target.wants/redmine-unicorn.service'
参考¶
Unicornのメモリ使用状況の調査¶
CentOS 6.5にruby 2.1.2を入れてRedmineをUnicorn上で動かしていたとき、ファイルのアップロードをするとファイルサイズ分のメモリを消費し、その後そのメモリをunicornプロセスが喰ったままとなってOS全体のメモリ枯渇を引き起こしていました。
今回、CentOS 7とその標準搭載ruby 2.0.0でRedmineをUnicorn上で動かしたので、再度ファイルのアップロード時のメモリ喰いを評価してみました。
Unicornメモリ使用状況調査#1¶
250MBのファイルをアップロードしたら、unicornのtimeout設定(デフォルトの60秒を30秒に変更)にひっかかってしまいワーカープロセスがkillされてしまいました。- unicorn.stderr.log
E, [2014-07-13T14:35:18.066964 #16275] ERROR -- : worker=2 PID:16287 timeout (31 s > 30s), killing E, [2014-07-13T14:35:18.853430 #16275] ERROR -- : reaped #<Process::Status: pid 16287 SIGKILL (signal 9)> worker=2 I, [2014-07-13T14:35:19.394439 #19944] INFO -- : worker=2 ready
Unicornメモリ使用状況調査#2¶
unicornのtimeoutを300秒に増やし、500MBのファイルのアップロードを行いました。
unicorn起動直後root 25084 15.1 9.9 451376 101504 ? Ssl 14:56 0:03 unicorn_rails m redmine 25114 0.0 9.4 451524 96680 ? Sl 14:57 0:00 unicorn_rails w redmine 25117 0.0 9.4 451528 96668 ? Sl 14:57 0:00 unicorn_rails w redmine 25119 0.0 9.4 451520 96672 ? Sl 14:57 0:00 unicorn_rails w
- 各ワーカープロセスの物理メモリ常駐量(RSS)は96MB
ファイルアップロード完了時
root 25084 2.9 9.9 451376 101448 ? Ssl 14:56 0:03 unicorn_rails m redmine 25114 4.3 55.0 1358688 560284 ? Sl 14:57 0:05 unicorn_rails w redmine 25117 0.4 10.0 455984 102296 ? Sl 14:57 0:00 unicorn_rails w redmine 25119 0.3 9.9 454616 100988 ? Sl 14:57 0:00 unicorn_rails w
しばらくRedmineをアクセスしていると
root 25084 0.4 9.6 451376 98628 ? Ssl 14:56 0:03 unicorn_rails m redmine 25114 0.7 11.4 473652 116888 ? Sl 14:57 0:05 unicorn_rails w redmine 25117 0.2 10.5 461152 107392 ? Sl 14:57 0:01 unicorn_rails w redmine 25119 0.2 10.5 463244 107480 ? Sl 14:57 0:01 unicorn_rails w
と、それまでメモリ使用量がVSZ(仮想メモリ使用量)が1.3GB、RSS(物理メモリ使用量)が560MBだったワーカープロセス25114が、しばらくすると他のワーカープロセスとほぼ同じ量に減りました。
Rubyのメモリ管理について¶
CentOS 6.5 - ruby 2.1.2と、CentOS 7.0 - ruby 2.0.0との間でメモリの解放について振舞いが異なる結果となりました。この振る舞いにおいてOSが関与することはなさそうなので、ruby 2.0.0と2.1.2の違いを調べてみました。
すると、ruby 2.1においてガベージコレクタ(GC)の大幅な変更がありました。
2.0までのGCは、マーク&スイープ方式ですが、2.1から世代別方式(Restricted Generational Garbage Collection: RGenGC)となりました。
Nginxのセットアップ¶
Nginxのサイトでは、CentOS 7向けのyumリポジトリはmainline用(開発最新版)に用意があります。
yumリポジトリの設定とNginxのインストール¶
- /etc/yum.repos.d/nginx.repoを作成します。
[nginx] name=nginx repo baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/ gpgcheck=0 enabled=1
- インストールします。
~$ 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/sysconfig/nginx /usr/lib/systemd/system/nginx.service /usr/libexec/initscripts/legacy-actions/nginx /usr/libexec/initscripts/legacy-actions/nginx/upgrade /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 ~$
- インストールした段階ではnginxサービスは自動起動設定されていません。
~$ systemctl status nginx nginx.service - nginx - high performance web server Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled) Active: inactive (dead) Docs: http://nginx.org/en/docs/
- nginxサービスの自動起動設定
~$ sudo systemctl enable nginx.service ln -s '/usr/lib/systemd/system/nginx.service' '/etc/systemd/system/multi-user.target.wants/nginx.service' ~$ systemctl status nginx nginx.service - nginx - high performance web server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled) Active: inactive (dead) Docs: http://nginx.org/en/docs/
nginxの設定¶
ポート80のデフォルト設定は使用しない(Redmine用に別途設定)のでリネームしておきます。
~$ cd /etc/nginx/conf.d conf.d$ sudo mv default.conf default.conf.orig
/etc/nginx/conf.d/redmine.confを新規作成します(以下は後ほど述べる問題あり)。
pstream unicorn-redmine { server unix:/tmp/unicorn_redmine.sock; } server { listen 80; server_name nostrum; root /var/lib/redmine/public; client_max_body_size 1G; location / { try_files $uri/index.html $uri.html $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; } error_page 500 502 503 504 /500.html; }
設定ファイルの検証を行います。
~$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
ファイアウォールにポート80を設定¶
ポート80を許可するようにファイアウォールを設定します。
まず、現在適用されているファイアウォールのゾーンを確認します。
~$ sudo firewall-cmd --get-default-zone public
publicゾーンで許可されているサービスを確認します。
~$ sudo firewall-cmd --list-services --zone=public dhcpv6-client ssh
httpサービス(ポート80)が許可されていないので、永続的に許可を設定します。
~$ sudo firewall-cmd --add-service http --zone=public --permanent success
publicゾーンで許可されているサービスにhttpが追加されたことを確認します。
~$ sudo firewall-cmd --list-services --zone=public dhcpv6-client http ssh
Nginxサービス起動¶
サービス起動エラー事例#1¶
~$ sudo systemctl start nginx.service Job for nginx.service failed. See 'systemctl status nginx.service' and 'journalctl -xn' for details.
おや、失敗です。
statusを見よとあるので、見てみます(-lオプションを付けるとエラーがフルに見れます)。
~$ sudo systemctl -l status nginx.service nginx.service - nginx - high performance web server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled) Active: failed (Result: exit-code) since 日 2014-07-13 20:17:02 JST; 18s ago Docs: http://nginx.org/en/docs/ Process: 27906 ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf (code=exited, status=1/FAILURE) 7月 13 20:17:02 avelo systemd[1]: Starting nginx - high performance web server... 7月 13 20:17:02 avelo nginx[27906]: nginx: [emerg] open() "/etc/nginx/conf.d/redmine.conf" failed (13: Permission denied) in /etc/nginx/nginx.conf:31 7月 13 20:17:02 avelo nginx[27906]: nginx: configuration file /etc/nginx/nginx.conf test failed 7月 13 20:17:02 avelo systemd[1]: nginx.service: control process exited, code=exited status=1 7月 13 20:17:02 avelo systemd[1]: Failed to start nginx - high performance web server. 7月 13 20:17:02 avelo systemd[1]: Unit nginx.service entered failed state.
/etc/nginx/nginx.conf の31行目で/etc/nginx/conf.d/redmine.confの読み込みでパーミッションエラーが発生とあります。
~$ ls -l /etc/nginx/conf.d/ 合計 12 -rw-r--r--. 1 root root 1097 7月 11 21:32 default.conf.orig -rw-r--r--. 1 root root 427 7月 11 21:32 example_ssl.conf -rw-r--r--. 1 root root 667 7月 13 20:12 redmine.conf
一見問題なさそうです。うーん、と悩んで、あ、SELinuxかも?
~$ ls -lZ /etc/nginx/conf.d/ -rw-r--r--. root root system_u:object_r:httpd_config_t:s0 default.conf.orig -rw-r--r--. root root system_u:object_r:httpd_config_t:s0 example_ssl.conf -rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 redmine.conf
Zオプションを指定すると、設定が違っているのが分かります。
別なマシンのredmine.confをホームディレクトリ経由でコピーしたのが原因です。
restoreconで本来の設定に合わせます。
~$ cd /etc/nginx/conf.d conf.d$ sudo restorecon redmine.conf conf.d$ ls -Z -rw-r--r--. root root system_u:object_r:httpd_config_t:s0 default.conf.orig -rw-r--r--. root root system_u:object_r:httpd_config_t:s0 example_ssl.conf -rw-r--r--. root root unconfined_u:object_r:httpd_config_t:s0 redmine.conf
他のファイルとじゃっかん異なりますが、たぶんhttpd_config_tが付いていればいけるでしょう。
conf.d$ sudo systemctl start nginx.service
今回はエラーなく実行できました。
conf.d$ sudo systemctl status nginx.service nginx.service - nginx - high performance web server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled) Active: active (running) since 日 2014-07-13 20:43:42 JST; 6s ago Docs: http://nginx.org/en/docs/ Process: 27925 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS) Process: 27924 ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS) Main PID: 27928 (nginx) CGroup: /system.slice/nginx.service tq27928 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.... mq27929 nginx: worker process 7月 13 20:43:42 avelo systemd[1]: Starting nginx - high performance web..... 7月 13 20:43:42 avelo nginx[27924]: nginx: the configuration file /etc/n...k 7月 13 20:43:42 avelo nginx[27924]: nginx: configuration file /etc/nginx...l 7月 13 20:43:42 avelo systemd[1]: Failed to read PID from file /run/ngi...nt 7月 13 20:43:42 avelo systemd[1]: Started nginx - high performance web ...r. Hint: Some lines were ellipsized, use -l to show in full.
まあ動いたようです。
サービス起動エラー事例#2¶
Nginxが無事動いて、ブラウザからRedmineにアクセスしたら、Internal error 発生です。
/var/log/nginx/error.log を見たら
2014/07/13 21:10:00 [crit] 28047#0: *3 connect() to unix:/tmp/unicorn_redmine.sock failed (2: No such file or directory) while connecting to upstream, client: 192.168.1.18, server: avelo, request: "GET / HTTP/1.1", upstream: "http://unix:/tmp/unicorn_redmine.sock:/", host: "avelo"
/tmpにsockファイルがあるか確認しましたが、ありました。
~$ ls -l /tmp srwxrwxrwx. 1 root root 0 7月 13 20:55 unicorn_redmine.sock :
いろいろ調べていたところ、次の記事を見かけました。
Making Fedora 17,Unicorn and Nginx Work Together
この記事では「Don't put the socket file in the /tmp directory.」とあります。理由も解説されており、まとめるとNginxのサービス起動設定ファイルでPrivateTmp=trueが設定されているため、他のプロセス(Unicorn)と/tmp下(/var/tmpも)のファイルが共有できないからです。
回避策はUNIXドメインソケットファイルを/tmp以外の場所(例:/var/lib/redmine/tmp/sockets 下)に設けることです。
- /var/lib/redmine/config/unicorn.rb の修正
-listen "/tmp/unicorn_redmine.sock", :backlog => 32 +listen "tmp/sockets/unicorn.sock", :backlog => 32
- /etc/nginx/conf.d/redmine.conf の修正
- server unix:/tmp/unicorn_redmine.sock; + server unix:/var/lib/redmine/tmp/sockets/unicorn.sock;
サービス起動エラー事例#3¶
Nginxが無事動き、エラー事例#2の回避策を講じたあと、ブラウザからRedmineにアクセスしたら、Internal error 発生です。
/var/log/nginx/error.log を見たら
2014/07/13 21:51:17 [crit] 28164#0: *1 connect() to unix:/var/lib/redmine/tmp/sockets /unicorn.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.1.18, server: avelo, request: "GET / HTTP/1.1", upstream: "http://unix:/var/lib/redmine/tmp/sockets/unicorn.sock:/", host: "avelo"
うむ、おそらくSELinuxでしょうか
redmine$ ls -lZ tmp/sockets/ srwxrwxrwx. root root system_u:object_r:var_lib_t:s0 unicorn.sock
Nginx(http)からアクセスできないかと思われます。
~$ sudo setenforce 0
これならアクセスできました。
/var/log/audit/audit.log を調べると
type=AVC msg=audit(1405256491.134:1898): avc: denied { write } for pid=28164 comm="nginx" name="unicorn.sock" dev="vda3" ino=17529898 scontext=system_u:syste m_r:httpd_t:s0 tcontext=system_u:object_r:var_lib_t:s0 tclass=sock_file type=AVC msg=audit(1405256491.134:1898): avc: denied { connectto } for pid=28164 comm="nginx" path="/var/lib/redmine-2.5.2/tmp/sockets/unicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:system_r:init_t:s0 tclass=unix_stream_socket
と、やはりSELinuxが原因でした。
このログの抜粋をaudit2allowにかけます。
~$ sudo cat /var/log/audit/audit.log | grep nginx | audit2allow #============= httpd_t ============== allow httpd_t init_t:unix_stream_socket connectto; allow httpd_t var_lib_t:sock_file write;
ポリシーファイル形式(テキスト)にします。
~$ sudo cat /var/log/audit/audit.log | grep nginx | audit2allow -m nginx module nginx 1.0; require { type httpd_t; type init_t; type var_lib_t; class sock_file write; class unix_stream_socket connectto; } #============= httpd_t ============== allow httpd_t init_t:unix_stream_socket connectto; allow httpd_t var_lib_t:sock_file write;
内容が妥当であれば、この内容でポリシーファイル形式(バイナリ)を作成します。
~$ sudo grep nginx /var/log/audit/audit.log | audit2allow -M nginx ~$ ls nginx.pp
ポリシーファイル形式(バイナリ)を適用します。
~$ sudo semodule -i nginx.pp
unicornとnginxを起動します。
~$ sudo systemctl start redmine-unicorn.service ~$ sudo systemctl start nginx.service
unicornを自動起動設定します。
~$ sudo systemctl enable redmine-unicorn.service
参考資料¶
SELinux policy for nginx and GitLab unix socket in Fedora 19