RedmineをCentOS 8上で動かすーUnicornとNginx編¶
- 目次
- RedmineをCentOS 8上で動かすーUnicornとNginx編
RedmineをCentOS 8上で動かすためのセットアップメモです。
RedmineをCentOS 7上で動かすーUnicornとNginx編のCentOS 8版です。
動作環境¶
仮想化環境¶
項目 | 内容 | 備考 |
---|---|---|
仮想ホストOS | Windows 10 Pro 1909 64bit版 | |
仮想化ソフトウェア | Hyper-V | Windows 10標準搭載 |
仮想CPU数 | 2 | |
仮想メモリ | 2048MB | |
ディスクイメージ | VHDX |
Redmine動作環境¶
項目 | 内容 | 備考 |
---|---|---|
OS | CentOS 8.1 1911 | |
Redmine | 4.1.1 | |
Ruby | 2.6.3 | |
RDBMS | MariaDB 10.3.17 | |
Rackサーバー | Unicorn 5.5.4 | |
Webサーバー | Nginx x |
Redmine構築の準備¶
開発ツール類のインストール¶
開発ツール一式をインストールします。
# dnf groupinstall "Development Tools" :
上述開発ツール一式("Development Tools")には含まれていないパッケージを追加インストールします。
ただし、CentOS 7の時に入れていたパッケージのうち以下はCentOS 8では提供されていないので、以下のインストールは保留して次へ進みます。
- libyaml-devel
- ImageMagick
- ImageMagick-devel
# dnf install openssl-devel readline-devel zlib-devel curl-devel
RDBMS MariaDBのインストール¶
現行のRedmineをMySQL(MariaDB)で運用しているので、ここではMariaDBを入れます。
MariaDBは、モジュラーリポジトリで提供されています。
# dnf module list mariadb CentOS-8 - AppStream Name Stream Profiles Summary mariadb 10.3 [d] client, server [d], galera MariaDB Module # dnf module install mariadb/server
開発用ライブラリをインストール
# dnf install mariadb-devel
perlの依存関係で問題報告¶
インストールされたパッケージを確認したところ、問題報告が・・・
# dnf list installed | grep maria モジュラーの依存に関する問題: 問題 1: conflicting requests - nothing provides module(perl:5.26) needed by module perl-DBD-MySQL:4.046:8010020191114030811:073fa5fe-0.x86_64 問題 2: conflicting requests - nothing provides module(perl:5.26) needed by module perl-DBI:1.641:8010020191113222731:16b3ab4d-0.x86_64 :
perlコマンドは実行可能です。
#dnf module list perl CentOS-8 - AppStream Name Stream Profiles Summary perl 5.24 common [d], minimal Practical Extraction and Report Language perl 5.26 [d] common [d], minimal Practical Extraction and Report Language ヒント: [d]efault, [e]nabled, [x]disabled, [i]nstalled
ぐぐってみたところ、module perlをenableすると解消できるとの記載を見かけたので対応を実施。
https://centosfaq.org/centos/yum-dnf-possible-confusion-centos-8/
# dnf module enable perl:5.26 依存関係が解決しました。 ================================================================================ パッケージ アーキテクチャー バージョン リポジトリー サイズ ================================================================================ モジュールストリームの有効化: perl 5.26 トランザクションの概要 ================================================================================ これでよろしいですか? [y/N]: y 完了しました!
MariaDBの設定¶
- /etc/my.cnf.d/mariadb-server.cnf の編集
[mysqld] + character-set-server=utf8mb4
- /etc/my.cnf.d/mysql-clients.cnf の編集
[mysql] + default-character-set = utf8mb4 + show-warnings
MariaDBのサービス起動設定¶
# systemctl enable --now mariadb
MariaDBは、同一マシン上で実行するRedmineプロセス、および同一マシン上にログインしたコンソールから接続するので、ファイアウォール設定は省略します。
MariaDBのrootアカウントにパスワード設定¶
# mysql -uroot MariaDB [(none)]> SELECT user,host,password FROM mysql.user; +------+-----------+----------+ | user | host | password | +------+-----------+----------+ | root | localhost | | | root | aberlour | | | root | 127.0.0.1 | | | root | ::1 | | +------+-----------+----------+ 4 rows in set (0.000 sec) MariaDB [(none)]> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('magdala'); Query OK, 0 rows affected (0.00 sec) MariaDB [none]> SET PASSWORD FOR 'root'@'aberlour' = 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)
Rubyのインストール¶
Redmine 4.0.1 でRuby 2.6に対応しています。
https://www.redmine.org/issues/30118
CentOS 8では、ruby 2.5と2.6が提供されています。
# dnf module list ruby CentOS-8 - AppStream Name Stream Profiles Summary ruby 2.5 [d] common [d] An interpreter of object-oriented scripting language ruby 2.6 common An interpreter of object-oriented scripting language ヒント: [d]efault, [e]nabled, [x]disabled, [i]nstalled
デフォルトは2.5ですが、今回は2.6をインストールします。
# dnf module enable ruby:2.6 依存関係が解決しました。 ================================================================================ パッケージ アーキテクチャー バージョン リポジトリー サイズ ================================================================================ モジュールストリームの有効化: ruby 2.6 トランザクションの概要 ================================================================================ これでよろしいですか? [y/N]: y 完了しました! # dnf module list ruby CentOS-8 - AppStream Name Stream Profiles Summary ruby 2.5 [d] common [d] An interpreter of object-oriented scripting language ruby 2.6 [e] common An interpreter of object-oriented scripting language ヒント: [d]efault, [e]nabled, [x]disabled, [i]nstalled # dnf module install ruby/common :
# dnf install ruby-devel rubygem-bundler :
Redmineのインストール¶
redmineアプリケーション実行用アカウントの作成¶
Readmineアプリケーションをroot権限で実行することは望ましくないので、Redmineを実行する専用のユーザーアカウントを作成します。
# useradd redmine # passwd redmine ユーザー redmine のパスワードを変更。 新しいパスワード: ******** 新しいパスワードを再入力してください: ******** passwd: すべての認証トークンが正しく更新できました。
redmineのリポジトリのクローンを作成¶
Redmineを、/var/lib/ディレクトリ下に、リポジトリのクローンとして展開します。
Redmineの公式リポジトリはSubversionですが、githubにミラーが公開されているので、そちらから取得します。
ブランチ名を指定して取得します。Redmine 4.1系は、ブランチ名が4.1-stableとなります。
# cd /var/lib # git clone -b 4.1-stable https://github.com/redmine/redmine.git redmine-4.1-stable : # chown -R redmine.redmine redmine-4.1-stable
Redmineデータベースの設定¶
データベース設定ファイル¶
- /var/lib/redmine-4.1-stable/config/database.yml
Redmineにはサンプルとしてdatabase.yml.sampleが含まれているので、このサンプルからMySQL用の設定を抜き出し修正するとよいでしょう。production: adapter: mysql2 database: redmine host: localhost username: redmine password: xxxxxxxx encoding: utf8mb4
- サンプルにはproduction以外にdevelopment、testの設定がありますが、通常productionのみ使用するので設定はproductionだけ記述します。
- adapter項はMariaDBはmysql2を指定します。
- database項はMariaDB上でRedmineのテーブルを収容するデータベース名を指定します。
- username項はMariaDBのデータベースに接続するMariaDBのユーザー名を指定します。MariaDBのユーザーは後の手順で作成します。
- password項はusernameで指定したMariaDBのユーザーのパスワードを指定します。
- encoding項はMariaDBで使用する文字エンコーディングを指定します。通常utf8mb4です。
MariaDBのデータベースユーザーのパスワードを記述しているのでパーミッションを厳しく設定しておきます。
$ chmod 600 /var/lib/redmine-4.1-stable/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 9 Server version: 10.3.17-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation 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 | +--------------------+ 4 rows in set (0.00 sec)
MariaDB上にRedmine接続用ユーザーを作成¶
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-4.1-stable/config/configuration.yml
を作成します。
production: email_delivery: delivery_method: :smtp smtp_settings: address: "localhost" port: 25
上記例では記載していませんが、メールサーバによってはパスワードを記述するのでパーミッションを厳しく設定しておきます。
$ chmod 600 /var/lib/redmine/config/configuration.yml
Rubyモジュール群のインストール¶
DNS名前解決結果からIPv4を優先使用する¶
rubyモジュールのリポジトリである rubygems.org はDNSで名前解決をするとIPv6とIPv4のアドレスを返却しますが、このうちIPv6アドレスでrubygems.orgに接続しようとしても無応答でインストールが失敗します。
回避策として、このマシンの名前解決優先順を RFC 3484の規定順ではなく、IPv4を優先するよう変更します。変更は、getaddrinfo関数の振る舞いを変更する設定ファイル/etc/gai.conf
に記述します。
- /etc/gai.conf を新規作成し以下を記述
precedence ::ffff:0:0/96 100
設定ファイルを作成したらマシンを再起動します。
Rubyモジュールのインストール¶
Redmine本体が依存するRubyモジュール群をインストールします。Rubyモジュールのインストールには、rubyのbundlerを使用します。
Redmineが依存するRubyパッケージは、Redmineのインストールディレクトリ下のvender/bundlerを指定し、そこへインストールします。
ユーザーredmineで以下を実行します。
~$ cd /var/lib/redmine-4.1-stable 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... :
Redmineの初期化¶
Redmine本体および依存するRubyモジュールのインストールが終わったら、Redmineの初期化を行います。
セッションデータ暗号化の鍵生成¶
改ざん防止のため、セッションデータを格納するクッキーを暗号化する鍵をランダムに生成します。
redmineユーザーで以下を実行します。
$ bundle exec rails generate_secret_token
- 注記)bundlerでRedmine固有ディレクトリ(--path vendor/bundler)にRubyモジュールをインストールしたので、railsコマンドを実行する際はbundle exec rails xxx のようにbundle execをつけて実行する必要があります。
データベースのスキーマを構築¶
Redmineが使用するデータベースにスキーマを構築します。
redmineユーザーで以下を実行します。
$ bundle exec rails db:migrate RAILS_ENV=production :
動作確認¶
Redmine(Ruby on Rails)デフォルトのWebアプリケーションサーバー WEBrick でRedmineの動作確認をします。
ファイアウォールで一時的にポート3000を許可¶
以下のコマンドで一時的にファイアウォールでポート3000を許可します。永続設定ではないので再起動すれば3000の許可は消えています。
# sudo firewall-cmd --add-port=3000/tcp
WEBrickサーバーでRedmineを実行¶
$ bundle exec rails server -e production => Booting WEBrick => Rails 5.2.4.2 application starting in production on http://0.0.0.0:3000 => Run `rails server -h` for more startup options [2020-04-19 23:14:33] INFO WEBrick 1.4.2 [2020-04-19 23:14:33] INFO ruby 2.6.3 (2019-04-16) [x86_64-linux] [2020-04-19 23:14:33] INFO WEBrick::HTTPServer#start: pid=11651 port=3000
ブラウザから、ポート3000へアクセスしRedmineの画面が表示されることを確認します。
Unicornのセットアップ¶
Rubyアプリケーションを動かすアプリケーションサーバー(Rackサーバー)のUnicornをセットアップします。
Unicornのインストール¶
UnicornはRubyモジュール(gem)として提供されるので、bundlerでインストールします。
Redmineをインストールしたディレクトリ下(例:/var/lib/redmine-4.1-stable)に、Gemfile.localというファイルを作成し、そこに以下を記述します。
gem "unicorn"
Redmineをインストールしたディレクトリで bundle update を実行します。
redmine$ bundle update : Installing kgio 2.11.3 : Installing raindrops 0.19.1 with native extensions : Installing unicorn 5.5.4 with native extensions Bundle updated! Gems in the groups development and test were not installed.
インストール後の単独起動確認¶
コマンドラインからUnicornを起動してRedmineの動作を確認します。
先にWEBrick確認時に一時的にファイアウォールにあけたポート3000を使用します。
$ bundle exec unicorn_rails -l 3000 -E production I, [2020-04-19T23:43:12.051845 #12279] INFO -- : listening on addr=0.0.0.0:3000 fd=7 I, [2020-04-19T23:43:12.052069 #12279] INFO -- : worker=0 spawning... I, [2020-04-19T23:43:12.054041 #12280] INFO -- : worker=0 spawned pid=12280 I, [2020-04-19T23:43:12.054255 #12280] INFO -- : Refreshing Gem list I, [2020-04-19T23:43:12.054374 #12279] INFO -- : master process ready I, [2020-04-19T23:43:15.967983 #12280] INFO -- : worker=0 ready
これでWebブラウザからポート3000で接続し動作確認をします。
参考)コマンドラインオプションは次です。
--listen -l [アドレス:]ポート ソケットのエンドポイントを指定 --config-file -c ファイル 設定ファイルを指定 -D デーモンプロセス起動指定 -E <RAILS_ENV> production等を指定
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の設定¶
CentOS 8で動かすにあたり、少し時間をかけてUnicornの設定ファイル(unicorn.rb および Systemd の service ファイル)の書き方を追究し、理解を深めます。
バージョン非依存な絶対パスをシンボリックリンクで作成¶
Nginxの設定ファイルには、Redmineへの絶対パスを記述する箇所があります。Redmineのバージョンにより絶対パスが異なると、バージョンアップの度に設定ファイルを変更する必要が生じます。これを避けるため、バージョンには依存しないパスをシンボリックリンクで作成します。
# cd /var/lib # ln -s redmine-4.1-stable redmine # ls -l : lrwxrwxrwx. 1 18 4月 20 11:56 redmine -> redmine-4.1-stable drwxr-xr-x. 19 4096 4月 19 23:38 redmine-4.1-stable
設定ファイル(unicorn.rb)¶
Redmineインストールディレクトリ下のconfigディレクトリに、unicorn.rbというファイル名で設定を記述します。
Unicorn起動時にオプションで設定ファイルを指定します。
- 参考:RedmineをCentOS 6上で動かすーUnicornとNginx編に添付のunicorn.rb
- 公式サイトの解説ページ(次のURL)
http://unicorn.bogomips.org/Unicorn/Configurator.html - 公式サイトのUnicorn設定サンプル(次のURL)
http://unicorn.bogomips.org/examples/unicorn.conf.rb
これらを参考にUnicornの設定ファイルを定義します。
- /var/lib/redmine/config/unicorn.rb
# -*- coding: utf-8 -*- # Unicorn設定ファイル # ワーカープロセスの数。1ワーカーで1つのリクエストを処理する。 # ワーカー数が上限に達すると、先行するリクエストが完了するまで待ちとなる。 worker_processes 2 # リクエスト待ち受け口、TCPとUNIXドメインとが指定可能。 listen "/var/run/unicorn/unicorn.sock", :backlog => 32 listen 8282, :tcp_nopush => true # タイムアウト秒数 timeout 30 # 稼働中のプロセスのPIDを書いておくファイル。 pid "tmp/pids/unicorn.pid" # デーモンで起動すると標準出力/標準エラー出力が/dev/nullになるので、 # それぞれログファイルに出力する。 stderr_path 'log/unicorn.stderr.log' stdout_path 'log/unicorn.stdout.log' # マスタープロセス起動時にアプリケーションをロードする(true時)。 # ワーカープロセス側でロードをしないのでメモリ消費、応答性良好になる。 # ただし、ソケットはfork後に開きなおす必要あり。 # HUPシグナルでアプリケーションはロードされない。 preload_app true # unicornと同一ホスト上のクライアントとのコネクション限定で、維持されているかを # アプリケーションを呼ぶ前にチェックする。 check_client_connection false before_fork do |server, worker| # Railsでpreload_appをtrueにしているときは強く推奨 defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! # new master phase out the old master old_pid = "#{server.config[:pid]}.oldbin" if old_pid != server.pid begin sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU Process.kill(sig, File.read(old_pid).to_i) rescue Errno::ENOENT, Errno::ESRCH end end end after_fork do |server, worker| # Railsでpreload_appをtrueにしているときは必須 defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end
この設定ファイルは、Unicornを実行するときにカレントディレクトリが/var/lib/redmine/にあることを前提としています。
worker_processes¶
応答性を良好に保つには、コア数以上のワーカーを指定します。ただし、仮想化環境ではCPU使用率とメモリ使用量を見ながらワーカー数を許容範囲まで増やします。
listen¶
リクエストを受け付けるプロトコルとポート、オプション設定を指定します。
UNIXドメインソケットの場合の例
listen "/var/run/unicorn/unicorn.sock", :backlog => 32
TCPソケットの場合の例
listen 8080, :tcp_nopush => true
- 複数のプロトコルを列挙することで複数のプロトコル・ポートを扱うことができます。
- UNIXドメインソケットはUnicornプロセスとNginxプロセスの間で読み書きする特殊ファイルです。Systemd 環境および SELinux 有効下では、/tmp や Unicornディレクトリ配下に置くことが難しいので、/var/run以下に置きます。/var/run 直下にファイルを作成するにはroot権限が必要なため、Unicorn起動時にroot権限で/var/run/unicornディレクトリを作成し、その後に Unicorn が/var/run/unicorn/unicorn.sockを設ける手順を踏みます。
- 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を記録しておくファイルを指定します。
stderr_path、stdout_path¶
Redmineインストールディレクトリ下のlogディレクトリの中にログファイルを生成します。
preload_app¶
trueに設定すると、マスタープロセス起動時にアプリケーションをロードし、ワーカープロセスをフォークするとアプリケーションが実行可能となります。複数ワーカープロセスでコードを共有するため、メモリ使用効率もよくなります。デメリットは、ワーカープロセスを再起動してもアプリケーションはロードされない点です。
before_fork¶
ワーカープロセスをforkする前にマスタープロセスによって呼ばれます。
USR2シグナルで新旧マスタープロセスが共存する場合は、旧マスタープロセスにQUITシグナルを送って終了させます。
after_fork¶
ワーカープロセスがforkされた後に呼び出されます。
Unicornのサービス化(起動終了設定)¶
- /usr/lib/systemd/system/redmine-unicorn.service
[Unit] Description=Redmine Unicorn Server After=mariadb.service [Service] User=redmine Group=redmine WorkingDirectory=/var/lib/redmine-4.1-stable Environment=RAILS_ENV=production SyslogIdentifier=redmine-unicorn PIDFile=/var/lib/redmine-4.1-stable/tmp/pids/unicorn.pid PermissionsStartOnly=true ExecStartPre=/usr/bin/install -m 755 -o redmine -g redmine -d /var/run/unicorn ExecStart=/usr/bin/bundle exec "unicorn_rails -c config/unicorn.rb -E production" ExecStop=/usr/bin/kill -QUIT $MAINPID ExecReload=/usr/bin/kill -USR2 $MAINPID [Install] WantedBy=multi-user.target
サービス起動順序の制御¶
Redmine(Unicorn)は、起動時にデータベースに接続できないとエラー終了してしまいます。
そこで、[Unit]セクションにAfterで、mariadb.serviceが実行されてからredmine-unicorn.serviceが起動されるよう順序を指定します。
起動プロセスの実行ユーザー・グループ¶
SystemdでExecStartにより実行したプロセスの実行ユーザーをroot以外にする場合、[Service]セクションのUser、Groupでユーザー・グループを設定します。
WorkingDirectoryとPIDFileは実パス(シンボリックリンクではなく)を指定¶
SELinuxの設定上、WorkingDirectoryとPIDFileに設定するパスはシンボリックリンクファイルを含まない実パスで設定します。
起動前に /var/run/unicorn ディレクトリ作成¶
Unicorn起動時にUNIXドメインソケットファイルを/var/run/unicornディレクトリ下に作成します。/var/runディレクトリ直下にファイルを作成するにはroot権限が必要なため、ExecStartPreで/var/run/unicornディレクトリを作成します。ここではディレクトリ作成にinstallコマンドを使っていますが、これはディレクトリ作成とパーミッションの設定をまとめて実施できるためです。
PermissionsStartOnly=true を指定しておくと、UserおよびGourpを指定していてもExecStartPreはroot権限で実行されます。
Unicornサービスの動作確認¶
Systemd からサービスとして起動し動作することの確認を行います。
一時的にファイアウォールの許可¶
一時的にファイアウォールでポート8282を許可します。
# firewall-cmd --add-port=8282/tcp success
Unicornサービスの開始¶
以下のようにsystemctlでstartし、statusを確認し実行状態になっていれば正常に起動しています。
# systemctl start redmine-unicorn # systemctl status redmine-unicorn ● redmine-unicorn.service - Redmine Unicorn Server Loaded: loaded (/usr/lib/systemd/system/redmine-unicorn.service; disabled; vendor preset: disabled) Active: active (running) since Tue 2020-04-21 22:10:00 JST; 2min 28s ago Process: 13131 ExecStartPre=/usr/bin/install -m 755 -o redmine -g redmine -d /var/run/unicorn (code=exited, status=0/SUCCESS) Main PID: 13133 (ruby) Tasks: 7 (limit: 11103) Memory: 194.7M CGroup: /system.slice/redmine-unicorn.service tq13133 unicorn_rails master -c config/unicorn.rb -E production tq13157 unicorn_rails worker[0] -c config/unicorn.rb -E production mq13159 unicorn_rails worker[1] -c config/unicorn.rb -E production 4月 21 22:10:00 pan systemd[1]: Starting Redmine Unicorn Server... 4月 21 22:10:00 pan systemd[1]: Started Redmine Unicorn Server.
Nginxのセットアップ¶
Nginxのインストール¶
$ dnf module list nginx CentOS-8 - AppStream Name Stream Profiles Summary nginx 1.14 [d] common [d] nginx webserver nginx 1.16 common nginx webserver ヒント: [d]efault, [e]nabled, [x]disabled, [i]nstalled
CentOS 8 のリポジトリ(AppStream)にて、Nginxが提供されています。バージョンは1.14と1.16があり、今回は1.16を使用します。
# dnf module install nginx:1.16/common :
サービスを有効化します。
# systemctl enable --now nginx # systemctl status nginx ● nginx.service - The nginx HTTP and reverse proxy server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled) Active: active (running) since Mon 2020-04-20 21:33:30 JST; 44s ago Process: 26791 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS) Process: 26787 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS) Process: 26785 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS) Main PID: 26792 (nginx) Tasks: 3 (limit: 11103) Memory: 13.0M CGroup: /system.slice/nginx.service tq26792 nginx: master process /usr/sbin/nginx tq26793 nginx: worker process mq26794 nginx: worker process 4月 20 21:33:30 pan systemd[1]: Starting The nginx HTTP and reverse proxy server... 4月 20 21:33:30 pan nginx[26787]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok 4月 20 21:33:30 pan nginx[26787]: nginx: configuration file /etc/nginx/nginx.conf test is successful 4月 20 21:33:30 pan systemd[1]: Started The nginx HTTP and reverse proxy server.
ファイアウォールでhttpとhttpsを許可します。
# firewall-cmd --add-service http --permanent success # firewall-cmd --add-service https --permanent success # firewall-cmd --reload success # firewall-cmd --list-services cockpit dhcpv6-client http https ssh
ブラウザからポート80にアクセスし、「Welcome to nginx on Red Hat Enterprise Linux!」が表示されたら確認OKです。
nginxの設定¶
/etc/nginx/conf.d/redmine.conf を新規作成します。
upstream unicorn { server unix:/var/run/unicorn/unicorn.sock; } server { listen 80; server_name _; 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; } error_page 500 502 503 504 /500.html; }
設定ファイルの検証を行います。
# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Nginxでセキュアなアクセス(TLS)を使用¶
Redmineへのアクセスを https 化(TLS化)します。
検証環境では、然るべきSSLサーバー証明書が用意できないので、自己証明書を作成します。
自己証明書の作成¶
秘密鍵の作成(パスフレーズなし)¶
ファイル名:server.key
~$ openssl genrsa -out server.key 2048 Generating RSA private key, 2048 bit long modulus (2 primes) ................................+++++ .........+++++ e is 65537 (0x010001)
証明書署名要求(CSR:Certificate Signing Request)の作成¶
ファイル名:server.csr
~$ openssl req -utf8 -new -key server.key -out server.csr You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [XX]: JP <--- 国(日本ならJP) State or Province Name (full name) []:Kanagawa <--- 県 Locality Name (eg, city) [Default City]:Kawasaki <--- 市 Organization Name (eg, company) [Default Company Ltd]:TK <--- 会社・組織 Organizational Unit Name (eg, section) []: <--- 部門(未入力可) Common Name (eg, your name or your server's hostname) []:alfa.torutk.com <--- サーバードメイン名(未入力可) Email Address []: <--- 管理者メール(未入力可) Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: <-- (未入力可) An optional company name []: <-- (未入力可) certs$
- Common Name(サーバードメイン名)は、次の手順でSANを指定することで無視されるので未入力
Subject Alternative Name(SAN) 情報の作成¶
ファイル名:san.txt
まず、最近のWebブラウザでは、Subject Alternative Name(SAN) を含めないとアクセスができないのでまずSAN情報をテキストファイルに記述します。
subjectAltName = DNS:*.torutk.com
ワイルドカードを使って複数のホスト名に対応させることができます(DNS指定の場合)。
自己署名証明書の作成¶
ファイル名:server.crt
~$ openssl x509 -in server.csr -out server.crt -extfile san.txt -req -signkey server.key -days 3650 Signature ok subject=C = JP, ST = Kanagawa, L = Kawasaki, O = TK, CN = alfa.torutk.com Getting Private key certs$ sudo chmod 600 server.key
作成したファイルの配置¶
上述で作成した秘密鍵と自己署名証明書を、次の場所に配置します。
ファイル名 | 配置ディレクトリ |
---|---|
server.key | /etc/pki/nginx/private |
server.crt | /etc/pki/nginx |
- nginx とその下の private ディレクトリは配置前に作成しておきます。
Nginx設定ファイルの編集・作成¶
- /etc/nginx/nginx.conf から、server {...} の記述を削除
--- /etc/nginx/nginx.conf.orig 2019-11-23 04:18:57.000000000 +0900 +++ /etc/nginx/nginx.conf 2020-04-22 10:15:01.376933021 +0900 @@ -35,26 +35,6 @@ # for more information. include /etc/nginx/conf.d/*.conf; - server { - listen 80 default_server; - listen [::]:80 default_server; - server_name _; - root /usr/share/nginx/html; - - # Load configuration files for the default server block. - include /etc/nginx/default.d/*.conf; - - location / { - } - - error_page 404 /404.html; - location = /40x.html { - } - - error_page 500 502 503 504 /50x.html; - location = /50x.html { - } - } # Settings for a TLS enabled server. #
- /etc/nginx/conf.d/redmine.conf
upstream unicorn { server unix:/var/run/unicorn/unicorn.sock; } server { listen 80 default_server; listen [::]:80 default_server; server_name _; return 301 https://$host$request_uri; } server { listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; server_name _; root /var/lib/redmine/public; ssl_certificate "/etc/pki/nginx/server.crt"; ssl_certificate_key "/etc/pki/nginx/private/server.key"; ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; ssl_ciphers PROFILE=SYSTEM; ssl_prefer_server_ciphers on; include /etc/nginx/default.d/*.conf; 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; } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } }
Redmineのデータ移行¶
旧バージョンのRedmineからデータを引き継いで運用する場合の手順です。
データベースを移行(旧Redmine環境からRDBMSのデータをエクスポートし、新Redmine環境のRDBMSへインポート)すると、プラグインのデータも含まれています。
そこで、Redmine本体とデータベースを使用するプラグインをあらかじめインストールしてからデータベースのマイグレーションを実行します。
プラグインの移行¶
旧Redmine 3.4 から Redmine 4.1 へバージョンアップする場合の、プラグインの移行についてです。
現在移行対象とする Redmine 3.4 で稼働しているプラグインと、Redmine 4.1対応状況です。
No | プラグイン名 | 稼働Ver. | DB? | Redmine 4.1対応状況 | 移行方針 |
---|---|---|---|---|---|
1 | clipboard_image_paste | 1.13 | 無 | 未 | 放棄(画像ペーストが標準機能に登録) |
2 | redmine_banner | 0.1.2 | 有 | 済 | バージョンアップ |
3 | redmine_github_hook | 2.2.1 | 無 | 済 | バージョンアップ |
4 | redmine_glossary | 0.9.2 | 有 | 済 | バージョンアップ1 |
5 | redmine_issue_templates | 0.2.2-dev | 有 | 済 | バージョンアップ2 |
6 | redmine_latex_mathjax | 0.3.0 | 無 | 済 | バージョンアップ3 |
7 | redmine_startpage | 0.1.0 | 無 | 済 | 放棄4 |
8 | redmine_wiki_extensions | 0.8.2 | 有 | 済 | バージョンアップ |
9 | redmine_wiki_lists | 0.0.9 | 無 | 済 | バージョンアップ |
10 | redmine_xls_export | 0.2.1.t11 | 無 | 済 | 同一バージョン使用5 |
11 | sidebar_hide | 0.0.8 | 無 | 未 | 同一バージョン使用6 |
12 | view_customize | 2.1.0 | 有 | 済 | バージョンアップ |
1 本家は未対応、フォーク版がいくつかあり、4.x対応
https://github.com/torutk/redmine_glossary
2 IE11対応が必要なら0.3-stableブランチ、不要なら1.0にバージョンアップ
3 Redmine本家サイトのPlugin Directoryには、Redmine 4対応のフォーク版が掲載(2020-04-22現在)
4 プラグインの数を減らすため放棄、routes設定で直接制御
https://torutk.hatenablog.jp/entry/20130701/p1
5 URLは https://github.com/two-pack/redmine_xls_export
類似プラグインに Redmine XLSX format issue exporter あり
6 Redmine 4対応はうたっていないので、だめな場合の代替手段も検討する
類似プラグイン Redmine Toggle Sidebar
View Customizeプラグインで制御 Redmineでサイドバーを開閉可能とし、かつ縦スクロールでも隠れないようにする
移行しないプラグインについて、データベースを使用しないプラグインは、Redmine 4.1で入れないだけで問題はありません。データベースを使用するプラグインは、データベースを元に戻す必要があります。これは移行作業の際に旧Redmine 3.4上で当該プラグインのmigrateでバージョン0に戻す(プラグインが変更したデータベーススキーマを戻す)ことで対処します。
データベースを使用するプラグインのインストール¶
- redmine_banner
- redmine_issue_templates
- redmine_wiki_extensions
- view_customize
- redmine_glossary
~$ cd /var/lib/redmine/plugins plugins$ git clone https://github.com/akiko-pusu/redmine_banner.git : plugins$ git clone https://github.com/akiko-pusu/redmine_issue_templates.git : plugins$ git clone https://github.com/haru/redmine_wiki_extensions.git : plugins$ git clone https://github.com/onozaty/redmine-view-customize.git view_customize : plugins$ git clone https://github.com/torutk/redmine_glossary.git : plugins$ ls README redmine_glossary redmine_wiki_extensions redmine_banner redmine_issue_templates view_customize
プラグインのデータベースマイグレーションは、後の手順で実施します。
データ移行¶
旧Redmineから新Redmineへデータ移行をするには次を実施します。
- データベース移行
- 添付ファイル移行
- リポジトリ移行
データベース移行¶
まずはRedmine 3.4のデータベースをエクスポートします。
~$ mysqldump -uredmine redmine > mysql_dump.sql
エクスポートしたデータベースを、Redmine 4.1のデータベースにインポートします。
~$ mysql -u redmine -D redmine < mysql_dump.sql
データベースの内容を移行したら、続いてデータベースのマイグレーションを実施します。
それには、まずRedmine本体のマイグレーションを行い、次にプラグインのマイグレーションを実施します。
Redmine本体のマイグレーション¶
~$ cd /var/lib/redmine-4.1-stable redmine-4.1-stable$ bundle exec rails db:migrate RAILS_ENV=production :
Redmineプラグインのマイグレーション¶
redmine-4.1-stable$ bundle exec rails redmine:plugins:migrate RAILS_ENV=production
文字コード(character set)、照会順序(collocation)の変更¶
MariaDBの設定では、文字コードをutf8mb4(各文字は最大4バイトで補助文字を含む)としましたが、過去のデータベースデータはutf8(各文字は最大3バイト)である場合、インポートした結果は過去の設定であるutf8のままとなります。このテーブルに4バイトからなるUTF-8文字を書き込むとエラーになります。Redmineの場合は、例えば「絵文字を含む文章をWiki記述して保存したところInternal Errorが返ってきた」という状況になります。
この場合、インポートした後に各テーブルの文字コード、照会順序を変更します。
指定したテーブルとそのカラムの文字コード、照会順序を変更するコマンドを次に示します。
> ALTER TABLE versions CONVERT TO CHARACTER SET utf8mb4;
versionsテーブルのCHARACTER SETはutf8mb4に、同テーブルのCOLLATIONはutf8mb4_generic_ciになりました。
RedmineデータベースのすべてのテーブルのCHARACTER SETをutf8からutf8mb4に変更するのに、テーブル1つ1つについて上述のコマンドを手打ちするのは大変です。そこで、ごそっとスクリプトを作って実行します。
~$ for t in $(mysql -uredmine -pxxxxxxxx redmine -e "show tables" -s -N); ~ do echo "ALTER TABLE $t CONVERT TO CHARACTER SET utf8mb4;"; done > alter_all_tables_charset_utf8mb4.sh
生成したスクリプトファイルの中身は次のようになります(抜粋)。
ALTER TABLE ar_internal_metadata CONVERT TO CHARACTER SET utf8mb4; ALTER TABLE attachments CONVERT TO CHARACTER SET utf8mb4; ALTER TABLE auth_sources CONVERT TO CHARACTER SET utf8mb4; ALTER TABLE banners CONVERT TO CHARACTER SET utf8mb4; ALTER TABLE boards CONVERT TO CHARACTER SET utf8mb4; :
実行します。
~% mysql -uredmine -pxxxxxxxx redmine < alter_all_tables_charset_utf8mb4.sh
添付ファイルの移行¶
redmineインストールディレクトリの下のfilesディレクトリの内容を旧Redmineから新Redmineへコピーします。
リポジトリの移行¶
旧Redmineと同じマシン上にあるSubversionとGitとをバックアップし、新Redmineのマシンに移行します。
Subversionの移行¶
旧subversionリポジトリをバックアップします。
~$ svnadmin dump /var/lib/svn/my_repo > svn_my_repo-`date +%Y%m%d`.dump
- 設定ファイル(リポジトリのconfディレクトリ以下)に手を入れていたら、上述dumpではバックアップされないので手動でコピーしておきます。
新subversionリポジトリに復元します。
/var/lib/svn、/var/lib/subversion/repo、/var/www/svn にはSELinuxでHTTPサーバーからアクセスできる設定が定義済みなので、このいずれかにsubversionリポジトリを設けるとよいでしょう。
# mkdir /var/lib/svn # svnadmin create /var/lib/svn/my_repo # svnadmin load /var/lib/svn/my_repo < svn_my_repo-202004231030.dump
TODO: apache httpdをインストール後、/var/lib/svn以下のオーナー、グループをapacheに変更し、またhttpdからRedmine認証を経てアクセスする設定を設ける
Gitの移行¶
旧Gitリポジトリをバックアップします。
~$ git clone --mirror /var/lib/git/my_repo.git git_my_repo-`date +%Y%m%d`.git ~$ tar czf git_my_repo-202004231100.tgz git_my_repo-202004231100.git
新gitリポジトリに復元します。
CentOS 8のSELinuxポリシーでは、/var/lib/git にはSELinuxのgit_sys_content_t タイプが、/var/www/git にはSELinuxのgit_content_t タイプが定義されています。
apache httpd から smart http 経由でgitリポジトリにアクセスする際は、gitリポジトリへの読み書き、および各リポジトリディレクトリのhooksディレクトリにあるスクリプトの実行が必要です。そこで、SELinuxポリシーの設定を変更します。
# semanage fcontext -m -t git_rw_content_t '/var/lib/git(/.*)?' # semanage fcontext -a -t git_script_exec_t '/var/lib/git/[^/]+/hooks(/.*)?' # restorecon -R /var/lib/git
残りのプラグインのインストール¶
データベースを伴わないプラグインをインストールします。
- redmine_github_hook
- redmine_latex_mathjax
- redmine_wiki_lists
- redmine_xls_export
- sidebar_hide
redmine_github_hook¶
redmine_latex_mathjax¶
redmine_wiki_lists¶
redmine_xls_export¶
sidebar_hide¶
plugin$ git clone https://gitlab.com/bdemirkir/sidebar_hide.git
旧Redmineのプラグインの代替¶
次のプラグインはRedmine 4.1に対応していないので、代替手段を講じます。
- clipboard_image_paste
- redmine_startpage
clipboard_image_paste¶
Redmine 4.1からは、画像データをクリップボードにコピーした状態でWiki編集領域にペースト操作をすると、添付ファイルに画像ファイルが自動で追加され、Wiki編集領域には画像ファイルの表示記法(!でファイル名を挟んだもの)が挿入されます。
なお、ファイル名は自動で付与され、後から名前を変えるのは簡単ではなさそうです。
redmine_startpage¶
本プラグインの使用はやめて、以下の修正を直接Redmineに入れます。
- config/routes.rb を変更
Rails.application.routes.draw do - root :to => 'welcome#index', :as => 'home' + root :to => 'wiki#show', :project_id => 'swe', :as => 'home'
ここで、sweはプロジェクト識別子です。
テーマ¶
旧Redmineで使用していた Gitmike テーマが、sidebar hideプラグインと干渉しているので、別なテーマを探します。
候補の調査¶
- PurpleMine2
サイドバーを左側に配置し、折り畳み機能を持つ。このテーマを使うときは機能が被るのでsidebar hideプラグインは削除する。 - Blueclair
Redmineのオリジナルテーマを基調に見やすく改善。sidebar hideと共存可。
落ち穂ひろい¶
Redmine 4.1系をCentOS 8で動かすにあたり、残る雑多なことをメモ
ImageMagickを入れる¶
CentOS 8(Red Hat Enterprise 8)では、OS提供パッケージからImageMagickが削除されています。
ImageMagickを入れない状態では、thumbnailマクロが機能しない等の制約があります。
EPELリポジトリからImageMagickが提供されているので、制約が受け入れられない場合(例えば本サイト。thumbnailを使いまくっています)、EPELからImageMagickをインストールします。
# dnf --enablerepo=epel install ImageMagick :
なお、Ruby gemモジュールを入れるときに、--withoutオプションでrmagickを除外していましたが、最近のRedmineはrmagickを使わずmini_magickを使っているのでbundleの入れ直し等は不要でした。