Atlassian の Confluence を自宅のサーバで動かすまで その 2

前回までのあらすじ:
Tomcat の設定まで終わりましたが、なんのために複数インスタンスを立ち上げるのか、前提条件についての話がなかったですね。家族旅行管理サイトとマンション管理組合サイトと、 1 つのサーバで 2 つのサイトを立ち上げたいからでした。

というわけで、次は MySQL のインストールと設定を行います。Atlassian はかなりドキュメントが充実していて、だいたいは Database Setup For MySQL を見れば事足ります。
補足としては character set の設定を utf8 ではなく、 utf8mb4 にした方が良さそう、ってところかな〜。要は、 4 byte 文字を扱えるようにしたい!ってことです。🍺とか🍛とか💩とかですね。
そのためには、上記のドキュメントの以下で記載されている設定を、下記のように書き換えます。

Step 3. Configure MySQL Server > To configure MySQL Server: > 2. > Specify the default character set to be UTF-8:

[mysqld]
...
character-set-server=utf8mb4
collation-server=utf8mb4_bin
...

以下の部分も同様です。

Step 4. Set up your MySQL database and user > To create the database and user privileges: > 2.

こんな感じ。

CREATE DATABASE foo CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
CREATE DATABASE bar CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;

ついでに、ここも、こう!

Step 4. Set up your MySQL database and user > To create the database and user privileges: > 3.

GRANT ALL PRIVILEGES ON foo.* TO 'foo'@'localhost' IDENTIFIED BY 'お好みで';
GRANT ALL PRIVILEGES ON bar.* TO 'bar'@'localhost' IDENTIFIED BY 'お好みで';

このまま無事に Confluence で利用できればいいのですが、そうは簡単にいきません。
character set に utf8mb4 を指定しているため、 MySQL の仕様にぶつかることになります。詳細は 14.8.1.7 Limits on InnoDB Tables > Maximums and Minimums にありますが、要は、

By default, the index key prefix length limit is 767 bytes. See Section 13.1.13, “CREATE INDEX Syntax”. For example, you might hit this limit with a column prefix index of more than 255 characters on a TEXT or VARCHAR column, assuming a utf8mb3 character set and the maximum of 3 bytes for each character. When the innodb_large_prefix configuration option is enabled, the index key prefix length limit is raised to 3072 bytes for InnoDB tables that use DYNAMIC or COMPRESSED row format.

Attempting to use an index key prefix length that exceeds the limit returns an error. To avoid such errors in replication configurations, avoid enabling innodb_large_prefix on the master if it cannot also be enabled on slaves.

The limits that apply to index key prefixes also apply to full-column index keys.

と、いうことだそうです。
テーブルやカラムの作成には Confluence が用意した DDL を流すだけなので、ここに手を入れることは考えない方が良いでしょう。
幸いにも MySQL 5.7 系であれば、この制限は緩和されているようなので、 MySQL のバージョンをあげることになります。
ところが、いまのところ Portage で扱っている MySQL の最新バージョンは 5.6.37 なんですよねぇ。
そこで、 Gentoo Linux にはローカルなオレオレ ebuild を利用するための overlay という仕組みがあります。 /etc/portage/make.conf の PORTDIR_OVERLAY にパスを指定することで、自分で ebuild を作成してなんとかする方法もあります、というか、若かりし頃はやってました(遠い目)。
現在は Gentoo Linux もかなりメジャーな存在になり、非公式なリポジトリやそれを扱うツールもあるため、ちょっと探すとでてきます、やったね!。
具体的には layman というツールを入れます。

# emerge layman

あとは、親切な人が https://gpo.zugaina.org/dev-db/mysql に 5.7 系の ebuild を置いてくれているので、

# layman -a mysql

とすると、ローカルのリポジトリに追加されます。マスクがかかっているので、外してあげれば、これで 5.7 系の MySQL をインストールすることができます。正直なところ、野良パッケージはできるだけ使いたくないのだけど、中身みても大丈夫っぽいので今回は OK ってことにします。

これで MySQL のお話はだいたいおしまい。
だんだん説明が荒くなっていくけど、次できっと最後だよ!

Atlassian の Confluence を自宅のサーバで動かすまで その 1

Confluence という、 Atlassian の製品があります。要は Wiki のお化けみたいなドキュメント共有 Web アプリケーションで、過去に仕事で使った際にすごくよかったので、プライベートでも使っています。
今回はそれを導入するまでのお話しです。

例によって、対象読者は環境を再構築せざるを得なくなった将来の自分です。感謝しろよ、未来のじぶん。

自宅のサーバで動かすには Download Confluence Server から必要なファイルを取ってきて、デプロイします。
Linux 64 Bit を選択すると、インストーラTomcat のインストールから Confluence 用のユーザとグループの作成まで全部やってくれるのですが、Linux ディストリビューションが用意した環境から独立したアプリケーションとなるので、ちょっと気持ちが悪いです。
そこで、 TAR.GZ Archive を選択し、自分で用意した Tomcat で動かします。
必要な作業はだいたいこんな感じです。

  1. Tomcat のインストールと設定
  2. MySQL のインストールと設定
  3. Apache のインストールと設定

1. のインストールについては Apache Tomcat を見ておけばだいたい大丈夫です。あ、ディストリビューションGentoo Linux ね。
インストールが終わったら、こんな感じで 2 つインスタンスを作ります。

# /usr/share/tomcat-8/gentoo/tomcat-instance-manager.bash --create --suffix foo
# /usr/share/tomcat-8/gentoo/tomcat-instance-manager.bash --create --suffix bar

インスタンスを 2 つ作る理由は、 1 つの Tomcat に複数の Atlassian のアプリケーションをデプロイするのはサポートされていないためです。Deploying Multiple Atlassian Applications in a Single Tomcat Container にいろいろ書かれています。
ここまでできたら、先ほどダウンロードした tar.gz ファイルを展開します。

# cd /usr/share/tomcat-8/webapps
# tar xvzf atlassian-confluence-6.3.1.tar.gz
# cp -r atlassian-confluence-6.3.1 foo
# mv atlassian-confluence-6.3.1 bar

/usr/share/tomcat-8/webapps に展開するのは、なんとなくです。ディレクトリ構成から、ここが良さそうな気がしました。というか、実は LinuxTomcat を動かすのは初めてだったりします。以前の職場で Tomcat を使った開発業務をやっていたこともあるんだけど、環境構築部隊が別に居たのと、サーバが Windows Server だったので興味もなく、そもそも Java の生態系にも興味がなく、ほら、 Java ってさ、クラス名とソースファイル名が合わないとコンパイルできないけど、なんかださくない?、そもそもなんで Java なの?、なんかプロセスの起動にめっさ時間かかるし、すっごいメモリ喰うし、 Java を選ぶ理由って、人を集めやすいってのと後方互換性を頑張ってるところ?、 Write once, run anywhere とかいってたけどさ、 FreeBSD 使ってた頃は Linux エミュレーションで動かしてたし、そろそろ(略)。

展開したら、少しだけファイルを修正します。このファイルでは、 Confluence の設定ファイル群を保存するパスを設定するらしいです。

# cd /usr/share/tomcat-8/webapps
# echo 'confluence.home=/var/atlassian/application-data/foo' >> foo/confluence/WEB-INF/classes/confluence-init.properties
# echo 'confluence.home=/var/atlassian/application-data/bar' >> bar/confluence/WEB-INF/classes/confluence-init.properties

で、そのディレクトリも作っておく、と。

# mkdir -p /var/atlassian/application-data/foo
# chown tomcat:tomcat /var/atlassian/application-data/foo
# chmod 755 /var/atlassian/application-data/foo
# mkdir /var/atlassian/application-data/bar
# chown tomcat:tomcat /var/atlassian/application-data/bar
# chmod 755 /var/atlassian/application-data/bar

ここまでできたら、 /usr/share/tomcat-8/webapps/foo/conf/server.xml を元に、こうしてこうして /etc/tomcat-8-foo/server.xml をこうじゃ!。

<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="kUn9w4mWiPp4t7E">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
      type="org.apache.catalina.UserDatabase"
      description="User database that can be updated and saved"
      factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
      pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <Service name="Catalina">
    <Connector port="8080" connectionTimeout="20000" redirectPort="8443"
      maxThreads="48" minSpareThreads="10"
      enableLookups="false" acceptCount="10" debug="0" URIEncoding="UTF-8"
      protocol="org.apache.coyote.http11.Http11NioProtocol"
      proxyName="www.example.com" proxyPort="443" scheme="https" />
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
          resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps"
        unpackWARs="true" autoDeploy="true">
        <Context path="/foo" docBase="/usr/share/tomcat-8/webapps/foo/confluence" debug="0" reloadable="false" useHttpOnly="true">
          <Manager pathname="" />
          <Valve className="org.apache.catalina.valves.StuckThreadDetectionValve" threshold="60" />
        </Context>
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="/var/log/tomcat-8-foo"
          prefix="localhost_access_log" suffix=".txt"
          pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>

この設定では、 https://www.example.com/foo で Confluence を動かすことを考慮しています。
https://www.example.com/bar 用には上記の設定を以下のように修正して、/etc/tomcat-8-bar/server.xml に設定します。

- Server 要素の port 属性の値に + 1
- Connector 要素の redirectPort 属性の値に + 1
- protocol 属性が AJP/1.3 の Connector 要素で、 port 属性の値に + 10、 redirectPort 属性の値に + 1
- Context 要素の path 属性の値を /bar、 docBase 属性の foo を bar へ
- Valve 要素の directory 属性の foo を bar へ

要は、Tomcat プロセスが使うポートとパスを独立させます。

最後に起動用のスクリプトである /etc/init.d/tomcat-8-foo を修正します。 start-stop-daemon へのオプションをこんな感じにします。

        start-stop-daemon  --start \
                --quiet --background \
                --chdir "${CATALINA_TMPDIR}" \
                --user ${CATALINA_USER}:${CATALINA_GROUP} \
                --make-pidfile --pidfile ${PIDFILE} \
                --exec ${JAVA_HOME}/bin/${cmd} \
                -- \
                        ${JAVA_OPTS} \
                        ${args} \
                        -Dcatalina.base="${CATALINA_BASE}" \
                        -Dcatalina.home="${CATALINA_HOME}" \
                        -Dsynchrony.context.path=/foo/synchrony \
                        -Dsynchrony.port=8081 \
                        -Djava.io.tmpdir="${CATALINA_TMPDIR}" \
                        -Dgentoo.classpath="${GCLASSPATH//:/,}" \
                        -classpath "${CLASSPATH}" \
                        org.apache.catalina.startup.Bootstrap \
                        ${CATALINA_OPTS} \
                        ${TOMCAT_START}

        eend $?

/etc/init.d/tomcat-8-bar には、-Dsynchrony.context.path=/bar/synchrony、-Dsynchrony.port=8091 みたいな感じになるかと。
これは、 WebSocket で使う URL の定義と Tomcat プロセスが WebSocket 用のポートを foo と bar で分けるための措置です。この辺のオプションについては、Recognized System Properties > synchrony.context.path にいろいろ書いてあります。

あとは、それぞれ Tomcat を起動して、

# /etc/init.d/tomcat-8-foo start
# /etc/init.d/tomcat-8-bar start

http://servername:8080/foo, http://servername:8090/bar で、 Confluence の設定画面が表示されれば、 Tomcat はできあがり。なんか、すっごい長いな。

まだまだ続くよ!

本棚にある漫画を電子化して一掃した話

これ、前回の更新からずいぶん経ってるよね?。ハムスターだったら、人生半分終わってるよね。人間に生まれてよかった〜。

久しぶりの更新ですが、今回は漫画の電子化についてです。我が家の本棚にはどうしようもないくらいの漫画で溢れていまして、これをなんとかすべく、電子化に取り組んで参りました。
最初は裁断機と ScanSnap で、裁断してスキャンしている間に、スキャン済みのデータをフィルタアプリケーションに喰わせて、紙質感を取り除きつつ zip ファイルを作成し、規則正しく命名されたフォルダに格納する、という作業を Windows で行なっていました、嫁が。

そんな折に、発見したのが漫画スキャン王という、漫画をダンボールに詰めて送ると、 PDF ファイルにしてくれるサービスでした。この PDF ファイルを元の JPG ファイルに分解し、紙質感を取り除き(以下略)、嫁が。

この一連の作業を手作業でやっていたので、ついカッとなってスクリプトを作成しました。うっかり無くしてしまいそうなので、ここに置いておきます。

https://github.com/maedy/hyohaku

こういう自動化が必要な作業には、 Windows はちょっと UI が窮屈すぎるんですよねぇ。そもそも UNIX には、プログラムのユーザはプログラムである、という大きな問題を小さなプログラムを組み合わせることで(略)。

このスクリプトですが、ComicGlass等の漫画を読む系のアプリケーションに便利なファイル名とディレクトリ構成を構築します。
今のところ、 669 冊ほどこのスクリプトに喰わせていますが、ちょっと mogrify のオプションが攻めすぎかな〜、と思います。紙質感は無くなってますが、スクリーントーンでの表現が意図しない結果になっている部分もあるように見受けられます。今後の課題です。

あとは、シェルスクリプトなので、ちょっと効率悪いかもしれません。ファイル名とディレクトリ名を生成する度に新しいプロセスが生まれています。 C で・・・書く?

この世界には漫画沼というものがありまして、我が家にも紙の漫画が少しづつ湧いてきている状態です。そろそろまた段ボールに詰めて送りつける時期かもしれません。

ファイルサーバのリプレイス

ちょっと自宅のファイルサーバを刷新したので、そのときの注意事項を記載しておきます。対象読者は何もかも忘れてしまった未来の自分です。
新規サーバは Gentoo Linux で作ります。既存のは FreeBSD 8.2-RELEASE です。いずれもファイルシステムZFS を使い RAIDZ で fail safe な状態にします。基本は Gentoo 本家のハンドブックと、Web で見つけたこのメモを見れば OK です。 / も ZFS にすることができます。

https://github.com/ryao/zfs-overlay/blob/master/zfs-install

サーバとなる PC には Western Digital の WD30EZRX という 3 TByte のディスクが 6 本 SATA3 で接続されており、 2 本壊れてもデータが失われないようにします(うわぁ、ディスクだけで 6 万円超えてるとか)。このディスクは AFT という技術が使われていてセクタが 4096 Byte あるそうです。いつまでも 512 Byte では効率が悪いということでしょうね。このボリュームは /home に当てて、他で使うボリュームは部屋に転がっていた Hitachi の HDS72202 という 2 TByte のディスクを使います。
構築作業の手順ですが、zpool を作成するところをちょいちょい調べたので、やっていることについて補足していきます。

まずはこれ。 zpool コマンドで zpool という名前のボリュームを作ります。

# zpool create -f -o ashift=12 -o cachefile=/tmp/zpool.cache -O normalization=formD -m none -R /mnt/gentoo zpool /dev/sda

オプションはそれぞれこんな意図があります。 man zpool で得られる情報です。

No. Option Explanation
1 create 任意のデバイスを使ってボリュームを作ります
2 -f 強制的に vdev を使います。 vdev はディスクだったりファイルだったりデバイスです
3 -o ashift=12 セクタ長を 2 の乗数で指定します。 4096 なら 12、 512 なら 9 ですね。ディスクの構造に依存しません。大きければパフォーマンスが上がりますが、ディスクの使用量も場合によっては上がります
4 -o cachefile=/tmp/zpool.cache ZFS の構造を管理するファイルを指定します。起動時にこれを読みます
5 -O normalization=formD UNICODE で書かれたファイル名を比較するアルゴリズムの指定です。 UNICODE ってそんなもんなのですが、 formD は Mac と相性が良いとか。
6 -m none どこにも mount しません
7 -R /mnt/gentoo -o cachefile=none,altroot=path と同等のようです。 4 と矛盾しますね。 root として振る舞う path を記載します。 Gentoo のインストールで使う chroot の path を指定すると良いです
8 zpool ボリュームの名前です。お好みで
9 /dev/sda vdev の名前です

で、起動用のボリューム zroot にこんなコマンドを実行しました。

# zpool create -f -o ashift=12 -O normalization=formD -m / -R /mnt/gentoo zroot sda

/dev/sda は HDS72202 なので ashift=9 で良かったと思いますが、ぱ、パフォーマンス重視なのです。実はあまり考えてません。名前は zroot にしました。これは好みです。

ストレージ用のボリューム home はこんな感じです。

# zpool create -f -o ashift=12 -o cachefile= -O normalization=formD -m /home -R /mnt/gentoo home raidz2 sdb sdc sdd sde sdf sdg

zroot と異なるのは vdev に raidz2 とディスクをしているところです。raidz2 は RAID-5 の亜種で、"write hole" と呼ばれる電源が落ちたときの問題を解決してます。 raidz2 の 2 はパリティに 2 本ディスクを使うという意味なので、 2 本までのディスク障害に耐えられます。

ここまで来たら、他は固有の手順はそんなにないと思いました。あとは zfs コマンドでボリュームを作って mount したら例のメモに従えば OK です。きっと 3 年後くらいにまたハマるので今の自分に感謝するはず。