Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その34 )( Docker で複数の Tomcat を起動して動作確認する )
概要
記事一覧はこちらです。
Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その33 )( PC の IP アドレスが変更された時に修正するファイルを最小限にする ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
参照したサイト・書籍
Spring Boot with Docker
https://spring.io/guides/gs/spring-boot-docker/Networking in Compose
https://docs.docker.com/compose/networking/docker-compose creating multiple instances for the same image
https://stackoverflow.com/questions/39663096/docker-compose-creating-multiple-instances-for-the-same-imageCompose file versions and upgrading
https://docs.docker.com/compose/compose-file/compose-versioning/Get Started, Part 3: Services
https://docs.docker.com/get-started/part3/COPY failed: stat /var/lib/docker/tmp/docker-builder918577595/...
https://github.com/moby/moby/issues/34986Web Server Load-Balancing with HAProxy on Ubuntu 14.04
https://www.howtoforge.com/tutorial/ubuntu-load-balancer-haproxy/How to Enable HAProxy Stats
https://tecadmin.net/how-to-configure-haproxy-statics/多機能なロードバランサとして使える多機能プロクシサーバー「HAProxy」入門
https://knowledge.sakura.ad.jp/8078/Using SSL Certificates with HAProxy
https://serversforhackers.com/c/using-ssl-certificates-with-haproxy- 今回の記事では設定していませんが、HAProxy で http, https の両方を受け付けられるようにする記事を見つけたのでメモ書きとして残しておきます。
How can I set the timezone please?
https://github.com/gliderlabs/docker-alpine/issues/136How to set locale in Docker Alpine?
https://stackoverflow.com/questions/49042223/how-to-set-locale-in-docker-alpinegitattributes
https://git-scm.com/docs/gitattributes
目次
- 方針
- docker-compose.app.yml を作成する
- HAProxy の設定ファイル haproxy.cfg を作成する
- logback-spring.xml を変更し、spring.profiles.active = product の時にログをコンソールに出力できるようにする
- jar ファイル起動用コンテナを生成するための Dockerfile を作成する
- 動作確認
- *.sh をチェックアウトした時に必ず改行コードが LF になるよう .gitattributes を作成する
手順
方針
- docker-compose.yml とは別に docker-compose.app.yml というファイル作成し、
docker-compose up -d
コマンドを実行した後にdocker-compose -f docker-compose.app.yml up -d
コマンドで起動します。 - docker-compose.app.yml で jar ファイルからの Tomcat 3インスタンスと HAProxy を起動します。HAProxy の 8080番ポートにアクセスすると Tomcat の3インスタンスのどれかにリクエストが振り分けられます。
- jar ファイルから起動する時の Profile は既存の product を使用します。また、Docker で起動する時に product の設定から変更するものは docker-compose.app.yml に環境変数(environment)として設定します。
- product で起動する時はログファイルに出力するように設定していますが、Docker で起動する時にはコンソールに出力されるようにします。
docker-compose.app.yml を作成する
docker-compose.app.yml を新規作成し、以下の内容を記述します。
# docker-compose -f docker-compose.app.yml --compatibility up -d # docker-compose -f docker-compose.app.yml --compatibility down version: '3' services: app: build: context: . dockerfile: docker/app/Dockerfile image: ksbysample-webapp-lending volumes: - ./build/libs/ksbysample-webapp-lending-2.0.8-RELEASE.jar:/app.jar - ./docker/app/docker-entrypoint.sh:/usr/local/bin/docker-entrypoint.sh environment: - SPRING_DATASOURCE_HIKARI_JDBC_URL=jdbc:postgresql://postgresql/ksbylending - SPRING_MAIL_HOST=mail-server - SPRING_RABBITMQ_HOST=haproxy deploy: mode: replicated replicas: 3 # entrypoint: /bin/sh # stdin_open: true # tty: true haproxy-app: image: haproxy:1.8.14-alpine container_name: haproxy-app volumes: - ./docker/app/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro ports: - "8080:8080" depends_on: - app haproxy-app-rsyslog: image: rafpe/docker-haproxy-rsyslog container_name: haproxy-app-rsyslog volumes: - ./docker/app/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro depends_on: - haproxy-app networks: default: external: name: ksbysample-webapp-lending_default
- app、haproxy-app、haproxy-app-rsyslog の3つのコンテナの設定を記述します。
- コンテナから接続する docker network は
docker-compose up -d
コマンド実行時に自動生成されるksbysample-webapp-lending_default
にします。docker-compose.app.yml の最後にnetworks: ksbysample-webapp-lending_default: external: name: ksbysample-webapp-lending_default
の設定を記述します。 - app コンテナの設定のポイントは以下の通りです。
- jar ファイルを Docker コンテナにコピーすることも考慮して(今回はコピーしませんが)、build の下の context の設定を
.
にし、Dockerfile のパスを dockerfile に記述します。 - jar ファイルはコンテナ内にコピーせず、
/app.jar
にマウントされるよう volumes に記述します。build し直した時にコンテナを生成し直さなくてもよいようにします。 - 以下の設定はサーバをコンテナ名に変更したものを environment に記述します。
- SPRING_DATASOURCE_HIKARI_JDBC_URL
- SPRING_MAIL_HOST
- SPRING_RABBITMQ_HOST
- deploy の設定を記述し、
docker-compose up -d
コマンドでコンテナを生成した時に app コンテナのインスタンスを自動で複数起動されるようにします。また deploy の設定は本来 docker swarm 用の設定ですが、--compatibility
オプションを追加すればdocker-compose up -d
コマンドでも使用できるようになります。
- jar ファイルを Docker コンテナにコピーすることも考慮して(今回はコピーしませんが)、build の下の context の設定を
HAProxy の設定ファイル haproxy.cfg を作成する
docker の下に app ディレクトリを新規作成した後、docker/app/haproxy.cfg を新規作成して以下の内容を記述します。
global log 127.0.0.1 local1 maxconn 4096 defaults log global mode http option httplog option dontlognull retries 3 option redispatch maxconn 2000 timeout connect 5000 timeout client 50000 timeout server 50000 listen app bind *:8080 stats enable stats hide-version stats realm Haproxy\ Statistics stats refresh 5s stats uri /haproxy?stats balance roundrobin option httpclose option forwardfor server ksbysample-webapp-lending_app_1 ksbysample-webapp-lending_app_1:8080 check inter 5s rise 2 fall 3 server ksbysample-webapp-lending_app_2 ksbysample-webapp-lending_app_2:8080 check inter 5s rise 2 fall 3 server ksbysample-webapp-lending_app_3 ksbysample-webapp-lending_app_3:8080 check inter 5s rise 2 fall 3
docker-compose -f docker-compose.app.yml --compatibility up -d
で複数起動させた app コンテナのコンテナ名は<プロジェクト名(ksbysample-webapp-lending)>_<コンテナ名(app)>_<連番(1~)>
になるので、ksbysample-webapp-lending_app_1、ksbysample-webapp-lending_app_2、ksbysample-webapp-lending_app_3 の3サーバにリクエストを振り分けるように設定します。
logback-spring.xml を変更し、spring.profiles.active = product の時にログをコンソールに出力できるようにする
<?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/defaults.xml"/> <include resource="org/springframework/boot/logging/logback/console-appender.xml"/> <property name="LOGGING_APPENDER" value="${logging.appender:-FILE}"/> <if condition='"${spring.profiles.active}" == "product" && "${LOGGING_APPENDER}" == "FILE"'> <then> <property name="LOG_FILE" value="${LOG_FILE}"/> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <file>${LOG_FILE}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> </appender> </then> </if> <if condition='"${spring.profiles.active}" == "develop"'> <then> <root> <appender-ref ref="CONSOLE"/> </root> </then> </if> <if condition='"${spring.profiles.active}" == "product"'> <then> <root> <appender-ref ref="${LOGGING_APPENDER}"/> </root> </then> </if> </configuration>
<property name="LOGGING_APPENDER" value="${logging.appender:-FILE}"/>
を追加します。<appender name="FILE" ...
を定義している部分の<if condition='"${spring.profiles.active}" == "product"'>
→<if condition='"${spring.profiles.active}" == "product" && "${LOGGING_APPENDER}" == "FILE"'>
に変更します。<if condition='"${spring.profiles.active}" == "product"'> ... </if>
の中に記述している<appender-ref ref="FILE"/>
→<appender-ref ref="${LOGGING_APPENDER}"/>
に変更します。
これで jar ファイル起動時に java の起動時オプションに -Dlogging.appender=CONSOLE
を指定すれば Profile が product でも CONSOLE に出力されるようになります。
jar ファイル起動用コンテナを生成するための Dockerfile を作成する
docker/app/docker-entrypoint.sh を新規作成し、以下の内容を記述します。
#!/bin/sh # 改行コードを LF にすること。LF でないと実行されない。 export JAVA_OPTS="-Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=384m" exec java $JAVA_OPTS \ -Djava.security.egd=file:/dev/./urandom \ -Dspring.profiles.active=product \ -Dlogging.appender=CONSOLE \ -jar /app.jar
docker/app/Dockerfile を新規作成し、以下の内容を記述します。
FROM openjdk:8-jdk-alpine RUN apk add --no-cache tzdata ENV TZ="Asia/Tokyo" ENV LANG="ja_JP.UTF-8" VOLUME /tmp EXPOSE 8080 ENTRYPOINT ["docker-entrypoint.sh"]
- Spring Boot with Docker の「Containerize It」に記載されている Dockerfile から以下の点を変更しました。
- 以下の2行を削除します。
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
- jar ファイルから出力されるログの日時を日本時間にしたいので、以下の2行を追加します。
RUN apk add --no-cache tzdata
ENV TZ="Asia/Tokyo"
- openjdk:8-jdk-alpine イメージのデフォルトの環境変数 LANG の値は C.UTF-8 なので、
ENV LANG="ja_JP.UTF-8"
を追加します。 - 8080番ポートを公開するので
EXPOSE 8080
を追加します。 - ENTRYPOINT には
"docker-entrypoint.sh"
だけ記述します。
- 以下の2行を削除します。
動作確認
docker-compose up -d
コマンドを実行した後、build タスクを実行して jar ファイルを作成します。
docker-compose -f docker-compose.app.yml --compatibility up -d
コマンドを実行します。
http://localhost:8080/haproxy?stats にアクセスして全てのインスタンスが緑色になるまで待ちます。
IntelliJ IDEA の Docker Plugin を見ると ksbysample-webapp-lending_app_1、ksbysample-webapp-lending_app_2、ksbysample-webapp-lending_app_3 の3つのコンテナが起動しており、ログがファイルではなくコンソールに出力されていることが確認できます。TimeZone を設定しているので、ログの日時が日本時間になっていることも確認できます。
以下の手順で動作確認します ( 画面キャプチャは省略します )。
- ブラウザを起動して http://localhost:8080/ にアクセスしてログイン画面を表示します。tanaka.taro@sample.com / taro でログインします。
- 検索対象図書館登録画面が表示されます。"東京都" で検索した後、一覧表示されている図書館から「国立国会図書館東京本館」を選択します。
- ログアウトします。
- ログイン画面に戻るので suzuki.hanako@test.co.jp / hanako でログインします。
- 貸出希望書籍 CSV ファイルアップロード画面が表示されます。以下の内容が記述された CSV ファイルをアップロードします。
"ISBN","書名"
"978-4-7741-6366-6","GitHub実践入門"
"978-4-7741-5377-3","JUnit実践入門"
"978-4-7973-8014-9","Java最強リファレンス"
"978-4-7973-4778-4","アジャイルソフトウェア開発の奥義"
"978-4-87311-704-1","Javaによる関数型プログラミング" - 「貸出状況を確認しました」のメールが送信されるので、メールに記述されている URL にアクセスします。
- 貸出申請画面が表示されます。3冊程「申請する」を選択して申請します。
- ログアウトします。
- 「貸出申請がありました」のメールが送信されるので、メールに記述されている URL にアクセスします。ログイン画面が表示されるので、tanaka.taro@sample.com / taro でログインします。
- 貸出承認画面が表示されます。「承認」あるいは「却下」を選択して確定させます。
- ログアウトします。
- 「貸出申請が承認・却下されました」のメールが送信されるので、メールに記述されている URL にアクセスします。ログイン画面が表示されるので、suzuki.hanako@test.co.jp / hanako でログインします。
- 貸出申請結果確認画面が表示されるので内容を確認します。
動作確認は特に問題ありませんでした。
HAProxy の stats page を見るとセッション数も In と Out のバイト数もほぼ均等になっており、リクエストが各 Tomcat に転送されていることが分かります。
またセッション情報が Spring Session により Redis に格納されているのでログイン後にどの Tomcat にアクセスしてもログイン状態が維持されていますが、ログインした後、
Redis の master に保存されているデータを全てクリアしてから、
メニューから「貸出希望書籍登録」を選択すると、セッション情報が削除されてログイン状態ではないのでログイン画面が表示されます。
最後に docker-compose -f docker-compose.app.yml --compatibility down
コマンドでコンテナを終了します。
これで簡単に Tomcat のマルチインスタンスでの動作確認が出来るようになりました。
*.sh をチェックアウトした時に必ず改行コードが LF になるよう .gitattributes を作成する
今回作成した docker/app/docker-entrypoint.sh は改行コードが LF でないと動作しないのですが、現在の git の設定ではチェックアウト時に改行コードを自動で CRLF になるように設定しているので(.gitconfig に autocrlf = true が設定されています)チェックアウトし直した時に改行コードが CRLF に変換されてしまいます。
*.sh だけ LF のまま維持する方法がないか調べたところ、https://git-scm.com/docs/gitattributes のページを見つけました。.gitattributes を作成して設定すれば維持できるようです。
.gitattributes を新規作成し、以下の内容を記述します。
* text=auto *.sh text eol=lf
実際に別のディレクトリに git clone してみたところ、docker/app/docker-entrypoint.sh の改行コードが LF になっていました。
履歴
2019/01/20
初版発行。