かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その21 )( Docker で RabbitMQ の環境を構築する )

概要

記事一覧はこちらです。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その20 )( Docker で Redis の環境を構築する3(Redis を 5.0.1 → 5.0.2 にバージョンアップする+.env の環境変数を使用するよう変更する)) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • RabbitMQ の環境を Windows バイナリ(rabbitmq-server-3.7.7.exe)をインストールして構築した環境から Docker の RabbitMQ による Cluster 環境へ変更します。
    • 今回は単体の RabbitMQ サーバ環境を構築し、次回 Cluster 環境を構築する予定です。
    • RabbitMQ は管理コンソールを使用したいので、末尾に -management が付いた 3.7.8-management を使用します。

参照したサイト・書籍

  1. rabbitmq
    https://hub.docker.com/_/rabbitmq/

  2. rabbitmq/3.7/debian/Dockerfile
    https://github.com/docker-library/rabbitmq/blob/1a8fd1c6ee027baafb7144c24ad3c995ba5e0d24/3.7/debian/Dockerfile

  3. rabbitmqctl(8)
    https://www.rabbitmq.com/rabbitmqctl.8.html

  4. RabbitMQ Monitoring
    https://grafana.com/dashboards/4279

  5. kbudde/rabbitmq_exporter
    https://github.com/kbudde/rabbitmq_exporter

  6. 【超ざっくりわかる】DebianUbuntuの違いを比較しました
    https://eng-entrance.com/linux-debian-ubuntu

  7. Alpine Linux で Docker イメージを劇的に小さくする
    https://qiita.com/asakaguchi/items/484ba262965ef3823f61

  8. alpine linuxベースのdocker imageに移行したはなし
    https://techblog.zozo.com/entry/docker_image_slim_in_alpinelinux

目次

  1. 単体の RabbitMQ サーバの環境を構築する
  2. ksbysample-webapp-lending から接続する
  3. RabbitMQ のメトリックスを Prometheus + Grafana で表示してみる
  4. docker-compose up -d コマンドでコンテナが起動しないことがあるので Docker の利用可能メモリを 2GB → 4GB に変更する+一部のコンテナを "-alpine" イメージに変更する
  5. メモ書き

手順

単体の RabbitMQ サーバの環境を構築する

.env に RabbitMQ のバージョン番号を記述します。

HOST_IP_ADDRESS=172.23.136.33
REDIS_VERSION=5.0.2
REDIS_CLUSTER_1_PORT=6379
REDIS_CLUSTER_2_PORT=6380
REDIS_CLUSTER_3_PORT=6381
REDIS_CLUSTER_4_PORT=6382
REDIS_CLUSTER_5_PORT=6383
REDIS_CLUSTER_6_PORT=6384

RABBITMQ_VERSION=3.7.8-management
  • RABBITMQ_VERSION=3.7.8-management を追加します。

docker-compose.yml に rabbitmq の設定を追加します。

  rabbitmq:
    image: rabbitmq:${RABBITMQ_VERSION}
    container_name: rabbitmq
    hostname: rabbitmq
    ports:
    - "5672:5672"
    - "15672:15672"
    environment:
    - RABBITMQ_DEFAULT_USER=rabbitmq
    - RABBITMQ_DEFAULT_PASS=12345678

docker-compose up -d コマンドを実行して起動します。

f:id:ksby:20181201160151p:plain

IntelliJ IDEA の Docker Plugin からログを見てみると以下のように出力されています。エラーは出ていません。

f:id:ksby:20181201160251p:plain f:id:ksby:20181201160346p:plain

管理コンソールにアクセスしてみます。http://localhost:15672/ にアクセスするとログイン画面が表示されますので、docker-compose.yml に RABBITMQ_DEFAULT_USER, RABBITMQ_DEFAULT_PASS で設定した rabbitmq / 12345678 でログインします。

f:id:ksby:20181201160702p:plain f:id:ksby:20181201160740p:plain

無事ログインできました。問題はなさそうです。

ksbysample-webapp-lending から接続する

src/main/resources/application-develop.properties の以下の点を変更します。

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=rabbitmq
spring.rabbitmq.password=12345678
  • 以下の2行を追加します。docker-compose.yml に RABBITMQ_DEFAULT_USER, RABBITMQ_DEFAULT_PASS で guest / guest 以外のユーザID、パスワードを設定したので、application-develop.properties にも同じユーザID、パスワードを設定します。
    • spring.rabbitmq.username=rabbitmq
    • spring.rabbitmq.password=12345678

Tomcat を起動します。Spring Actuator の health check を見ると rabbitmq が認識されています。

f:id:ksby:20181201162154p:plain

ブラウザから http://localhost:8080/ にアクセスして「貸出希望書籍 CSV ファイルアップロード」から貸出希望書籍を登録すると(ここで RabbitMQ にメッセージが送信されます)、

f:id:ksby:20181201162337p:plain

定期タスクが RabbitMQ からメッセージを受信して処理されて、結果のメールが返ってきました。

f:id:ksby:20181201162414p:plain

RabbitMQ の管理コンソールを見るとメッセージが配信されたことが確認できます。

f:id:ksby:20181201162547p:plain

rabbitmqctl コマンドでユーザ一覧を出力してみます。docker exec -it rabbitmq rabbitmqctl list_users コマンドを実行すると、デフォルトで登録している rabbitmq ユーザが出力されました。

f:id:ksby:20181201164125p:plain

RabbitMQ のメトリックスを Prometheus + Grafana で表示してみる

RabbitMQ のメトリックスを Grafana で表示させる Dashboard があるのか調べてみたところ RabbitMQ Monitoring を見つけました。これを利用して表示させてみます。

RabbitMQ → Prometheus への exporter は kbudde/rabbitmq_exporter を Docker で起動して利用します。docker-compose.yml に rabbitmq_exporter の設定を追加します。

  rabbitmq_exporter:
    image: kbudde/rabbitmq-exporter:latest
    container_name: rabbitmq_exporter
    ports:
    - "9419:9419"
    environment:
    - RABBIT_URL=http://${HOST_IP_ADDRESS}:15672
    - RABBIT_USER=rabbitmq
    - RABBIT_PASSWORD=12345678
    - RABBIT_CAPABILITIES=bert,no_sort
    - PUBLISH_PORT=9419

docker/prometheus/prometheus.yml に rabbitmq_exporter からメトリックスを収集する設定を追加します。

- job_name: 'rabbitmq_exporter'
  static_configs:
  - targets: ['172.23.136.33:9419']

docker-compose downdocker-compose up -d コマンドを実行します。

f:id:ksby:20181202002038p:plain

Grafana に RabbitMQ MonitoringDashboard を追加します。http://localhost:3000/ にアクセスした後、画面左側のメニューから「Create」-「Import」を選択します。

f:id:ksby:20181202002312p:plain

「Import」画面が表示されますので 4279 の ID を入力します。

f:id:ksby:20181202002444p:plain

「Prometheus」で「spring-actuator」を選択した後、「Import」ボタンをクリックします。

f:id:ksby:20181202002657p:plain

RabbitMQ MonitoringDashboard が表示されます(画面右上の表示間隔の設定を Last 3 hours Refresh every 5s → Last 15 minutes Refresh every 5s に変更しています)。

f:id:ksby:20181202002845p:plain f:id:ksby:20181202002943p:plain

docker-compose up -d コマンドでコンテナが起動しないことがあるので Docker の利用可能メモリを 2GB → 4GB に変更する+一部のコンテナを "-alpine" イメージに変更する

docker-compose.yml に Redis、RabbitMQ の設定を追加してから docker-compose downdocker-compose up -d コマンドを何度も実行すると、docker-compose up -d コマンドでエラーメッセージが出ないにもかかわらず実際には Redis Cluster が構築できなかったり、RabbitMQ が起動していなかったりしたことがありました。

docker images コマンドで Docker Image の一覧を表示させてサイズを確認すると、

f:id:ksby:20181202014251p:plain

  • redis:5.0.2-custom (197MB x 7 = 1379MB)
  • rabbitmq:3.7.8-management (149MB)
  • grafana/grafana:latest (236MB)
  • prom/prometheus:latest (97.7MB)

で合計が 1861.7MB もあり、Docker Engine にデフォルトで設定されている利用可能メモリのサイズ(2048MB)ぎりぎりでした。

Docker Engine が利用可能なメモリを 2048MB → 4096MB へ、Swap を 1024MB → 2048MB へ変更します。

f:id:ksby:20181202013548p:plain

また Redis のコンテナは全てを redis:5.0.2-custom にする必要はないので、redis-cluster-1~redis-cluster-6 コンテナは redis:${REDIS_VERSION}-customredis:${REDIS_VERSION}-alpine に変更し、redis-cluster-make コンテナだけ redis:${REDIS_VERSION}-custom を使用するように変更します。redis-cluster-1~redis-cluster-6 コンテナには volumes: - ./docker/redis/redis.conf:/etc/redis/redis.conf も追加します。rabbitmq コンテナも rabbitmq:${RABBITMQ_VERSION}rabbitmq:${RABBITMQ_VERSION}-alpine に変更します。

  # 起動したコンテナに /bin/sh でアクセスする場合には以下のコマンドを実行する
  # docker exec -it redis /bin/sh
  #
  # 起動したコンテナの redis に redis-cli でアクセスするには以下のコマンドを実行する
  # docker exec -it redis redis-cli
  #
  #############################################################################
  # 単体 Redis サーバ
  # redis:
  #   image: redis:${REDIS_VERSION}
  #   container_name: redis
  #   ports:
  #   - "6379:6379"
  #
  #############################################################################
  # Redis Cluster
  redis-cluster-1:
    image: redis:${REDIS_VERSION}-alpine
    container_name: redis-cluster-${REDIS_CLUSTER_1_PORT}
    ports:
    - "${REDIS_CLUSTER_1_PORT}:6379"
    - "1${REDIS_CLUSTER_1_PORT}:16379"
    volumes:
    - ./docker/redis/redis.conf:/etc/redis/redis.conf
    command:
    - /bin/sh
    - -c
    - |
      redis-server /etc/redis/redis.conf \
                  --cluster-announce-ip ${HOST_IP_ADDRESS} \
                  --cluster-announce-port ${REDIS_CLUSTER_1_PORT} \
                  --cluster-announce-bus-port 1${REDIS_CLUSTER_1_PORT}
  redis-cluster-2:
    image: redis:${REDIS_VERSION}-alpine
    container_name: redis-cluster-${REDIS_CLUSTER_2_PORT}
    ports:
    - "${REDIS_CLUSTER_2_PORT}:6379"
    - "1${REDIS_CLUSTER_2_PORT}:16379"
    volumes:
    - ./docker/redis/redis.conf:/etc/redis/redis.conf
    command:
    - /bin/sh
    - -c
    - |
      redis-server /etc/redis/redis.conf \
                  --cluster-announce-ip ${HOST_IP_ADDRESS} \
                  --cluster-announce-port ${REDIS_CLUSTER_2_PORT} \
                  --cluster-announce-bus-port 1${REDIS_CLUSTER_2_PORT}
    depends_on:
    - redis-cluster-1
  redis-cluster-3:
    image: redis:${REDIS_VERSION}-alpine
    container_name: redis-cluster-${REDIS_CLUSTER_3_PORT}
    ports:
    - "${REDIS_CLUSTER_3_PORT}:6379"
    - "1${REDIS_CLUSTER_3_PORT}:16379"
    volumes:
    - ./docker/redis/redis.conf:/etc/redis/redis.conf
    command:
    - /bin/sh
    - -c
    - |
      redis-server /etc/redis/redis.conf \
                  --cluster-announce-ip ${HOST_IP_ADDRESS} \
                  --cluster-announce-port ${REDIS_CLUSTER_3_PORT} \
                  --cluster-announce-bus-port 1${REDIS_CLUSTER_3_PORT}
    depends_on:
    - redis-cluster-1
  redis-cluster-4:
    image: redis:${REDIS_VERSION}-alpine
    container_name: redis-cluster-${REDIS_CLUSTER_4_PORT}
    volumes:
    - ./docker/redis/redis.conf:/etc/redis/redis.conf
    ports:
    - "${REDIS_CLUSTER_4_PORT}:6379"
    - "1${REDIS_CLUSTER_4_PORT}:16379"
    command:
    - /bin/sh
    - -c
    - |
      redis-server /etc/redis/redis.conf \
                  --cluster-announce-ip ${HOST_IP_ADDRESS} \
                  --cluster-announce-port ${REDIS_CLUSTER_4_PORT} \
                  --cluster-announce-bus-port 1${REDIS_CLUSTER_4_PORT}
    depends_on:
    - redis-cluster-1
  redis-cluster-5:
    image: redis:${REDIS_VERSION}-alpine
    container_name: redis-cluster-${REDIS_CLUSTER_5_PORT}
    volumes:
    - ./docker/redis/redis.conf:/etc/redis/redis.conf
    ports:
    - "${REDIS_CLUSTER_5_PORT}:6379"
    - "1${REDIS_CLUSTER_5_PORT}:16379"
    command:
    - /bin/sh
    - -c
    - |
      redis-server /etc/redis/redis.conf \
                  --cluster-announce-ip ${HOST_IP_ADDRESS} \
                  --cluster-announce-port ${REDIS_CLUSTER_5_PORT} \
                  --cluster-announce-bus-port 1${REDIS_CLUSTER_5_PORT}
    depends_on:
    - redis-cluster-1
  redis-cluster-6:
    image: redis:${REDIS_VERSION}-alpine
    container_name: redis-cluster-${REDIS_CLUSTER_6_PORT}
    volumes:
    - ./docker/redis/redis.conf:/etc/redis/redis.conf
    ports:
    - "${REDIS_CLUSTER_6_PORT}:6379"
    - "1${REDIS_CLUSTER_6_PORT}:16379"
    command:
    - /bin/sh
    - -c
    - |
      redis-server /etc/redis/redis.conf \
                  --cluster-announce-ip ${HOST_IP_ADDRESS} \
                  --cluster-announce-port ${REDIS_CLUSTER_6_PORT} \
                  --cluster-announce-bus-port 1${REDIS_CLUSTER_6_PORT}
    depends_on:
    - redis-cluster-1
  redis-cluster-make:
    build:
      context: ./docker/redis
      args:
      - REDIS_VERSION=${REDIS_VERSION}
    image: redis:${REDIS_VERSION}-custom
    container_name: redis-cluster-make
    command:
    - /bin/sh
    - -c
    - |
      expect -c "
      spawn redis-cli --cluster create \
                        ${HOST_IP_ADDRESS}:${REDIS_CLUSTER_1_PORT} \
                        ${HOST_IP_ADDRESS}:${REDIS_CLUSTER_2_PORT} \
                        ${HOST_IP_ADDRESS}:${REDIS_CLUSTER_3_PORT} \
                        ${HOST_IP_ADDRESS}:${REDIS_CLUSTER_4_PORT} \
                        ${HOST_IP_ADDRESS}:${REDIS_CLUSTER_5_PORT} \
                        ${HOST_IP_ADDRESS}:${REDIS_CLUSTER_6_PORT} \
                      --cluster-replicas 1
      expect \"Can I set the above configuration? (type 'yes' to accept): \"
      send \"yes\n\"
      expect eof
      "
    depends_on:
    - redis-cluster-1
    - redis-cluster-2
    - redis-cluster-3
    - redis-cluster-4
    - redis-cluster-5
    - redis-cluster-6

  redis_exporter:
    image: oliver006/redis_exporter:latest
    container_name: redis_exporter
    ports:
    - "9121:9121"
    environment:
    - REDIS_ADDR=redis://${HOST_IP_ADDRESS}:${REDIS_CLUSTER_1_PORT},redis://${HOST_IP_ADDRESS}:${REDIS_CLUSTER_2_PORT},redis://${HOST_IP_ADDRESS}:${REDIS_CLUSTER_3_PORT},redis://${HOST_IP_ADDRESS}:${REDIS_CLUSTER_4_PORT},redis://${HOST_IP_ADDRESS}:${REDIS_CLUSTER_5_PORT},redis://${HOST_IP_ADDRESS}:${REDIS_CLUSTER_6_PORT}

  # 起動したコンテナに /bin/sh でアクセスする場合には以下のコマンドを実行する
  # docker exec -it rabbitmq /bin/sh
  #
  # 起動したコンテナの rabbitmq に rabbitmqctl で接続して管理コマンドを実行するには以下のコマンドを実行する
  # docker exec -it rabbitmq rabbitmqctl ...
  rabbitmq:
    image: rabbitmq:${RABBITMQ_VERSION}-alpine
    container_name: rabbitmq
    hostname: rabbitmq
    ports:
    - "5672:5672"
    - "15672:15672"
    environment:
    - RABBITMQ_DEFAULT_USER=rabbitmq
    - RABBITMQ_DEFAULT_PASS=12345678

  rabbitmq_exporter:
    image: kbudde/rabbitmq-exporter:latest
    container_name: rabbitmq_exporter
    ports:
    - "9419:9419"
    environment:
    - RABBIT_URL=http://${HOST_IP_ADDRESS}:15672
    - RABBIT_USER=rabbitmq
    - RABBIT_PASSWORD=12345678
    - RABBIT_CAPABILITIES=bert,no_sort
    - PUBLISH_PORT=9419

docker/redis/Dockerfile は ADD redis.conf /etc/redis/ を削除します。

ARG REDIS_VERSION
FROM redis:${REDIS_VERSION}
RUN apt-get update -qq && apt-get install -y expect

redis:5.0.2-custom の Docker Image を削除してから docker-compose up -d コマンドを実行します。

f:id:ksby:20181202024148p:plain (.....途中は長いので省略.....) f:id:ksby:20181202024321p:plain

IntelliJ IDEA の Docker Plugin で見ると、コンテナは全て起動しており、Redis Cluster の構築も成功していました。

f:id:ksby:20181202024806p:plain

Grafana の Dashboard も正常に表示されて、Tomcat を起動して Web アプリケーションを実行しても特に問題はありませんでした(画面キャプチャは省略)。

再度 docker images コマンドで Docker Image の一覧を表示させてサイズを確認すると、

f:id:ksby:20181202025317p:plain

  • redis:5.0.2-custom (197MB)
  • redis:5.0.2-alpine (40.9MB x 6 = 245.4MB)
  • rabbitmq:3.7.8-management-alpine (82.8MB)
  • grafana/grafana:latest (236MB)
  • prom/prometheus:latest (97.7MB)

で合計が 858.9MB まで下がりました。

メモ書き

今回は記事を書いている途中に書いたり、最後に書いたりしたメモ書きです。

  • redis/5.0/Dockerfilerabbitmq/3.7/debian/Dockerfile もベースの OS には debian:stretch-slim を使用していました。 OFFICIAL REPOSITORY だと debian が多いのでしょうか? 1. 【超ざっくりわかる】DebianとUbuntuの違いを比較しました の記事を読んだ限りでは、堅実で下記の alpine 程ではないが少ないメモリで動くらしい。
  • それとは別に -alpine という Docker Image もありました。Alpine Linux を使用していて、軽量で docker pull、docker build コマンド等が超高速になるらしい。。。というか Docker for Windows でコンテナを多数起動する時には Docker Image のサイズが小さくなる alpine 版が用意されているのはありがたいということが分かりました。
  • Redis も RabbitMQ も管理で使うポート番号に +10000 するのは何かよく使われるルールなのでしょうか?
  • Spring Actuator の Health Check がここにきてすごい便利に感じています。Web アプリケーションから Redis や RabbitMQ がきちんと認識できているのかを簡単に確認できます! DBサーバとしか接続しない場合にはそんなに気にしないのかもしれませんが、いろいろなサーバに接続するようになるとその便利さが実感できます。

履歴

2018/12/02
初版発行。