intra-martが起動するDockerコンテナを作成する。alpineで。


概要

intra-martが起動するDockerコンテナを作成する にinspire the nextされ、ムシャクシャしてやってみた。

intra-mart の環境をDockerコンテナ上に構築します。

軽量と噂のalpineで。ubuntuならapt-getでresinが入るご時世なのにね。

今回目指すイメージは以下のような感じです。
- 「/imart/login」で、作成したテナント管理者でログインできるところまでを確認します。
- imart.warは、外から渡せるようにします。
- データベースは別に立てたコンテナのものを利用します。
- Webサーバ(Apacheとか)は用意しません。
- IMBoxとIM-ContentSearchは入れないものとします。(CassandraやSolrが必要なため)

試した各アプリケーションのバージョンです。

application version 説明
Resin Pro 4.0.48 本家が配布しているものを利用します。
OpenJDK 1.8.0_92 apkでインストールされるものを利用します。
intra-mart 8.0.13(Maxima) 2016 Springを利用します。
PostgreSQL 9.5.3 DockerHubで配布されているlatestを利用します。

注1 システム要件を100%満たしていないが、そこは不問とする。割り切った関係が大事です。

注2 本家のresin-proにはlicenseが含まれていないため、自分でlicenseを入れる必要があります。入れなくても30日ぐらいは動くらしい

注3 Oracleじゃなきゃダメなintra-mart上で動くアプリケーションは、見なかったことにする。

事前に用意しておくもの

  • imart.war
  • postgresのjdbcドライバ (postgresql-9.4.1208.jar)

intra-mart Accel シリーズ TRY版 ダウンロードからIM-Jugglingツールをダウンロードして、
warファイルを作成します。

手順の詳細は、インスパイア元に記載があるので、そちらを参照されたい。

resin-web.xmlについて

preparedStatementCacheQueriesの値を0とか8とか小さい値にしていないと、テナントのセットアップ時にエラーが出て泣けることになります。

本家のマニュアルでは、20を指定している例が提示されているけど、これだとエラーになった。

参考 intra-martのテナント環境セットアップ時にjava.sql.SQLExceptionが発生したときの対策


<database jndi-name="jdbc/default">
        <driver>
            <type>org.postgresql.Driver</type>
            <url>jdbc:postgresql://postgres:5432/iap_db</url>
            <user>imart</user>
            <password>imart</password>
            <init-param>
                <param-name>preparedStatementCacheQueries</param-name>
                <param-value>8</param-value>
            </init-param>
        </driver>
        <max-connections>20</max-connections>
        <prepared-statement-cache-size>8</prepared-statement-cache-size>
    </database>

Dockerビルド用のファイルを作成

Dockerfile

以下のようなDockerfileを書きました。
javaさえあればいいんだろ、という甘い考えは、resinのmakeの段階で打ち砕かれます。
また、jni.hもmake時に必要です。なので、resinのmake後に、必要でなくなったタイミングでapk delで消します。(ダイエットのため)

alpineのサイトで、必要とされるファイル、それが含まれるパッケージを探します。


FROM alpine:3.4

ENV RESIN_VERSION 4.0.48
ENV RESIN_HOME /opt/resin-pro-${RESIN_VERSION}
ENV JAVA_HOME /usr/lib/jvm/java-1.8-openjdk

RUN apk add --virtual=build-dependencies --no-cache g++ libstdc++ linux-headers make wget ca-certificates && \
    apk add --no-cache openjdk8 && \
    ALPINE_GLIBC_BASE_URL="https://github.com/sgerrand/alpine-pkg-glibc/releases/download" && \
    ALPINE_GLIBC_PACKAGE_VERSION="2.23-r3" && \
    ALPINE_GLIBC_BASE_PACKAGE_FILENAME="glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    ALPINE_GLIBC_BIN_PACKAGE_FILENAME="glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    ALPINE_GLIBC_I18N_PACKAGE_FILENAME="glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    wget \
        "https://raw.githubusercontent.com/andyshinn/alpine-pkg-glibc/master/sgerrand.rsa.pub" \
        -O "/etc/apk/keys/sgerrand.rsa.pub" && \
    wget \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \
    apk add --no-cache \
        "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \
    \
    rm "/etc/apk/keys/sgerrand.rsa.pub" && \
    /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 C.UTF-8 || true && \
    echo "export LANG=C.UTF-8" > /etc/profile.d/locale.sh && \
    \
    apk del glibc-i18n && \
    \
    rm "/root/.wget-hsts" && \
    rm \
        "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME"

ENV LANG=C.UTF-8

RUN wget http://caucho.com/download/resin-pro-${RESIN_VERSION}.tar.gz -P /usr/local && \
    cd /usr/local && \
    tar xvzf resin-pro-${RESIN_VERSION}.tar.gz && \
    rm -f resin-pro-${RESIN_VERSION}.tar.gz && \
    cd resin-pro-${RESIN_VERSION} && \
    ./configure --prefix=/opt/resin-pro-${RESIN_VERSION} --enable-64bit && \
    make && \
    make install && \
    rm -rf /usr/local/resin-pro-4.0.48 && \
    ln -s /opt/resin-pro-${RESIN_VERSION} /opt/resin && \
    apk del build-dependencies 


EXPOSE 8080

ENTRYPOINT ["/opt/resin/bin/resinctl"," -server", "app-0", " start-with-foreground"]


本当はresin.propertiesなどを適切に編集する必要があるけど、動作確認レベルではなくても何とかなります。
割り切って先に進むことにします。

Dockerイメージのビルド

Dockerビルドを実行しイメージを作成します。

docker build -t imart-base:4.0.48 .

PostgreSQLの準備

イメージの取得&起動

docker run --name postgres -d -e PGPASSWORD=postgres -e POSTGRES_USER=postgres -p 5432:5432 postgres:latest

現時点でのlatestは9.5.3とのこと。

intra-martが接続するロールの作成

データベースとログインロールの作成を参照して、ロールを作ります。

今回はPostgreSQLもコンテナなので、こんな感じでやってみました。

まず、コンテナに接続。

docker exec -it postgres bash

PostgreSQLにつないで。

psql -U postgres

ロールとデータベースを作る。

postgres=# CREATE ROLE imart WITH LOGIN PASSWORD 'imart';
CREATE ROLE

postgres=# CREATE DATABASE iap_db OWNER imart ENCODING 'utf8';   
CREATE DATABASE

resinのコンテナを起動する

まず、事前に用意したファイルが以下のようにあると仮定します。

  • /home/intramart/war/*.war (IM-Jugglingで作成したwarファイル)
  • /home/intramart/lib/*.jar (JDBCドライバ)

これをdocker runするときにマウントして渡すことにします。

先に立てたPostgreSQLは--linkで渡しておきます。

docker run -it -d --name intra -p 8080:8080 --link postgres:postgres -v /home/intramart/war/:/opt/resin/webapps -v /home/intramart/lib/:/opt/resin/webapp-jars imart-base:4.0.48

しばらくすると、warファイルの展開がなされ、resinが起動します。

テナントセットアップとログインの確認

以下にアクセスすると、初期設定画面が出てきます。ウィザードに従って進みます。

http://<Dockerのホスト>:8080/imart/system/login

この後、システム管理者でログインすると、以下のような画面になります。

以下にアクセスし、テナント管理者でもログインできることを確認します。

http://<Dockerのホスト>:8080/imart/login

おまけ

Resinの入ったコンテナのイメージサイズ

場所 サイズ
Ubuntu(ビルドしている環境) 337.3MB
Gitlab Registry 123 MB

DockerのホストはUbuntu 16。 もう少し削れるかもしれない。