第9回redmine.tokyo勉強会

redmine.tokyo勉強会に参加した。今回で9回目ということだったんだけど、今までそんな勉強会が存在することは知らなかった。

参加したセッションのメモはこちら
第9回redmine.tokyo勉強会 2015/11/27

収穫

Lychee Redmine

アジャイルウェアの川端さんがセッションで紹介していたもの。有償だけどガントチャートの管理が便利そうなプラグイン。依然、似たようなプラグインを探したことがあったけど有償は除外していたのであまり知らなかった。

Redmineのプラグインはバージョンによって動かなくなっていることが多く、GitHubにあるものは誰かがForkして動くようにしているけどFork元の本家にはPRする文化はあまり無さそうな気がしていて亜流がいっぱいあってよくわからなくなっていることが多い。そういう状態だから自分もForkしてとりあえず動くようにして使うという悪循環になっているので、有償でもちゃんとメンテナンスしてくれるものを使ったほうが良いのかもしれない。

Redmine 3.2 レスポンスデザイン

@naitohさんのRedmine最新動向のセッションで、3.2でいろいろ改善されることを聞いた。レスポンスデザインになるそうで、自作のテーマにも影響がでてくるかもしれないので要確認。

View Customize Plugin

onozaty/redmine-view-customize

@onozatyさんがLTで紹介していたもの。任意の画面にcssやjavascriptを画面をカスタマイズできるプラグイン。テーマを使わなくても使えるので痒いところに手が届きそう。

開発プロセス

勉強会ではRedmineというツールの話、Redmineを使った開発プロセスの話が混ざってくることが興味深かった。チケット駆動開発の話や、どこまでをチケットで管理するかなどの話は悩みの種であるので共感できる話は多い。

ただ正直なところ個人的にはRedmine自体を管理するのが面倒だし、新しいものを使いたいのでGitHub Enterprise使ってGitHub FlowとかPR駆動開発とかやりたかったりする。

とはいえどんなツールを使っても、どんな開発プロセスを導入しようとも、人が絡んでソフトウェアを開発する以上、ためになる話はいいっぱい聞ける気がする。

コンテキスト

Redmineの管理者が多く参加されていたので、コンテキストが近くディスカッションなども機能するのかなと思った。

イベント&コミュニティスペース dots.

dotsさんのイベント&コミュニティスペースが会場だったんだけど、近いし、イベント開催以外でも貸し切りじゃないときはコワーキングスペースとしても使えるらしい。

コース 料金(税込)
1時間 500 円
3時間 1,300 円
5時間 2,000 円
終日 2,500 円

Redmineを全員で使ったらカオスになった話

タスク管理のツールとしてオープンソースのRedmineを使っていた。エンジニアだけで使っているうちは特に問題はなかった。エンジニアが10数名、全員でも40人規模の会社なので全員の作業を見える化したいよねという話が上がって全員でRedmineを使い始めることになった。そして何が起きたか。

プロジェクトが乱立した

エンジニアであれば「プロジェクト」は単位は大体想像がつくと思う。しかしながらツール上ではその単位でプロジェクトは作られなかった。「正規のプロジェクト」の小規模な機能追加であっても「○○対応プロジェクト」と銘打たれツール上にプロジェクトが作成された。

「〜対応プロジェクト」「〜導入プロジェクト」「〜検討プロジェクト」「〜プロジェクト」・・・どんな言葉にもプロジェクトを付ければ”プロジェクト”にできるんだということは新鮮ではあったし、勉強にもなった。(そもそも”プロジェクト”って何だ?)

そして多数のプロジェクトがそれほどグルーピングもされずに乱立されていった結果どうなったか。

誰が何をやっているかわからなくなった

ツール上に作成された「○○プロジェクト」は実際に手を動かす作業者しかプロジェクトメンバーに登録されていない。Redmineは様々な変更をプロジェクトメンバーに通知してくれるが乱立した「ツール上のプロジェクト」では直接の作業者へしか通知がされないため全体を把握するのが難しくなった。

スケジュールが管理できなくなった

何を言っているかわからねーと思うが俺も何を言っているかわからない。

ようはバージョンやマイルストーンに変わる単位としてプロジェクトが生成されていた。最初はそれでも大丈夫だったのだろうが、沢山プロジェクトが作成されるとどれが現在アクティブなプロジェクトがわからず、今何がどれだけ進んでいるのかはさっぱりわからなくなった。

そして俺が死んだ

とあることで社員1人1人にヒアリングを行っていた。(この話も別の機会に書きたい)みんなが口をそろえて「誰が何をやっているかわからない」「今どの案件が進んでいるのかわからない」と言い出していた。「Redmine上に全部書いてありますよね?」と尋ねても同じ回答が返ってきてようやく社内の幾つかのプロジェクトが機能していないことに気付いた。

奇妙な使い方だとは思いつつ当人達はそれが使いやすい方法なのだろうと傍から見ていたけど実際には使いやすい方法ではなかったのだ。

そこから乱立したプロジェクトの統合やプロジェクト上のタスクやWikiの大移動を始めた。悲しいかなRedmineではマイルストーンやWikiのプロジェクトの移動に対応していないので、わざわざRedmineのプラグイン(タスク)を書いてActiveRecordのモデルやSQL文を直接実行したりした。直接実行するのは怖いからわざわざVagrant+Chef Soloで同じ環境を作って検証することもした。

何で俺がこんなことをしているのかと思いつつ、各メンバーに移動していいか確認しながら1週間かけてようやく整理ができた。結果的には全体が把握できるようなプロジェクト階層と、プロジェクトを分割した方がやりやすいところはそのまま続けるハイブリッド運用に落ち着いた。

真の問題

慣れていないことをするのだから何かしら失敗すると思っていたし、とりあえずやってみるという話だったので、あれこれ余計な口出しをせず、実際に問題が起きた後で自分たちなりの使い方を模索していけばいいと思っていた。だから非効率な使い方をする人がいたのは想定内だったし、整理した結果それなりの運用に復旧したのでそこは失敗は成功の母。根本的な問題は誰もが良いやり方だと思っていないのにも関わらずそれを変えようと相談したり実行したりしなかったところだ。もっと早く手を打っていれば誰かが致命傷を負わずに済んだはず。

ルールやツールは守るため、使うためにあるのではなく、いいアウトプットを出すための手段でしかない。結局のところ良い仕事をする、良いものを作るのは運用ルールでもツールでもなく人だということである。しかし自発的に人を巻き込んで問題を解決できる人はそうはいない。経営者はみんなにそうして欲しいだろうしそういった文化を作りたいと思うだろうが、営業時間会社にいればサラリーが貰える環境ではなかなかそういうわけにはいかない。周りに流されて仕事をする方が圧倒的に楽だからだ。

僕はコードを書いてツールを向上したりデータを整理することはできても、人の心を変えたり教育する力はまだ持ち合わせていない。それをどこまでやるべきなのかという落とし所もよくわかっていない。客観的に見ても僕が開発に時間を割けないことは会社としてはマイナスなはずだ。開発ができない人や苦手な人でもモチベーターとして有能な人がいるならその人に任せたいのが正直なところ。

ベホマやザオリク唱えられるMPにも限界がある。

何故かこの記事に反響があるようで、2つのカテゴリの反応があるのを見て自分の文章が悪いことに気が付いて多少修正してます。

それは
・Redmineの導入を失敗した話・苦労話
・効率の悪いやり方をやり続けてしまう意識の問題
の2つの論点をごっちゃにしてしまったところ。

前者については本当笑い飛ばしてもらって同じ過ちを冒さないようにしていただければ書いた甲斐があったというもの。後者についてはどうしていいかわからないのでMPが尽きるまでになんとかしたい。

個人的にはRedmine自体の課題やRedmineの利用にはルールが必要という話はどうでもよくて、良い仕事、良い物を創るために方法を改善していくところしか興味が無い。

中途半端にMySQL 5.6が入ってRedmineが動かなくなった

Debian7にてsslの問題修正などをアップデートするためにパッケージの更新をしていたところRedmineが動かなくなっていた。

Unicornを実行すると以下のようなエラーが出力されている。

Incorrect MySQL client library version! This gem was compiled for 5.5.35 but the client library is 5.6.17

mysqlもアップデートされていたけどちゃんと見ていなかった。調べてみると面倒なことになっている。

$ sudo dpkg -l | grep mysql
ii  libdbd-mysql-perl                  4.021-1+b1                    amd64        Perl5 database interface to the MySQL database
ii  libmysqlclient-dev                 5.6.17-1~dotdeb.1             amd64        MySQL database development files
rc  libmysqlclient16                   5.1.66-0+squeeze1             amd64        MySQL database client library
ii  libmysqlclient18:amd64             5.6.17-1~dotdeb.1             amd64        MySQL database client library
ii  mysql-client                       5.5.35+dfsg-0+wheezy1         all          MySQL database client (metapackage depending on the latest version)
ii  mysql-client-5.5                   5.5.35+dfsg-0+wheezy1         amd64        MySQL database client binaries
ii  mysql-common                       5.6.17-1~dotdeb.1             all          MySQL database common files, e.g. /etc/mysql/my.cnf
ii  mysql-server                       5.5.35+dfsg-0+wheezy1         all          MySQL database server (metapackage depending on the latest version)
rc  mysql-server-5.1                   5.1.66-0+squeeze1             amd64        MySQL database server binaries and system database setup
ii  mysql-server-5.5                   5.5.35+dfsg-0+wheezy1         amd64        MySQL database server binaries and system database setup
ii  mysql-server-core-5.5              5.5.35+dfsg-0+wheezy1         amd64        MySQL database server binaries
ii  php5-mysql                         5.5.11-1~dotdeb.1             amd64        MySQL module for php5

mysqlは5.5が入っているが、開発用ライブラリはdotdebの5.6が入ってしまっている。dotdebはNginxやPHPの新しいバージョンをリリースしているリポジトリ。(紛らわしいがphp5-mysqlが5.5なのはPHPの現行最新版が5.5.11なため)

mysqlパッケージを検索するとdotdebがmysql-server-5.6を公開しているようなので5.6にあげてしまうことにした。

mysql-*-5.5mysql-*-5.6は別パッケージでmysql-*-5.6を入れようとしてもうまくアップグレードされないようなので、5.5を削除してから5.6を入れるみようとした。すると、そもそもmysql-clientmysql-serverのバージョンもdotdebの5.6になっていたので、mysql-*-5.5を削除しようとすると5.6が推薦されてインストールされた。apt-get upgrade mysql-client mysql-serverで良かったのかもしれない。

sudo apt-get remove mysql-client-5.5 mysql-server-5.5
...
The following packages will be REMOVED:
  mysql-client-5.5 mysql-server-5.5
The following NEW packages will be installed:
  mysql-client-5.6 mysql-server-5.6
The following packages will be upgraded:
  mysql-client mysql-server
2 upgraded, 2 newly installed, 2 to remove and 0 not upgraded.

次にgemのmysql2パッケージをビルドしなおすためにパッケージを入れなおした。

$ rm -rf vendor/bundle
$ bundle install --path=vendor/bundle
...
Installing mysql2 (0.3.15) 

ちなみに今さくらのVPSの石狩リージョンの方に移行しようとしていてそちらはChef-Soloでセットアップしてみると綺麗に5.6になっていたのでやはりmysql-client mysql-serverをアップグレードすればよかったのかもしれない。

mysql.rb
# default[:mysql][:packages] = %w(mysql-client mysql-server mysql-common mytop libmysqlclient-dev)
node[:mysql][:packages].each do |pkg|
  package pkg do
    action :install
  end
end
$ sudo dpkg -l | grep mysql
ii  libdbd-mysql-perl                  4.021-1+b1                    amd64        Perl5 database interface to the MySQL database
ii  libmysqlclient-dev                 5.6.17-1~dotdeb.1             amd64        MySQL database development files
ii  libmysqlclient18:amd64             5.6.17-1~dotdeb.1             amd64        MySQL database client library
ii  mysql-client                       5.6.17-1~dotdeb.1             all          MySQL database client (metapackage depending on the latest version)
ii  mysql-client-5.6                   5.6.17-1~dotdeb.1             amd64        MySQL database client binaries
ii  mysql-client-core-5.6              5.6.17-1~dotdeb.1             amd64        MySQL database core client binaries
ii  mysql-common                       5.6.17-1~dotdeb.1             all          MySQL database common files, e.g. /etc/mysql/my.cnf
ii  mysql-server                       5.6.17-1~dotdeb.1             all          MySQL database server (metapackage depending on the latest version)
ii  mysql-server-5.6                   5.6.17-1~dotdeb.1             amd64        MySQL database server binaries and system database setup
ii  mysql-server-core-5.6              5.6.17-1~dotdeb.1             amd64        MySQL database server binaries
ii  php5-mysql                         5.5.11-1~dotdeb.1             amd64        MySQL module for php5

Redmineは無事動いた。

GitHubっぽいRedmineテーマ少し更新

担当者や報告者がログインユーザのときにboldにするpullリクエストを頂いたので、そしてGitHubのデザインが変わったのに追従しようと思ってcssをsassに変更したところで作業を放置していたことを思い出したのでほんの少しだけGitHubに近づける努力だけして リビジョン4 として公開しました。

日本語フォントを指定してたら海外の人からフォントがおかしいとか言われてしまったので日本語版を別にリリースするという面倒なことになっています。

Gitでmeriyoフォントを指定したものを使うには以下になります。meiryoイラネという人はmasterブランチのままで良いです。

cd redmine/public/theme
git clone git://github.com/makotokw/redmine-theme-gitmike.git gitmike
git checkout -b ja r4_japanese_font

gitmike screenshot

rbenvとunicornでRedmineのRuby環境を分けて動かす

超絶シンプルなブログを作ろうとして逆算していくとRedmineが障壁になったのでRedmineを単独で動かすことにしました。

今までRedmineはPassengerを使ってApacheやNginxで動かして来ましたが、今回はunicornで動かすことにしました。unicornで動かすと言ってもポート80はウェブサーバで使うのでリバースプロキシで接続することになります。多くの場合Redmineはチーム内であったりして使う人が限られていると思うのでそれで多少パフォーマンスが落ちても問題ないと思っています。それよりも環境を独立して動かすことを優先するという形です。

  • rbenvでrubyは入れる
  • nginxからproxyでunicornに接続する
  • Redmineはgitでいれる
  • Redmineに必要なgemはvendor/bundleに入れる
  • Redmineのデータベースはmysqlを使う
  • RedmineはSubURI/redmineで公開する

これによりRedmine(Railsアプリ)の実行環境を完全に独立できます。OSに依存する部分は少ないですがDebian/Ubuntu向けの内容になります。基本的に最後の仕上げらへんのsudoコマンドを使っている部分を除いて一般ユーザでセットアップします。

rbenvをセットアップ

OS XならHomebrewでbrew install rbenvで入れると楽です。aptはパッケージが古かったので直接入れることにします。

git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.profile
echo 'eval "$(rbenv init -)"' >> ~/.profile

Debian/Ubuntuなので.profileに書いています。rbenvのセットアップ詳細はrbenvを参照。

Redmineのruby環境をセットアップ

Redmineで使うrubyをインストールします。とりあえず1.9.xのこの時点の最新を使いました。

rbenv install 1.9.3-p392
...

Bundlerのインストール

rbenv shell 1.9.3-p392
gem install bundler
rbenv rehash

Redmineのインストール

どこにインストールしても問題ないです。~/redmineでも可。この時点の最新2.3を使いました。

git clone https://github.com/redmine/redmine redmine
cd redmine
git checkout -b release/2.3.0 2.3.0

Redmineの依存解決

データベースはmysqlを使うのでsqlite, postgresqlを除外します。--path vendoer/bundleを設定しているのでRedmineで使うgemはそこにインストールされ他のRubyアプリケーションに影響させないようにします。

rbenv local 1.9.3-p392
bundle install --without development test rmagick sqlite postgresql --path vendor/bundle

データベースのセットアップ

例です。データベースユーザやパスワードはちゃんとしたものを使ってください。

mysql -u root -p
create database redmine character set utf8;
create user 'redmine'@'localhost' identified by 'redmine';
grant all privileges on redmine.* to 'redmine'@'localhost';
exit;
cp -p config/database.yml.example config/database.yml

config/database.ymlを編集します。

# mysql
production:
  adapter: mysql2
  database: redmine
  host: localhost
  username: redmine
  password: redmine
  encoding: utf8

Redmineのセットアップ

cd /path/to/redmine
bundle exec rake generate_secret_token
RAILS_ENV=production bundle exec rake db:migrate
RAILS_ENV=production bundle exec rake redmine:load_default_data
mkdir tmp tmp/pdf public/plugin_assets

Sub URIで動作させるためにconfig.ruを修正します。Root(/)で動かすならこの作業は不要です。

# This file is used by Rack-based servers to start the application.

require ::File.expand_path('../config/environment',  __FILE__)
#run RedmineApp::Application
if ENV['RAILS_RELATIVE_URL_ROOT']
  map ENV['RAILS_RELATIVE_URL_ROOT'] do
    run RedmineApp::Application
  end
else
  run RedmineApp::Application
end

unicorn追加でインストール

cd /path/to/redmine
echo 'gem "unicorn"' >> Gemfile.local
bundle

unicorn設定ファイル

cd /path/to/redmine
curl -o config/unicorn.rb https://raw.github.com/defunkt/unicorn/master/examples/unicorn.conf.rb

パスのみ変更してあとはデフォルトのままです。必要に応じて調整してください。

# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.

APP_PATH = File.expand_path('../../', __FILE__)

worker_processes 4

working_directory APP_PATH # available in 0.94.0+

listen "#{APP_PATH}/tmp/unicorn.sock", :backlog => 64

timeout 30

pid "#{APP_PATH}/tmp/unicorn.pid"

stderr_path "#{APP_PATH}/log/unicorn.stderr.log"
stdout_path "#{APP_PATH}/log/unicorn.stderr.log"

preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
  GC.copy_on_write_friendly = true

check_client_connection false

before_fork do |server, worker|
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end

unicorn実行

テスト実行。Root(/)で動かすなら--path /redmineは不要です。

cd /path/to/redmine
bundle exec unicorn_rails -c config/unicorn.rb -E production --path /redmine

nginx設定

config/unicorn.rbでリスニングしているunix socketに接続させます。

upstream redmine {
    server unix:/path/to/redmine/tmp/unicorn.sock;
}
server {
...
    location /redmine {
        root /path/to/redmine/public;
        if (-f $request_filename) { break; }
        proxy_set_header    X-Real-IP           $remote_addr;
        proxy_set_header    X-Forwarded-Host    $host;
        proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_pass http://redmine;
    }
...
}

仕上げ

問題なければ起動スクリプトを/etc/init.d/redmineに置いて実行。USER, APPPATH, URIPATHあたりを修正してください。

#! /bin/sh

### BEGIN INIT INFO
# Provides:          redmine
# Required-Start:    $all
# Required-Stop:     $network $local_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the redmine web server
# Description:       starts redmine
### END INIT INFO

USER=username
APP_PATH=/path/to/redmine
RAILS_ENV=production
URI_PATH=/redmine

SET_PATH="cd $APP_PATH"
DAEMON="bundle exec unicorn_rails"
DAEMON_OPTS="-c $APP_PATH/config/unicorn.rb -E $RAILS_ENV -D --path $URI_PATH"
CMD="$SET_PATH; $DAEMON $DAEMON_OPTS"
NAME=redmine
DESC="Unicorn app for redmine"
PID="$APP_PATH/tmp/unicorn.pid"
OLD_PID="$PID.oldbin"

cd $APP_PATH || exit 1

sig () {
        test -s "$PID" && kill -$1 `cat $PID`
}

oldsig () {
        test -s $OLD_PID && kill -$1 `cat $OLD_PID`
}

case ${1-help} in
start)
        sig 0 && echo >&2 "Already running" && exit 0
        su - $USER -c "$CMD"
        ;;
stop)
        sig QUIT && exit 0
        echo >&2 "Not running"
        ;;
force-stop)
        sig TERM && exit 0
        echo >&2 "Not running"
        ;;
restart|reload)
        sig HUP && echo reloaded OK && exit 0
        echo >&2 "Couldn't reload, starting '$CMD' instead"
        su - $USER -c "$CMD"
        ;;
upgrade)
        sig USR2 && exit 0
        echo >&2 "Couldn't upgrade, starting '$CMD' instead"
        su - $USER -c "$CMD"
        ;;
rotate)
        sig USR1 && echo rotated logs OK && exit 0
        echo >&2 "Couldn't rotate logs" && exit 1
        ;;
*)
        echo >&2 "Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>"
        exit 1
        ;;
esac

exit 0
sudo service redmine start
sudo update-rc.d redmine defaults

起動時に動かすようにもしておきます。

その他

Redmineを初期セットアップ風に書いているけど実際は2.2->2.3のアップグレード。

Ruby 1.9にあげたらgem install activerecord-mysql-adapterというエラーになった。bundlerで依存関係解決しているのに・・・調べたらconfig/database.ymlのadapter: mysqlをadapter: mysql2にすると直った。

実は最初はpassenger-standaloneで進めていたがSubURIで動かせないという問題に遭遇した。proxy redirectで無理やり変換できそうだが面倒なのとunicornつかってみたかったので諦めた。ルートディレクトリで公開できるなら行けた。

参考


This markdown is rendered by wp-gfm

GithubっぽいRedmineのテーマ少し更新してみた

GitmikeというGithubっぽいRedmineのテーマ少し更新してみた。

変更点は2つ。チケットをグループ化(例えばバージョンとかで)して表示しているときにグループごとの総数のカウントが表示されていた。Redmine 2.2を使っているけどいつから表示されたのかるかは不明。日本語フォントを使っていると字の大きさが合っていないようで気になったので修正した。

もう一つはチケットの優先度で高いものは赤、低いものは青背景で表示していたんだけど、これがpriority-5とかpriority-1とかのclassでスタイルを適応させていた。この数字は優先度の順位のように見えて実は列挙型の値を管理するテーブルのIDが使われているので優先度など列挙値を新しく定義したりすると当然IDが変わってしまい意図したスタイルが適応されないという問題があった。でもデータベーステーブルを見ているとhighestとかposition nameなるカラムの値があってよく見るとpriority-5 priority-highestというようなclassが設定されていたのでposition nameを使うように修正した。

https://github.com/makotokw/redmine-theme-gitmike/tagsからダウンロードできます。海外の人から日本語フォント使っているせいで文字がどうこうという指摘を受けたので日本語フォントを指定したバージョンは_jaというsuffixをつけた方に入っています。gitでセットアップするならこんな感じ。

cd redmine/public/theme
git clone git://github.com/makotokw/redmine-theme-gitmike.git gitmike
cd gitmike
git checkout -b redmine/r3_ja r3_ja

ついでにテーマのテストをするRedmineの開発環境をつくってみたのでQiitaに環境構築メモをアップしました。

Redmineで新規チケット作成時にデフォルトの担当者を設定する方法

Redmineで新規のチケットを作成するときに担当者(アサイン)のデフォルトが空欄で一人で使っているサーバだったりするといちいち自分に設定するのが面倒なので初期値を設定する方法を調べた。

Redmine.JPに新規チケット作成時、デフォルトの担当者をチケット作成者にするがあった。ただこの方法はredmine本体を変更しているのでバージョンアップの度に変更が必要になってしまう。gitでpatchでも作っておけばいいかと思ったがすでにあるんじゃないかとさらに英語圏でも検索していくと redmine.orgのFeature #482 default assignment setting にたどり着く。そしてコメントにこのリクエストに対応したプラグインを発見。

いろいろforkされているけど今のところのメインはPaulさんっぽい https://github.com/giddie/redmine_default_assign redmine_default_assignはプロジェクトごとにデフォルトの担当者を設定できるようになっている。

これで動くのを確認して、日本語翻訳をいれたものを作ってみた。

redmine_default_assignプラグイン v0.2 + ja 導入手順

Redmine 2.x系が必要です。

1. https://github.com/makotokw/redmine_default_assign/tags からダウンロードする
(pull request日本語訳を取り込んでもらったのでgitが使えて最新版を使いたい人はhttps://github.com/giddie/redmine_default_assignからcloneすると良いです)
2. redmine/plugins/redmine_default_assign に配置する
3. rake redmine:plugins:migrate RAILS_ENV=production を唱える
4. 必要に応じてウェブサーバを再起動
5. Redmineを開いてプロジェクトごとに設定でデフォルトの担当者を設定する

これでひとつ面倒な作業が減りました。

DebianでRedmine 1.3.2から2.0に更新する

さくらのVPS 512からさくらのVPS 2Gに移行していろいろ作業している間に Redmineは1.4.xがリリースされ、さらに Rails3向けのRedmine 2.0がリリースされた。

取り残されないうちにRedmine 2.0に更新する。Nginx+Passengerで動かしているがほとんどの作業はコマンドラインからでウェブサーバの違いが手順に影響することはあまりない。

本家サイトの手順にそっていく
http://www.redmine.org/projects/redmine/wiki/RedmineUpgrade

なおCentOS版の更新手順はredmine.jpで公開されている
http://blog.redmine.jp/articles/redmine-2_0-installation_centos/

Step 1 – Check requirements

Redmine 1.3.2の環境でRubyは1.8.7のみ、Railsは 2.3.14、gemは古いという状態。

一方、Redmine 2.0はRubyは1.8.7, 1.9.2, 1.9.3, jruby-1.6.7、Railsは3.2.3が必要。他のパッケージが記載されていないのでよく読んでみると、Redmine 1.4からBundlerに対応し、依存パッケージbundle installでセットアップできるようになったようだ。

さて今回はいろいろあって(後述)、Ruby 1.8.7を継続して使うことにした。Redmineの依存パッケージをインストールしていく。

su
PATH="$PATH:/var/lib/gems/1.8/bin"
gem install bundler
cd /path/to/redmine
bundle install --without development test

gemのバイナリのパスが通してないので面倒なことをしている。

RMagickの依存ライブラリのインストール

RMagickのインストールに失敗したので補足しておく。いままでRMagickはオプションだったし、別に要らないと思ってインストールしていなかった。しかし、bundle installの途中で失敗してストップしてしまい、withoutするのも癪なのでRMagickをインストールしてみる。

apt-cache search magick でそれらしいパッケージを検索し、以下のコマンドを実行。

apt-get install imagemagick
apt-get install libmagickcore-dev
apt-get install libmagickwand-dev

正直なところ3回実行した。最初にCan't install RMagick 2.13.1. Can't find Magick-configというエラーだったので薄々開発モジュールが要りそうだと思っていてimagemagickをインストールしてもMagick-configは入らなかったので続けてlibmagickcore-devをインストール。しかしそれでも Can't install RMagick 2.13.1. Can't find MagickWand.h. というエラーがでたので libmagickwand-dev をインストール。これでRMagickはインストールできた。

Step 2 – Backup

MySQLデータベースだけ。ここからはrootではなく通常ユーザで実行。

mysqldump -u redmine -p redmine > ~/redmine.dump.sql

Step 3 – Perform the upgrade

gitで管理しているので2.0のローカルブランチを作成する。

cd /path/to/redmine
git status
git checkout master
git pull
git pull --tags
git checkout -b redmine/2.0.0 2.0.0

Step 4 – Update the database

mv vendor/plugins/* plugins/ 
rm  config/initializers/session_store.rb
rake generate_secret_token
rake db:migrate RAILS_ENV="production"
rake redmine:plugins:migrate RAILS_ENV=production

1行目について
プラグインのディレクトリが変更されたらしい。(プラグインを使っていなかったので未検証)

2,3行目について
Redmine 1.4からsessionまわりが変わったらしいのだが

rake db:migrate RAILS_ENV=”production”
Please remove config/initializers/session_store.rb and run rake generate_secret_token.

と怒られたので従う。

5行目について

rake db:migrate_plugins RAILS_ENV=production
Note: The rake task db:migrate_plugins has been deprecated, please use the replacement version redmine:plugins:migrate

ということでdb:migrate_pluginsはredmine:plugins:migrateに置き換わった。

プラグインを入れてなかったのでRedmine 2.0とプラグインの互換性についてはなんとも言えない。自作テーマはRedmine 2.0でも問題なさそうだ。

undefined method `log_path’

データベースのマイグレーションを実行しようとすると以下のようなエラーが表示された。

rake db:migrate RAILS_ENV="production"
rake aborted!
undefined method `log_path' for #<Rails::Application::Configuration:0x7f0a75721448>

Configクラスにlog_pathがないので怒られている模様。config/additional_environment.rbに記載していたログのカスタマイズのコードが該当していた。ドキュメントのまま記述していいたのだけど・・・とりあえずコメントアウト。

config/additional_environment.rb
#config.logger = Logger.new(config.log_path)
#config.logger.level = Logger::WARN

本家サイトでも報告されているのでそのうち修正されるか、回避策が提示されるだろう。それまではデフォルトの設定でいく。
undefined method ‘log_path’
install redmine 2.0, when rake generate_secret_token, an error appear..

Step 5 – Clean up

rake tmp:cache:clear
rake tmp:sessions:clear
sudo service nginx restart

Redmineが無事表示できたら、ログインして管理 > 情報からバージョンを確認しておく。
次に 管理 > ルールと権限から新しい権限のチェック。

管理者にて
「チケットをプライベートに設定」
「自分のチケットをプライベートに設定」
「関連するチケットの管理」
チェックが入っていなかった。いつから増えたのかは不明。

Ruby 1.9系のインストール

移行を諦めたRuby 1.9の話。

Debianは1.8系がruby1.8、1.9系がruby1.9.1をそれぞれapt-get installでインストールできる。もともとruby1.9だったのだが問題があってパッケージ名がruby1.9.1になったようで混乱する。apt-cache show ruby1.9.1で以下のように表示される。

Package: ruby1.9.1
Version: 1.9.3.0-2.1

しかし実際いれてみて ruby1.9.1 -vとすると ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux] で1.9.3にならなかった。。

sudo apt-get install ruby1.9.1 ruby1.9.1-dev
# /usr/bin/gem is already managed by gem
# gemは別にmasterで管理されてるよと怒られたので削除
sudo update-alternatives --remove-all gem
sudo update-alternatives --install /usr/bin/ruby ruby /usr/bin/ruby1.8 120\
  --slave /usr/bin/irb ruby-irb /usr/bin/irb1.8\
  --slave /usr/bin/gem ruby-gems /usr/bin/gem1.8 
sudo update-alternatives --install /usr/bin/ruby ruby /usr/bin/ruby1.9.1 150\
  --slave /usr/bin/irb ruby-irb /usr/bin/irb1.9.1\
  --slave /usr/bin/gem ruby-gems /usr/bin/gem1.9.1\
  --slave /usr/bin/rake ruby-rake /usr/bin/rake1.9.1
sudo update-alternatives --config ruby

一応ruby1.9.1には切り替えられるようにはしたが、最新版を使うならRVMから入れた方が良いような気もしている。いずれにせよRedmine以外Rubyアプリケーションは動かしていないので一旦保留にした。

GitHubテイストなRedmineのテーマを自作してみた

VMware ImageでGitLabを試してみたが現状の要求ではRedmineの方が向いていることがわかった。単に今風のデザインのものが使いたいという邪な気持ちがあったのでRedmineのテーマをGitHubっぽくしてみるということをやってみた。

反響があったのでGitHubより公開しました。
https://github.com/makotokw/redmine-theme-gitmike/tags

Redmineのテーマはスタイルシートを以下の階層につくって設定から変更することで適応できた。

public/themes/{themename}/stylesheets/application.css

参考: http://www.redmine.org/projects/redmine/wiki/Themes

スタイルシートなので他のテーマを参考にしながら作成することができる。
http://www.redmine.org/projects/redmine/wiki/Theme_List

今回は A1 theme をベースにGitHubのカラーなどを適応してみた。人様のテーマを変更している都合で今のところテーマは公開しておらず。 A1 theme 作者様に再頒布の許可をいただきました。(GPL3で公開しているとのこと) GPLなので本テーマもGPL3で公開しました。

タグからダウンロードできます。
makotokw/redmine-theme-gitmike

さくらのVPSでRedmineとかTracをApacheからNginxに切り替える

「さくらのVPS」でっていうのがいいタイトルなのかどうかわからないけど、実際のところはDebina 6で構築する話。ApacheをWebサーバとして公開していたRedmine/Trac/Subversionをある機会でNginxに切り変えることにした。

この記事の段階ではDebian 6+Nginx 1.0.14の内容となっています。(1.2.0からはパッケージが変わっているようです)

Nginxにする動機

正直なところ、個人利用のRedmineやTracでパフォーマンスを気にする必要もあまりなく、これ単独でNginxにする動機はない。背景にはレンタルサーバで公開しているWordPressのblogをNginx+php-fpmを利用する形でさくらのVPS 2Gに移行しようと思っていたことがある。するとPort 80をNginxに明け渡さないといけなくなるため他のサービスも対応が必要になる。

方針

今回は以下の方針でいくことにする

  • RedmineはNginx+passengerで公開
  • Trac/SubversionはApacheをバックエンドにしてNginxをリバースプロキシとして公開

Trac/Subversionはもうreadonlyでほとんど使っていないので本来はRedmine/Gitに移行したいところなのである。必要なものは移行したが開発を辞めてしまったYahoo! WidetやMovableTypeプラグインなどは移行コストと構築コストを考えたときに後者を取ってしまっているのが現状である。今回もさくらのVPS 2Gに構築したときも悩んだがやはり面倒になったのでそのままTrac/Subversionを構築してしまった。パフォーマンスを気にする必要もなく、メンテナンスコストを掛けたくないので別にApacheのままでいいという判断である。

対してRedmineについては現在も利用しているし、Railsはそれほど設定に悩まなそうなので(これは甘い見通しだったが)Nginxに移行してみようと考えた。

Nginxのインストール

なお、ここからの手順はすべてrootで実行している。

Debian squeezeからインストールしたら、Nginx 0.7だった。ちょっと古いと思いunstableから入れようかと思ったがdotdebという便利なリポジトリがあるようなのでこれを使ってみることに。

dotdebリポジトリを追加

/etc/apt/sources.listに以下を追加。

# dotdeb.org
deb http://packages.dotdeb.org stable all
deb-src http://packages.dotdeb.org stable all

GnuPG キーの追加のため以下を実行する。

cd /tmp
wget http://www.dotdeb.org/dotdeb.gpg
cat dotdeb.gpg | apt-key add -

とりあえず更新
aptitude update

nginx-extrasのインストール

dotdebのnginx 1.2.0からpassengerモジュールはnginx-extrasから取り除かれ、代わりにnginx-passerngerというパッケージが公開されています。従って1.2以降でpassengerを使う場合に実行するコマンドは aptitude install nginx-passerngerが正解です。各パッケージごとのモジュール一覧は以下のリンクを参照ください。
https://docs.google.com/a/moolfreet.com/spreadsheet/ccc?key=0AjuNPnOoex7SdG5fUkhfc3BCSjJQbVVrQTg4UGU2YVE#gid=0

nginx-extrasではPassengerに対応してくれている。サイコー。
http://www.dotdeb.org/2011/05/07/rails-user-dotdeb-now-supports-passenger/

というわけでインストールする。

aptitude install nginx-extras

デフォルトだとport 80を使うようになっているのでApacheを動かしているとNginxは開始できないと思われる。

Nginxの設定

細かい調整は今後必要になってくる、とりあえずサーバのバージョン情報を返すのを無効にしておく。

server_tokens off;

Passenger(Ruby On Rails)のために以下のコメントを外しておく。

        ##
        # nginx-passenger config
        ##
        # Uncomment it if you installed nginx-passenger
        ##

        passenger_root /usr;
        passenger_ruby /usr/bin/ruby;

Virtual Hostの設定

Debian/UbuntuでApacheとおなじみの管理方式になっている。nginx.confよりsites-enabled/*がIncludeされており、sites-availableにサイトごとの設定を書いて、sites-enabeldにシンボリックリンクを張る方式である。

a2ensite/a2dissiteと同様のコマンドngxensite/ngxdissiteがインストールされていた。これを使うとsites-availableにファイルを置いておけば有効・無効(シンボリックリンクの生成・削除)は以下のように行える。

# 有効にする
ngxensite (ファイル名)
# 無効にする
ngxdissite (ファイル名)

a2ensiteでは複数のファイルを指定できたが、ngxensiteで複数指定しても最初のファイルしか有効にならなかった。

Apacheの設定変更

Apacheはバックエンドとして動かすことになるのでいくつかの設定変更が必要になってくる。

Portの変更

VirutalHostで公開しているのでそれぞれのPortを変更する。まずListeningのPort変更。

NameVirtualHost *:8081
Listen 8081

mod_rpafのインストール

NginxをリバースプロキシとしてApacheをバックエンドで動作させる場合、Apacheから見て接続してくるクライアントはNginxである。同じサーバで動かすので同じホストからアクセスされることになる。この場合、ログのリモートホストが127.0.0.1で出力されたり、グローバルIPで接続を制限していても127.0.0.1からのアクセスなので素通りになったりして面倒なことになる。

これらを解決するのがmod_rpafである。mod_rpafはリバースプロキシが送ってくるX-Forwarded-Forなどのヘッダを見てリバースプロキシのリクエスト元をリモートホストとして処理してくれる。

mod-rpafもaptでインストールできた。

aptitude install libapache2-mod-rpaf
a2enmod rpaf

デフォルトの設定は以下のようになっていたのでApacheとNginxを同一サーバで動かすならこのままでいい。

<IfModule mod_rpaf.c>
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1
</IfModule>

X-Forwarded-Forのヘッダの設定などはNginx側で行う必要があるがそれはこのあとに記載する。

サイトの設定

さて、いよいよここからApacheからNginxへの移行のためのサイト設定になる。
まずApacheのVirutalHostのポートを以下のようにして変更しておく。

<VirtualHost *:8081>

次にNginxのサイト設定を行う。説明の都合で一つにまとめると以下のような感じになる。

server {
    root /usr/share/nginx/www;
    index index.html
    server_name example.com;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /redmine {
        passenger_enabled on;
        passenger_base_uri /redmine;
    }

    location /trac {
        proxy_set_header    X-Forwarded-Host    $host;
        proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_pass          http://127.0.0.1:8081;
    }

    location /svn {
        proxy_set_header    X-Forwarded-Host    $host;
        proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_pass          http://127.0.0.1:8081;
    }
    location ~ /\.ht {
       deny all;
    }
}

Trac/Subversionはそれぞれサブディレクトリで公開していたので、それぞれのlocationでproxy_passtとして同じサーバでポート8081で動いているApacheを指定し、X-Forwarded-Forの設定を行なっている。

ドキュメントルートがデフォルト(/usr/share/nginx/www)のままだが実際にはApacheの際のドキュメントルートと同じものを設定している。そのためApacheの.htで始まるファイルを返してしまわないようにアクセスを拒否する設定をいれている。

Redmineもサブディレクトリで公開している。nginx.confでpassenger_rootとpassenger_rubyの設定は有効にしたのでここでは、passenger_enabled、passenger_base_uriの設定を追加している。ちなみにRailsアプリをサブディレクトリで公開するための設定はPassengerのサイトに書いてあった。他にもいろいろな情報があって参考になる。
http://www.modrails.com/documentation/Users%20guide%20Nginx.html#deploying_rails_to_sub_uri

Nginxのログローテーション

Apacheにはrotatelogsという専用モジュールへログファイルをpipeして日付をファイル名につけてローテーションできたがNginxではそのような機能はなく、logrotateを使うのが基本のようである。デフォルトでは以下のようなファイルがインストールされていた。

/var/log/nginx/*.log {
        daily
        missingok
        rotate 52
        compress
        delaycompress
        notifempty
        create 0640 www-data adm
        sharedscripts
        prerotate
                if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
                        run-parts /etc/logrotate.d/httpd-prerotate; \
                fi; \
        endscript
        postrotate
                [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`
        endscript
}

logrotateを調べたところdateextというオプションがあるのでdailyと併用すれば日付の名前をつけてローテーションできるようだ。確かlogrotateにはログを恒久的に残すという仕様はなかったと思うので、rotateの設定で世代を沢山残すようにするか自分でファイルをコピーするかしないといけない。

置き換え

ひと通り設定が終わったので、Apache/Nginxを再起動する。Nginxのデフォルトサイトは無効にしておく。ブラウザでアクセスできれば成功となる。

ngxdissite default
ngxensite example
/etc/init.d/apache restart
/etc/init.d/nginx restart

参考になったもの

このエントリを書いている時点で日本語の本はこれしかないと思われる。最初の情報としてはかなり訳にたつ。

Nginxの設定に書けるDirective一覧。新しいサービスはドラスティックに変わっていくのでまずはオフィシャルな情報をチェックするに限る。
Nginx – Directive Index

RedmineのようなRuby On RailsをApache/Nginxで実行させるPassengerのNginx向けのドキュメント、各種設定について参考になる。
Phusion Passenger users guide, Nginx version

まとめ

細かい設定などまだまだ勉強することは多いが、設定の書き方など結構フレキシブルな感じがある。例えばaccess_logがlocationディレクティブでも書けるので今回のようにサービスごとにサブディレクトリに分けている場合はサービスごとにログファイルを運用することも可能である。(Aapcheでも同様のことはできるがちょっと面倒というか設定に可読性があまりないと思う)

まだまだ何をするにせよApacheからNginxへの翻訳が必要な状況だが使っていくうちに覚えるであろうと信じたい。今回はあくまでWordpressを持ってくるための事前準備なので、次はWordpressの移行に取り組みたい。

試行錯誤集

うまくいった手順だけを書くと簡単に見えてしまうが、ここにたどり着くまでいろいろあった。同じことにハマった人のために紹介しておく。

X-Forwarded-Forの設定は明示的に必要

Apacheにmod_rpafを入れたらそれでokと思っていたがApacheのログが127.0.0.1になる。Nginxはproxy_passを設定してもX-Forwarded-Forの設定は自前でする必要があるようだ。しばらくApache側の設定反映を疑ったため時間を浪費した。

gem passengerは使わなくていい

Passengerのインストール方法をみるとNginxへのインストールには、

gem install passenger
passenger-install-nginx-module

を実行すればよくて、最初はこれに従ってみたところ以下のような質問が表示された。

Automatically download and install Nginx?

Nginx doesn't support loadable modules such as some other web servers do,
so in order to install Nginx with Passenger support, it must be recompiled.

Do you want this installer to download, compile and install Nginx for you?

 1. Yes: download, compile and install Nginx for me. (recommended)
    The easiest way to get started. A stock Nginx 1.0.10 with Passenger
    support, but with no other additional third party modules, will be
    installed for you to a directory of your choice.

 2. No: I want to customize my Nginx installation. (for advanced users)
    Choose this if you want to compile Nginx with more third party modules
    besides Passenger, or if you need to pass additional options to Nginx's
    'configure' script. This installer will  1) ask you for the location of
    the Nginx source code,  2) run the 'configure' script according to your
    instructions, and  3) run 'make install'.

Whichever you choose, if you already have an existing Nginx configuration file,
then it will be preserved.

え、せっかくaptでnginx入れたのに何いってんの?ちょっと待ってちょっと待ってちょっと待って。でキャンセルした。そう、この方法でインストールする場合、Passenger機能の付いたnginxをビルドして新規にインストールすることになる。でもやっぱり管理上、aptで運用したい。

libapache2-mod-passengerがあるんだからnginxのパッケージもあるんじゃないのとapt-cache search passengerで検索してnginx-extrasが見つかったのでgem uninstall passengerで消えてもらった。

passenger-install-nginx-moduleを実行するためにいろんなパッケージを入れたのはここだけの秘密。

nginx-fullはnginx-extrasの上位版ではない

dotdebからnginxをインストールするとnginx-fullがインストールされる。さらにnginx-extrasをインストールしようとするとnginx-fullと衝突したので、nginx-fullはnginx-extrasを包括しているんだろうと勝手に勘違いしてしまった。そのためpassengerの設定をしようとすると「 unknown directive “passenger_root” 」とか言われて怒られる。

nginx-fullとnginx-extrasのパッケージの情報を表示してみたところ以下のようにモジュールが異なっていた。

(nginx-full)
Standard HTTP Modules:
   Core, Access, Auth Basic, Auto Index, Browser, Charset, Empty GIF, FastCGI,
   Geo, Gzip, Headers, Index, Limit Requests, Limit Zone, Log, Map, Memcached,
   Proxy, Referer, Rewrite, SCGI, Split Clients, SSI, Upstream, User ID, UWSGI
 Optional HTTP Modules:
   Addition, Debug, GeoIP, Gzip Precompression, HTTP Sub, Image Filter, IPv6,
   RealIP, Secure link, Stub Status, SSL, WebDAV, XSLT
 Other Modules:
   File AIO
 Mail Modules:
   Mail Core, IMAP, POP3, SMTP, SSL
 Third Party Modules:
   Auth PAM, Cache purge, Echo, Syslog, Upstream Fair Queue
 (nginx-extras)
Standard HTTP Modules:
   Core, Access, Auth Basic, Auto Index, Browser, Charset, Empty GIF, FastCGI,
   Geo, Gzip, Headers, Index, Limit Requests, Limit Zone, Log, Map, Memcached,
   Proxy, Referer, Rewrite, SCGI, Split Clients, SSI, Upstream, User ID, UWSGI
 Optional HTTP Modules:
   Addition, Debug, WebDAV, Flash Streaming Video, GeoIP, Gzip Precompression,
   HTTP Sub, Image Filter, MP4, RealIP, Stub Status, SSL, XSLT, IPv6, Embedded
   Perl, Secure Link, Random Index
 Mail Modules:
   Mail Core, POP3, IMAP, SMTP, SSL
 Third Party Modules:
   Echo, Embedded Lua, http push, Nginx Development Kit, Upload module,
   Upload Progress, HttpHeadersMore, Upstream Fair Queue, Chunkin, Auth PAM
 Modules added by Dotdeb:
   File AIO, Syslog, Cache purge, Passenger

というわけで nginx-extras > nginx-full である。nginx-fullを削除して、nginx-extrasを入れなおすはめになった。