Edited at

イントラ環境向け複数Redmine構築メモと使用プラグイン一覧

More than 1 year has passed since last update.

ベストな方法かどうかはわからないですが、どのように環境構築しているのかを自分のメモ代わりに書いています。

もし、もっとこうした方がいいよと言うのがあればコメントお願いします。


Redmineの利用目的

社内でRedmineを20サイト以上運用管理しています。社内におけるRedmineの利用目的としては


  • 情報共有

  • 文書管理

  • ナレッジ共有

  • 案件管理・出荷業務管理

  • ITIL的運用(サポート、問い合わせ)

  • プロジェクト管理

  • 在庫・出荷情報管理

となっていて、Redmine本来のプロジェクト管理として使っているところは少ないです。

ExcelからAccess使ってマクロ組んで...の代わりに、RedmineのチケットをDBとして利用している使い方が多い状態です。

また、使用する部署、部門横断的な管理等があり、それぞれ管理ポリシーが異なるため同一ホストでは運用が困難なため結果として複数ホストになっています。


サーバー環境

OS: CentOS 7.4

HTTP Server: Apache 2.4

DB: MariaDB

DB管理: phpmyadmin (PHPは7.1)

Ruby: 2.3

Rubyはソースコードからコンパイルしています。Rubyが最新バージョンでないのは一部のプラグインでRuby 2.4に対応していないものがあったので2.3にしています。

他は、yumでインストールしています。

インストール時の流れは

http://blog.redmine.jp/articles/3_4/install/centos/

http://blog.redmine.jp/articles/3_0/installation_centos/

を参照してください。


Apacheの設定

複数のRedmineを1台のサーバーで構築するので、VirtualHostを使用します。

passengerの設定とVirtualHostのファイル構成は以下のようにしています。


/etc/httpd/conf.d/

/etc/httpd/conf.d/passenger.conf

/etc/httpd/conf.d/virtualhost.conf
/etc/httpd/conf.d/virtualhost/<ホスト名>.conf

VirtualHostの設定ファイルを1ホストに対して1ファイルとすることで、複数建てる時にコピーして使用できるので便利です。


/etc/httpd/conf.d/passenger.conf

LoadModule passenger_module /usr/local/lib/ruby/gems/2.3.0/gems/passenger-5.1.11/buildout/apache2/mod_passenger.so

<IfModule mod_passenger.c>
PassengerRoot /usr/local/lib/ruby/gems/2.3.0/gems/passenger-5.1.11
PassengerDefaultRuby /usr/local/bin/ruby
</IfModule>

# Passengerが追加するHTTPヘッダを削除するための設定(任意)。
#
Header always unset "X-Powered-By"
Header always unset "X-Runtime"

# 必要に応じてPassengerのチューニングのための設定を追加(任意)。
# 詳しくはPhusion Passenger users guide(https://www.phusionpassenger.com/library/config/apache/reference/)参照。
PassengerMaxPoolSize 20
PassengerMaxInstancesPerApp 4
PassengerPoolIdleTime 864000
PassengerHighPerformance on
PassengerStatThrottleRate 10
PassengerSpawnMethod smart
PassengerFriendlyErrorPages off
PassengerStartTimeout 120



/etc/httpd/conf.d/virtualhost.conf

# VirtualHost設定群読み込み

IncludeOptional conf.d/virtualhost/*.conf


/etc/httpd/conf.d/virtualhost/ホスト名.conf

<VirtualHost *:80>

ServerName <ホスト名>.example.local
DocumentRoot /var/www/redmine/site/<ホスト名>/public
ErrorLog logs/<ホスト名>-error_log
CustomLog logs/<ホスト名>-access_log combined
</VirtualHost>

PassengerPreStart http://<ホスト名>.example.local


RedmineのVirtualHostは、/var/www/redmine/site以下にホスト名をフォルダ名にしてRedmineをインストールしています。


MariaDBの設定

物忘れが激しいので、RedmineのDBを作成する際は、ユーザ名とDB名を同じにしています。

パフォーマンスチューニングは、 https://github.com/major/MySQLTuner-perl を利用して適宜調整しています。


/etc/my.cnf.d/server.cnf

#

# These groups are read by MariaDB server.
# Use it for options that only the server (but not clients) should see
#
# See the examples of server my.cnf files in /usr/share/mysql/
#

# this is read by the standalone daemon and embedded servers
[server]

# this is only for the mysqld standalone daemon
[mysqld]
character-set-server = utf8
skip-name-resolve
thread_cache_size=4
query_cache_size=0
query_cache_type=0
query_cache_limit=8M
innodb_file_per_table=1
innodb_log_file_size=16M
tmp_table_size=32M
max_heap_table_size=32M
table_open_cache=512
join_buffer_size=256K

# スロークエリの出力設定
slow_query_log=ON
# スロークエリと判定する秒数
long_query_time=3
# スロークエリログの場所
log-slow-queries=/var/log/mariadb/mariadb_slow.log

performance_schema=on

# this is only for embedded server
[embedded]

# This group is only read by MariaDB-5.5 servers.
# If you use the same .cnf file for MariaDB of different versions,
# use this group for options that older servers don't understand
[mysqld-5.5]

# These two groups are only read by MariaDB servers, not by MySQL.
# If you use the same .cnf file for MySQL and MariaDB,
# you can put MariaDB-only options here
[mariadb]

[mariadb-5.5]


チューニング中の値になっていますので、数字は参考にしないでください。

適宜、mysqltunerを使用してパラメータ設定を行ってください。


使用しているプラグインとテーマ

テーマと多数のプラグインを各Redmineのサイトに適用するのは困難なため、/var/www/redmine/theme, /var/www/redmine/plugin のフォルダ以下にそれぞれ使用するテーマとプラグインを入れます。

各Redmineのサイト用のフォルダ(/var/www/redmine/site/<ホスト名>/)のplugin, public/theme フォルダ以下で、先のテーマ、プラグインをシンボリックリンクします。シンボリックリンクを行う際は相対パスにせず絶対パスにします。(フォルダ移動させた時も不整合が起こらないようにするため)

このようにすることで、同一のプラグインを使用していてパッチの適用忘れやバージョンアップ忘れを防ぎます。

必ず入れているプラグインの方では、Redmine3.4.2で動作確認(簡単に)していますが、一部でしか使用していないプラグインはまだ未検証なものがあります。


使用しているテーマ

Redmineのテーマは、

https://github.com/farend/redmine_theme_farend_fancy

を使用しています


使用しているプラグイン


ほぼ必ず入れれているプラグイン

プラグイン名称
機能
備考

Clipboard image paste
クリップボードイメージの貼り付け

Redmine Banner plugin
バナー表示をさせる。
管理者からの通知に便利

Redmine Default Custom Query
プロジェクト毎にデフォルトのカスタムクエリーを指定できる

DMSF
文書、画像の管理を可能にする
ZIP圧縮で文字化けするのでパッチ必要。easyredmine社でもメンテされている

Knowledgebase
ナレッジベース
メンテ復活!!

Redmine LDAP Sync
LDAP情報の同期、参照フィールドの追加、グループ割り当てが可能

Redmine Multiple Projects per Issue plugin
一つのチケットを複数プロジェクトに割り当て

Redmine Startpage plugin
Redmineのデフォルトの概要ページを任意のページに変更できる
TOPページプロジェクトを作成してWikiページをStartPageにしているケースが多い

Redmine Tags
チケット、Wikiへのタグ追加
redmineup(旧redmine crm)社がサポート?

Redmine Wiki Extensions plugin
Wikiの機能拡張
Tag機能はRedmine Tagsと被るので無効にする

Redmine Wiki Lists plugin
Wikiページにチケット一覧を表示

Sidebar Hide Plugin
サイドバーを隠すボタン追加
view customizeでも可能

Spectator plugin
管理者が他人に成りすますことができる

View Customize plugin
神プラグイン! javascriptができればなんでもできる。

WikiNG
視覚的に便利なマクロ追加と、オリジナルのmacro追加可能
本家 3.4.x対応


一部で使用しているプラグイン

プラグイン名称
機能
備考

Computed custom field
カスタムフィールドで計算ができる
チケット作成後に計算結果が反映される。view customizeでできない計算も可能(内部データ参照可能)。easyredmine社でもメンテされている。

Lycheeプラグイン
ガントチャート、EVM、リソース管理等

Redmine Agile
タスクカンバン

Redmine Checklist
チケットにチェックリスト追加
Pro版はテンプレート登録可能

Redmine Contact
コンタクトリスト(会社、顧客)を作成できる

Redmine Introductions plugin
チュートリアルを作成できる

Redmine Issue Templates plugin
チケットテンプレート作成
個人的にはView Customizeでやる方が好きだが、View Customize触れない人でもテンプレートが作成できる

Redmine Products
製品情報を登録できる

Redmine Q&A plugin
QAサイト構築

Redmine Wiki Unc plugin
fileリンクをサポートできる
できるだけFileリポジトリを使用しているが、アクセス権の関係上できない場合はこれを使う。ただし、IEのみ対応になる


プラグインパッチ


DMSF

DMSFの保存フォルダ指定は、最新のものは相対パスで指定するようになっています。

Redmineのフォルダ移行する際にも相対パスの方が都合がよいのでDMSFを最新のものにアップデートしたら変更をお勧めします。(デフォルトは、dmsfになっていますが、旧DMSFからアップグレードした場合は、files/dmsf になると思います)

DMSFで複数ファイル選択してダウンロードもしくはフォルダーのダウンロードを行った際に、UTF-8のままZIP圧縮を行うので、Windowsで展開した際に文字化けが起こるので、SJISに変換する必要があります。

diff -urN ../../redmine/plugins/redmine_dmsf/app/controllers/dmsf_controller.rb redmine_dmsf/app/controllers/dmsf_controller.rb

--- ../../redmine/plugins/redmine_dmsf/app/controllers/dmsf_controller.rb 2017-10-30 17:37:11.602348740 +0900
+++ redmine_dmsf/app/controllers/dmsf_controller.rb 2017-11-09 09:47:57.086032137 +0900
@@ -413,11 +413,15 @@

def zip_entries(zip, selected_folders, selected_files)
member = Member.where(:user_id => User.current.id, :project_id => @project.id).first
+ encoding = "utf-8"
+ encoding = "sjis" if request.env["HTTP_USER_AGENT"] =~ /Windows/ && request.env["HTTP_ACCEPT_LANGUAGE"] =~ /^ja/
+
if selected_folders && selected_folders.is_a?(Array)
selected_folders.each do |selected_folder_id|
folder = DmsfFolder.visible.find_by_id selected_folder_id
if folder
- zip.add_folder(folder, member, (folder.dmsf_folder.dmsf_path_str if folder.dmsf_folder))
+# zip.add_folder(folder, member, (folder.dmsf_folder.dmsf_path_str if folder.dmsf_folder))
+ zip.add_folder(folder, member, (@folder.dmsf_path_str if @folder), encoding)
else
raise FileNotFound
end
@@ -432,7 +436,8 @@
unless (file.project == @project) || User.current.allowed_to?(:view_dmsf_files, file.project)
raise DmsfAccessError
end
- zip.add_file(file, member, (file.dmsf_folder.dmsf_path_str if file.dmsf_folder)) if file
+# zip.add_file(file, member, (file.dmsf_folder.dmsf_path_str if file.dmsf_folder)) if file
+ zip.add_file(file, member, (@folder.dmsf_path_str if @folder), encoding) if file
end
end
max_files = Setting.plugin_redmine_dmsf['dmsf_max_file_download'].to_i
diff -urN ../../redmine/plugins/redmine_dmsf/lib/dmsf_zip.rb redmine_dmsf/lib/dmsf_zip.rb
--- ../../redmine/plugins/redmine_dmsf/lib/dmsf_zip.rb 2017-10-30 17:37:11.640347920 +0900
+++ redmine_dmsf/lib/dmsf_zip.rb 2017-11-09 09:53:10.165323530 +0900
@@ -20,6 +20,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

require 'zip'
+require 'kconv'

class DmsfZip

@@ -43,7 +44,8 @@
@zip.close if @zip
end

- def add_file(file, member, root_path = nil)
+# def add_file(file, member, root_path = nil)
+ def add_file(file, member, root_path = nil, encoding = "utf-8")
unless @files.include?(file)
string_path = file.dmsf_folder.nil? ? '' : "#{file.dmsf_folder.dmsf_path_str}/"
string_path = string_path[(root_path.length + 1) .. string_path.length] if root_path
@@ -53,6 +55,11 @@
else
string_path += file.formatted_name(Setting.plugin_redmine_dmsf['dmsf_global_title_format'])
end
+
+ if encoding == "sjis"
+ string_path = string_path.tosjis()
+ end
+
@zip_file.put_next_entry(string_path)
File.open(file.last_revision.disk_file, 'rb') do |f|
while (buffer = f.read(8192))
@@ -63,15 +70,25 @@
end
end

- def add_folder(folder, member, root_path = nil)
+# def add_folder(folder, member, root_path = nil)
+ def add_folder(folder, member, root_path = nil, encoding = "utf-8")
+
unless @folders.include?(folder)
string_path = "#{folder.dmsf_path_str}/"
string_path = string_path[(root_path.length + 1) .. string_path.length] if root_path
+
+ if encoding == "sjis"
+ string_path = string_path.tosjis()
+ end
+
@zip_file.put_next_entry(string_path)
@folders << folder
- folder.dmsf_folders.visible.each { |subfolder| self.add_folder(subfolder, member, root_path) }
- folder.dmsf_files.visible.each { |file| self.add_file(file, member, root_path) }
+# folder.dmsf_folders.visible.each { |subfolder| self.add_folder(subfolder, member, root_path) }
+# folder.dmsf_files.visible.each { |file| self.add_file(file, member, root_path) }
+ folder.dmsf_folders.visible.each { |subfolder| self.add_folder(subfolder, member, root_path, encoding) }
+ folder.dmsf_files.visible.each { |file| self.add_file(file, member, root_path, encoding) }
+
end
end


knowledgebase

イントラ環境下だとインターネット側にアクセスする場合だけだとおもいます。Gemfileを以下のようにします

不具合修正を含めたものは

https://github.com/crosspoints/redmine_knowledgebase

で公開しています

2018/1/12時点で本家側に取り込まれましたので本家のものを使用ください。

以下不要です

gem 'redmine_acts_as_taggable_on', :git => "https://github.com/alexbevi/redmine_acts_as_taggable_on"

gem 'ya2yaml'
gem 'awesome_nested_set'

不具合修正パッチ

--- redmine_knowledgebase-master/app/views/articles/show.html.erb       2017-11-19 22:57:32.000000000 +0900

+++ redmine_knowledgebase/app/views/articles/show.html.erb 2018-01-11 16:13:19.261609100 +0900
@@ -18,8 +18,9 @@
<% end %>

<li><%= link_to_if_authorized l(:label_new_comment), { :controller => "articles", :action => "comment",
:article_id => @article.id, :project_id => @project}, :class => "icon icon-comment", :remote => true, :method => :get %>
</li>
+ <li> <%= watcher_link(@article, User.current) %></li>
<li>
- <%= render :partial => 'watchers/watchers', :locals => {:watched => @article} %>
+ <%= render :partial => 'articles/watchers', :locals => {:watched => @article} %>
</li>
</ul>
<br />
diff -uprN redmine_knowledgebase-master/app/views/categories/show.html.erb redmine_knowledgebase/app/views/categories/sh
ow.html.erb
--- redmine_knowledgebase-master/app/views/categories/show.html.erb 2017-11-19 22:57:32.000000000 +0900
+++ redmine_knowledgebase/app/views/categories/show.html.erb 2018-01-11 16:13:19.385997800 +0900
@@ -20,7 +20,8 @@
<li><%= link_to_if_authorized l(:label_new_category), { :controller => 'categories', :action => 'new', :parent_id =
> @category.id, :project_id => @project}, :class => 'icon icon-add' %></li>
<li><%= link_to_if_authorized l(:label_edit_category), { :controller => 'categories', :action => 'edit', :id => @ca
tegory.id, :project_id => @project}, :class => 'icon icon-edit' %></li>
<li><%= link_to_if_authorized l(:label_delete_category), { :controller => 'categories', :action => 'destroy', :id =
> @category.id, :project_id => @project}, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-de
l' %></li> <li>
- <%= render :partial => 'watchers/watchers', :locals => {:watched => @category} %>
+ <li><%= watcher_link(@category, User.current) %></li>
+ <%= render :partial => 'categories/watchers', :locals => {:watched => @category} %>
</li>
</ul>
<h3><%= l(:title_browse_by_category) %></h3>


WikiNG

buttonマクロが動作しない場合は以下のようにする


wiking.css

a.wiki-class-button {

border-width: 1px;
border-style: solid;
-moz-border-radius: 6px;
border-radius: 6px;
background-color: #507aaa;
border-color: #809fc3 #2C4056 #2C4056 #809fc3;
-moz-text-shadow: 1px 1px 1px #2C4056;
text-shadow: 1px 1px 1px #2C4056;
padding: 0.5em 1.25em;
text-decoration: none;
color: #fff;
display: inline-block;
}
a:active.wiki-class-button {
border-color: #2C4056 #809fc3 #809fc3 #2C4056;
}

View Customizeで定義してもOK