Docker コンテナで Redmine 4.0 へのアップグレード作業まとめ

この記事は、sameersbn/redmine コンテナを用いた Redmine 4.0.x へのバージョンアップにおける知見をメモするものです。GOALは Redmine 3.4.7 から Redmine 4.0.x (sameersbn/redmine:4.0.3-1) へのアップグレード完了です(結果的には、できたけど保留、となりました)。

Redmine は利用プロジェクト・人によりプラグイン構成等全く異なるため、これそのままが役に立つものでないと思いますが、類似ケースでの問題点の解決などアップグレードの一助になればと思うところです。

Redmineコンテナ

sameersbn/redmine は、Redmineサービスを提供するDockerイメージで、(おそらく)Officialレポジトリに次いで使われている定番イメージです。

https://github.com/sameersbn/docker-redmine

RepositoryDownloadsStars
https://hub.docker.com/_/redmine10M+728
https://hub.docker.com/r/bitnami/redmine500K+38
https://hub.docker.com/r/sameersbn/redmine10M+301

(2019/04/21現在)

何が便利かといえば、Available Configuration Parameters にある通り多様なパラメタによる細かい機能設定で、大部分のニーズを満たせるのではないでしょうか。指定パスにプラグインを配置してコンテナを起動するだけで Migration を自動でやってくれる等、おかげで面倒くさいセットアップのかなりの部分を省略してくれます。

redmine 4.0 魅力機能

さて、Redmine 4.0 になぜするのか?というところですが、このあたりの記事で惹かれるかどうか。個人的にはガントチャートの改善や、## 記号によるチケットタイトルの自動展開なんかが気になります。

Pluginの対応状況チェック

[注] git pull して更新があったものを “更新あった” と記載しているため、“Redmine 4.0.x 対応があった” の意味ではない。少々強引だが更新があれば Redmine 4.X 対応しているだろうの期待のもと、Try&Errorで進めるスタンスのため。

更新あった

  • redmine_default_custom_query
  • redmine_issue_templates
  • redmine_issues_summary_graph
  • redmine_pivot_table
  • redmine_wiki_extensions
  • view_customize
  • redmine_work_time

更新なかった

更新がないものは、Redmine 4.x で使えない可能性が高いことを意味します。

$ clipboard_image_paste ❯❯❯ git pull
Already up to date.

clipboard_image_paste はめちゃ便利なので使い続けたい。お気に入りです。

$ redmine-slack ❯❯❯ git pull
Already up to date.

たぶん今なら redmine_messenger plugin を使ったほうがいい。commit log にも redmine 4.x 対応の記載あり。

https://github.com/AlphaNodes/redmine_messenger/commit/1d7e53fd9cb0f58ce0904f50093253c2a646d4fb

$ redmine_github_hook ❯❯❯ git pull
Already up to date.
$ redmine_issue_completion ❯❯❯ git pull
Already up to date.
$ redmine_tweaks ❯❯❯ git pull
Already up to date.

ほかは、今となってはあまり必要ないかな。

git管理していないもの

  • easy_gantt : 結果消すこととする(詳細後述)
  • redmine_agile : 結果消すこととする(詳細後述)

作業

順番注意。Redmine 3.x のままやることがあるのにプラグインだけ先行してアップデートしてしまうと、動かなくなるので注意(Redmine 4.x対応しているものは、4.x以上の縛りを設定しているものも多い)

作業1. Pluginアンインストール

現在利用中のプラグインをアンインストールする方法として、参考にいくつか記載します。

redmine_agile plugin

パット見面白いのだがFree版だと「かんばん風の見た目も楽しめる」程度のもので、実用的かというとちょっと厳しいかなという印象。例えば、Agileタブを開いた時に表示したい状態をカスタムフィルタで保存することができないので、毎回選び直さなければならない点(パラメタを含むURLでがんばって運用できなくもないが)。

Webサービス(Redmine)コンテナを通常起動したあとに docker exec -it コンテナ名 bash して以下のコマンドを実行。

entrypoint.sh app:rake redmine:plugins:migrate NAME=redmine_agile VERSION=0 RAILS_ENV=production
Running raketask redmine:plugins:migrate...
Migrating redmine_agile (Redmine Agile plugin (Light version))...
== 5 AddStoryPointsToAgileRanks: reverting ====================================
-- remove_column(:agile_data, :story_points, :integer)
   -> 0.0834s
== 5 AddStoryPointsToAgileRanks: reverted (0.1472s) ===========================

... 省略

== 1 CreateIssueStatusOrders: reverting =======================================
-- remove_index(:issue_status_orders, {:column=>:position})
   -> 0.0191s
-- remove_index(:issue_status_orders, {:column=>:issue_id})
   -> 0.0207s
-- drop_table(:issue_status_orders)
   -> 0.0084s
== 1 CreateIssueStatusOrders: reverted (0.0488s) ==============================

Pluginの削除:

# sameersbn/redmine コンテナ内で
rm -rf /home/redmine/data/plugins/redmine_agile

[注] /home/redmine/redmine/plugins ではありません!詳細は記事下部の参考情報セクションに記載しています。

easy gantt plugin

error:

redmine_1  | NoMethodError: undefined method `to_prepare' for ActionDispatch::Reloader:Class
redmine_1  | /home/redmine/redmine/plugins/easy_gantt/after_init.rb:43:in `<top (required)>'
redmine_1  | /home/redmine/redmine/plugins/easy_gantt/init.rb:24:in `require_relative'
redmine_1  | /home/redmine/redmine/plugins/easy_gantt/init.rb:24:in `<top (required)>'

Redmine Gantt Plugin - Easy Redmine

公式にある通り Redmine 4 対応は完了しているのだが、わざわざPluginによるガントチャート機能を利用していたモチベーションは以下の通り。

  • もともとオリジナルのものはチケットタイトル幅が狭く表示がよく切れる
  • ガントチャート画面でチケットのステータス変更が一切できない
  • EasyGanttではドラッグで開始・期日を設定でき、まとめて設定反映できる(便利)
  • チケット関連付けもドラッグでできる

このなかで半分はRedmine 4にて解消されているので、とりあえず標準のもので過ごしてみようと思う。 ドラッグでの日付設定機能はオリジナルでは全く敵わないところですが、Free版EasyGanttだと複数プロジェクトを跨いだガントチャート表示ができない制約があり、なんとも中途半端な状況だったので消すことの悔いもなし。

モデル削除:

entrypoint.sh app:rake redmine:plugins:migrate NAME=easy_gantt VERSION=0 RAILS_ENV=production
Running raketask redmine:plugins:migrate...
Migrating easy_gantt (Easy Gantt plugin)...
== 20170224134615 UpdateRestApiSettings: reverting ============================
== 20170224134615 UpdateRestApiSettings: reverted (0.0000s) ===================

== 20170213152215 AddDefaultPrintableTemplate: reverting ======================
== 20170213152215 AddDefaultPrintableTemplate: reverted (0.0000s) =============

Pluginの削除:

# sameersbn/redmine コンテナ内で
rm -rf /home/redmine/data/plugins/easy_gantt

[注] /home/redmine/redmine/plugins ではありません!詳細は記事下部の参考情報セクションに記載しています。

redmine_tweaks plugin

redmine_tweaks はもともと怪しかった(設定がうまく反映できないバグや、migrationを使わずにredmine本体のテーブル利用している設計思想などの)ため redmine 4.x 対応は厳しいかなと思っていた。ヘッダメニューなんかは地味に便利に使っていたのだが、レポジトリもread-onlyになってしまっていたので更新が期待できず、今後のredmine追従に支障が生じるため削除。

redmine_tweaks はDBを利用しているがRedmineの settings テーブルに書き込んでいて migration が無い。なのでファイルだけ消すことにする。(plugin_redmine_tweaksというnameでsettingsテーブルに存在している)

なので、Migrationしても何も起きません。

$ entrypoint.sh app:rake redmine:plugins:migrate NAME=redmine_tweaks VERSION=0 RAILS_ENV=production
Running raketask redmine:plugins:migrate...
Migrating redmine_tweaks (Tweaks)...
$

Pluginの削除:

# sameersbn/redmine コンテナ内で
rm -rf /home/redmine/data/plugins/redmine_tweaks

[注] /home/redmine/redmine/plugins ではありません!詳細は記事下部の参考情報セクションに記載しています。

redmine_issue_completion plugin

https://github.com/insspb/redmine_issue_completion

error

redmine_1  | Migrating plugins. Please be patient, this could take a while...
redmine_1  | rake aborted!
redmine_1  | NoMethodError: undefined method `to_prepare' for ActionDispatch::Callbacks:Class
redmine_1  | /home/redmine/redmine/plugins/redmine_issue_completion/init.rb:3:in `<top (required)>'

to_prepare メソッドを使っていて Redmine 4 では利用できなかった。
1ファイルだけのシンプルなPluginなので若干の修正で利用できるようになるものの、独自運用は辛いこと、および機能要件もシンプルなので view_customize plugin にて javascript で同等の操作性を実現するなど代替手段もあり、致命的じゃないし削除する。

作業2. Pluginのアップデート

まずは各pluginディレクトリに移動して git pull し、更新があるかチェックします。
(とりあえず git pull というのも少々乱暴なので、本当は各プロジェクトページで更新情報を確認しましょう)

以下、不都合あった Plugin のメモ。

clipboard_image_paste plugin

redmine_1  | rake aborted!
redmine_1  | NoMethodError: undefined method `to_prepare' for ActionDispatch::Callbacks:Class
redmine_1  | /home/redmine/redmine/plugins/clipboard_image_paste/init.rb:32:in `<top (required)>'

clipboard_image_paste は pull request が出ているようだが、2019/04/21現在まだ merge されていない。 https://github.com/peclik/clipboard_image_paste/pull/80/files

一旦、pull request元の @Utopism のレポジトリからpullすることにする。

[https://github.com/Utopism/clipboard_image_paste.git:embed:cite]

git remote add branch-v4 https://github.com/Utopism/clipboard_image_paste.git
git pull branch-v4 master

redmine_github_hook plugin

Errorが出て動かない。

$ more log/unicorn.stderr.log

I, [2019-04-21T15:59:49.539450 #302]  INFO -- : Refreshing Gem list
/home/redmine/redmine/plugins/redmine_github_hook/app/controllers/github_hook_controller.rb:4:in `<class:GithubHookController>': undefined method `skip_before_filter' for GithubHookController:Class (NoMethodError)
        from /home/redmine/redmine/plugins/redmine_github_hook/app/controllers/github_hook_controller.rb:3:in `<top (required)>'

commit log も2年ほど内容変更がないみたい。RedmineへのGitレポジトリ連携は直近主要因ではないので、今回はバッサリ切ることにする。
https://github.com/koppen/redmine_github_hook/commits/master

手順超サマリ

後日へのカンペ・参考として記録。

Redmine起動したあと、

# コンテナ内で

entrypoint.sh app:rake redmine:plugins:migrate NAME=redmine_agile VERSION=0 RAILS_ENV=production
rm -rf /home/redmine/data/plugins/redmine_agile

entrypoint.sh app:rake redmine:plugins:migrate NAME=easy_gantt VERSION=0 RAILS_ENV=production
rm -rf /home/redmine/data/plugins/easy_gantt

rm -rf /home/redmine/data/plugins/redmine_tweaks

exit

起動しているコンテナを削除。ここで rm -f redmine までしっかりやらないとコンテナキャッシュの方には上で消したファイルがコピーで残っているので、次に起動するとまた Migration されて復活してしまう

docker-compose stop redmine
docker-compose rm -f redmine

plugin最新化。ここで image: sameersbn/redmine:4.0.3-1 に変更する。

# 作業用にPluginディレクトリを設定。もちろんお好みで。
export _WORK_RED_PLUGINDIR=/path/to/xx

# work_time をgit管理していなかったのでやり直し
cd ${_WORK_RED_PLUGINDIR}
rm -rf redmine_work_time
git clone https://github.com/tkusukawa/redmine_work_time.git

# 使わないので削除
cd ${_WORK_RED_PLUGINDIR}
rm -rf redmine_issue_completion

# 最新化
cd ${_WORK_RED_PLUGINDIR}/view_customize
git stash; git pull
cd ${_WORK_RED_PLUGINDIR}/redmine_default_custom_query
git stash; git pull
cd ${_WORK_RED_PLUGINDIR}/redmine_issue_templates
git stash; git pull
cd ${_WORK_RED_PLUGINDIR}/redmine_issues_summary_graph
git stash; git pull
cd ${_WORK_RED_PLUGINDIR}/redmine_pivot_table
git stash; git pull
cd ${_WORK_RED_PLUGINDIR}/redmine_wiki_extensions
git stash; git pull

# fork先に変更
cd ${_WORK_RED_PLUGINDIR}/clipboard_image_paste
git remote add branch-v4 https://github.com/Utopism/clipboard_image_paste.git
gti remote -v
git pull branch-v4 master

Redmine 4.x 検証まとめ

参考情報に記載したとおり project_settings_tabs まわりのエラーが致命的なので、最後の最後で保留することにしました。プロジェクトの “設定” 画面に繊維する際に 500 エラーが発生してしまうため・・・。ここは別途、時間を見つけて再Tryしようと思います。

Redmine 3.x から 4.x へのアップグレードは Rails 4.x から 5.x への変化を伴い、alias_method_chain という定番コーディング手法が使えなくなったことで Plugin の互換性には大ダメージがあります。そのため Redmine 4.x のリリース後もすぐには飛びつかず様子を見ていて、4ヶ月程経過したのでそろそろよいかなと試すに至ったのですが、惜しいところで終わってしまいました。

上記の通り、メンテナンスされていない Plugin を Redmine 4.x で利用するのはハードルが高いため、ちょっと妥協できるものや代替プラグインがあるものはバッサリ捨てて乗り換えるのが近道なのだろうと思っています。

ちなみに、今回は全く関係ないですが別プロジェクトで活躍しているスクラム開発用プラグイン redmine_backlogsは、Redmine 3.4 へのアップグレード時点で簡単には動かなくなっていたので Redmine 3.3 で止まっている。そのプロジェクトは、この先もずっと Redmine 3.3 から動けなさそうです。

(参考情報)Pluginのアンインストールができない

sameersbn/redmine の README には以下の記載がある。

Uninstalling Plugins

To uninstall plugins you need to first tell redmine about the plugin you need to uninstall. This is done via a rake task:

docker run --name=redmine -it --rm \
  --volume=/srv/docker/redmine/redmine:/home/redmine/data \
  sameersbn/redmine:4.0.3-1 \
  app:rake redmine:plugins:migrate NAME=plugin_name VERSION=0

Once the rake task has been executed, the plugin should be removed from the /srv/docker/redmine/redmine/plugins/ directory.

rm -rf /srv/docker/redmine/redmine/plugins/plugin_name

Any configuration that you may have added in the /srv/docker/redmine/redmine/plugins/post-install.sh script for the plugin should also be removed.

For example, to remove the recurring tasks plugin:

docker run --name=redmine -it --rm \
  --volume=/srv/docker/redmine/redmine:/home/redmine/data \
  sameersbn/redmine:4.0.3-1 \
  app:rake redmine:plugins:migrate NAME=recurring_tasks VERSION=0
rm -rf /srv/docker/redmine/redmine/plugins/recurring_tasks

Now when the image is started the plugin will be gone.

via GitHub - sameersbn/docker-redmine: Docker Image for Redmine

しかし、Plugin <PLUGIN_NAME> was not found とエラーが出て実行できない。例えばこのような感じ。

Running raketask redmine:plugins:migrate...
Plugin easy_gantt was not found.

試したこと:

  • 説明通りに docker run で実行

    • DB接続の環境変数は設定してある
  • docker-compose run redmine bash でコンテナ内に入って entrypoint.sh app:rake ... を実行

    • docker-compose は普段サービス提供用で利用していて正常な前提

よくよく見てみると、説明通りだとrake が実行されるタイミングでは /home/redmine/redmine/plugins ディレクトリ内に何も存在していない。しかし、 sameersbn/redmine を普通に起動した際にはこのディレクトリ内にはマウントした plugins が一通り配置されている。これは起動スクリプトでファイル一式をコピーしているのだと思う。

docker-redmine/entrypoint.sh at 5bd6bcdcdeb68ee7fc169e1f44e180821adafd80 · sameersbn/docker-redmine · GitHub (2019/04/21時点の master レポジトリ)

install_plugins() での処理: docker-redmine/functions at 5bd6bcdcdeb68ee7fc169e1f44e180821adafd80 · sameersbn/docker-redmine · GitHub

一方、その下にある app:rake では execute_raketask として実行しているが、中身は以下の通り、ただ bundle exec raks $@ しているだけ。/home/redmine/redmine/plugins にプラグインが存在していない状態で実行しており、その結果 Plugin <PLUGIN_NAME> was not found エラーが出ていると見える。

docker-redmine/functions at 5bd6bcdcdeb68ee7fc169e1f44e180821adafd80 · sameersbn/docker-redmine · GitHub

結果的には アプリケーションとしてのredmineを正常に起動した状態で(Webサービスコンテナが起動している状態で) redmine:plugins:migrate を実行する必要があるということ。実際、”Pluginアンインストール” セクションで記載の通り Migration が正常に完了しました。

(参考情報)super: no superclass method ‘project_settings_tabs’

Completed 500 Internal Server Error in 47ms (ActiveRecord: 5.3ms)

ActionView::Template::Error (super: no superclass method `project_settings_tabs' for #<#<Class:0x00000000071b1140>:0x00000000074deea8>):
    1: <h2><%=l(:label_settings)%></h2>
    2:
    3: <%= render_tabs project_settings_tabs %>
    4:
    5: <% html_title(l(:label_settings)) -%>

plugins/redmine_wiki_extensions/lib/wiki_extensions_projects_helper_patch.rb:22:in `project_settings_tabs'
plugins/redmine_default_custom_query/app/patches/helpers/projects_helper_patch.rb:13:in `project_settings_tabs_with_default_query_setting_tab'
plugins/redmine_issue_templates/lib/issue_templates/projects_helper_patch.rb:6:in `project_settings_tabs'
app/views/projects/settings.html.erb:3:in `_app_views_projects_settings_html_erb___1919254735469764375_59610100'
lib/redmine/sudo_mode.rb:63:in `sudo_mode'

1個ずつPluginを外して切り分けた結果、それぞれ単体では動作した。
ちょっと調べてみると下記のIssue(今回利用しているPluginとは全く関係ない)の議論が参考にるのではないかと思う。

それぞれのファイルの対象コードは以下の通り。比較用にメモ。

# redmine_wiki_extensions/lib/wiki_extensions_projects_helper_patch.rb:22
module ProjectsHelperMethodsWikiExtensions
  def project_settings_tabs
    tabs = super #line 22
# redmine_issue_templates/lib/issue_templates/projects_helper_patch.rb:6
module ProjectsHelperPatch
  def project_settings_tabs
    tabs = super #line 6
# redmine_default_custom_query/app/patches/helpers/projects_helper_patch.rb:13
included do
  alias_method :project_settings_tabs_without_default_query_setting_tab, :project_settings_tabs
  alias_method :project_settings_tabs, :project_settings_tabs_with_default_query_setting_tab
end

def project_settings_tabs_with_default_query_setting_tab
  tabs = project_settings_tabs_without_default_query_setting_tab #line 13

(参考情報)Creating scope :system. Overwriting existing method Enumeration.system.

Creating scope :system. Overwriting existing method Enumeration.system.
Creating scope :sorted. Overwriting existing method Group.sorted.
Creating scope :sorted. Overwriting existing method User.sorted.

エラーの背景はQiitaの記事に関連したものと思うのだが、ググってみると割と数年前から出てる記載も見つかるし、出ているからといって問題になるわけでもない。けど 3.x 系では表示されていないのが気になる・・・。しばし様子見。