Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

【バックアップ】midPointで構築する「冗長構成」実践編

Last updated at Posted at 2019-12-05

はじめに

 システム要求の度合により手厚さは変わりますが、どんなシステムも実運用をする上で、一定の可用性の確保は必要不可欠です。ここでは「3日目 midPointで構築するシステムの構成例」でご紹介した冗長構成を実践していきます。
 また、今回はDockerを利用した環境構築を行っていきます。Docker実行環境があれば簡単に動かすことができますので、動くものベースに理解を深めていただければと思います。

:information_source: GitHubで公開しています
本稿で紹介するDocker ビルドファイルは、以下のGitHubで公開しています。ぜひこちらも合わせてご参照ください。
https://github.com/naokiiiii/midpoint-dockerfiles

冗長構成の概要

 今回構築する冗長構成は、以下の図のようになります。
 この構成により、midPointサーバーの処理が負荷分散され、また、片方のノードが停止した場合でも、残りのノードで処理が継続可能となります。なお、画面処理は「ロードバランサー」+「共有データベース」を活用して可用性が確保され、タスク処理はmidPointに内包するスケジューリングライブラリ「Quartz」+「共有データベース」+「ノード間通信(REST)機能(※)」を活用して可用性が確保されています。

※ リモートノードに対する死活監視、リモートノードへのスケジューリング登録および削除、リモートノードで実行中のタスクの強制終了を行います
image.png

 次に、構成するDockerコンテナは、以下の表のようになります。

コンテナ名 コンテナ名(物理名) ポート
(外部ポート:コンテナポート)
役割 利用イメージ 補足
LBコンテナ mp-ha-example-lb 443:443
80:80
ロードバランサー(SSLアクセレータ) fuww/alpine-nginx-sticky SSLを復号し、構成されるIGAコンテナへロードバランシング(スティッキーセッション)するように構成
IGAコンテナ#1 mp-ha-example-iga1 8080:8080 midPoint本体(NodeA) evolveum/midpoint:4.0.1 公式midPointのDockerイメージに、あらかじめ準備したmidPoint初期設定をインポートするように構成
IGAコンテナ#2 mp-ha-example-iga2 8081:8080 midPoint本体(NodeB)
DBコンテナ mp-ha-example-db4mp 5432:5432 midPointデータベース postgres:10.6 公式PostgreSQLのDockerイメージに、midPointデータベース(DDL)を構築するように構成

 そして、構成するコンテンツは、以下の表のようになります。

コンテンツ名 URL ID/PASSWORD
midPoint管理コンソール https://iga.example.com/ administrator/5ecr3t

冗長構成の構築

 前述を踏まえまして、実際に冗長構成を構築していきます。

前提条件

 実行環境(OS)は問いませんが、「Docker CE」(※1)および「Docker Compose」(※2)がインストールされていることが、前提条件となります。

※1「Docker CE」は、コンテナ型の仮想化環境を提供するオープンソースソフトウェアのコミュニティー版である「Docker Community Edition」の略称です。
※2「Docker Compose」は、複数のコンテナから成るサービスを構築、実行する手順を自動的にし、管理を容易にするツールです。

 既に、Dockerの実行環境をお持ちの方は、この部分は読み飛ばして構いません。お持ちでない方は、以下のサイトを参考にインストールしてください。

 Dockerは、さまざまなOSに対応しているので、任意の環境にインストールしてください。また、必要に応じて、DockerのHTTP/HTTPSプロキシの通し方について記載された「HTTP/HTTPS proxy」を参照し、設定を行ってください。

 なお、筆者はCentOS 7で確認を行ったため、これ以降CentOS 7をベースにして記載しますが、読者の実行環境に読み替えて実施することも可能です。

事前準備

 今回は、「Docker CE」および「Docker Compose」を使用して構築しますが、このDockerホストとなるCentOSへFQDNでアクセスできるように、クライアントマシンのhostsファイルに設定を追加します。

hosts
xxx.xxx.xxx.xxx iga.example.com

※「xxx.xxx.xxx.xxx」の部分はCentOSのIPアドレスです。

設定確認

 構築手順に入る前に、マニュアルとDockerビルドファイルの設定箇所を確認してみましょう。

マニュアル

 midPointのマニュアルに、セットアップ方法が解説されています。

 [STEP]
 1. 共有データベースの設定をする
 2. クラスタリング設定をする(クラスタモードをオンにし、クラスタ設定項目を設定する)

:information_source: POINT
共有データベースの例として記載がある`PostgreSQL`の他、`MySQL`、`Oracle`、`SQLServer`など、主要データベースに対応しています。但し、midPointの作り上、副問合せ処理が多用されているので、副問合せ処理の苦手な`MySQL`の選択は控えた方が良さそうです。
また、3.9以前のノード間通信は、`JMX`方式を採用していましたが、セキュリティの懸念により、4.0から`REST`方式が追加されました。4.0でも`JMX`方式の設定も可能ですが、非推奨となっていますので、`REST`方式を選択してください。

設定箇所

 マニュアル通りに、<MP_HOME>/config.xmlに設定することも可能ですが、今回提供するDockerビルドファイルには、以下のように設定しています。

共有データベースの設定

:information_source: POINT
オフィシャルDockerイメージは、環境変数`REPO_***`を指定することでデータベース設定が可能です。

クラスタリングの設定

:information_source: POINT
オフィシャルDockerイメージは、環境変数`MP_JAVA_OPTS`の中に、クラスタ設定項目を指定することで、クラスタリングの設定が可能です。

構築手順

 まずは、今回公開したDockerビルドファイルを任意の場所にダウンロードし、解凍します。

ダウンロード・解凍
$ wget https://github.com/naokiiiii/midpoint-dockerfiles/archive/mp-ha-example4qiita.zip
$ unzip mp-ha-example4qiita.zip

 次に、Dockerイメージのビルド、およびDockerコンテナの起動をします。

ビルド・起動
$ cd midpoint-dockerfiles/mp-ha-example/
$ docker-compose up -d --build
~ (省略) ~
Creating mp-ha-example-db4mp ... done
Creating mp-ha-example-lb    ... done
Creating ha-example-iga2     ... done
Creating ha-example-iga1     ... done

 最後に、以下の通り、コンテナが起動していることを確認します。

起動確認
$ docker-compose ps
       Name                      Command                 State                       Ports                
----------------------------------------------------------------------------------------------------------
ha-example-iga1       /usr/local/bin/startup.sh       Up (healthy)   0.0.0.0:8080->8080/tcp               
ha-example-iga2       /usr/local/bin/startup.sh       Up (healthy)   0.0.0.0:8081->8080/tcp               
mp-ha-example-db4mp   docker-entrypoint.sh postgres   Up             0.0.0.0:5432->5432/tcp               
mp-ha-example-lb      nginx -g daemon off;            Up             0.0.0.0:443->443/tcp,                
                                                                     0.0.0.0:80->80/tcp 

 これで、midPointの冗長構成の構築が完了です。

 補足になりますが、Dockerコンテナを停止する場合には、以下のコマンドを実行します。

停止
$ docker-compose down
Stopping mp-ha-example_iga2 ... done
Stopping mp-ha-example_iga1 ... done
Stopping mp-ha-example-lb    ... done
Stopping mp-ha-example-db4mp ... done
Removing mp-ha-example_iga2 ... done
Removing mp-ha-example_iga1 ... done
Removing mp-ha-example-lb    ... done
Removing mp-ha-example-db4mp ... done
Removing network mp-ha-example_default

冗長構成の動作確認

 それでは、冗長構成の動作を確認していきましょう。今回は、以下の2つのシナリオで確認します。

  • [1] 画面処理の可用性
     スティッキーセッションでロードバランシングされた側のノードがダウンした場合でも、残りのノードにロードバランシングされ、画面処理が継続されることを確認します。ただし、セッションは共有されていないので、再度ログインを求められます。
  • [2] タスク処理の可用性
     タスクが実行中のノードがダウンした場合でも、残りのノードでタスクが自動リカバリーされ、タスク処理が継続されることを確認します。

[1] 画面処理の可用性

 はじめに、画面処理の可用性の確認を行います。

 まずは、midPoint管理コンソールにアクセスし、administratorユーザーでログインします。
 ブラウザの開発者ツール等で、ロードバランサーのCookieの値(iga_lb_id)を見ると、どちらのノードにロードバランシングされているか確認できます。ここでは、ノードAにロードバランシングされています。
image.png

 次に、ユーザーの登録を行います。
 ユーザー一覧で現在のユーザー登録状態を確認し、「新規ユーザー登録画面」に遷移します。一旦、最低限の名前のみ入力したものでユーザーを登録し、新しくユーザーが登録されたことを確認します。
image.png
image.png
image.png

このタイミングで、ノードAで障害が発生したと仮定して、ノードAのコンテナを強制終了します。

強制終了・起動確認
$ docker-compose kill iga1
Killing ha-example-iga1 ... done
$ docker-compose ps
       Name                      Command                 State                      Ports                
---------------------------------------------------------------------------------------------------------
ha-example-iga1       /usr/local/bin/startup.sh       Exit 137                                           
ha-example-iga2       /usr/local/bin/startup.sh       Up (healthy)   0.0.0.0:8081->8080/tcp              
mp-ha-example-db4mp   docker-entrypoint.sh postgres   Up             0.0.0.0:5432->5432/tcp              
mp-ha-example-lb      nginx -g daemon off;            Up             0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp 

 画面に戻り、ユーザー一覧の検索を行います。
 エラー画面に遷移することなく、ノードBにロードバランシングされますが、セッションは共有されてないので、再度、ログインを求められ、トップページに戻ってしまいます。しかし、先ほど登録したユーザーデータは共有されているので、画面処理が継続可能であることが確認できます。なお、もともとノードBにロードバランシングされていたユーザーは、スティッキーセッションですので、ログインも求められることなく、画面処理が継続可能です。
image.png
image.png
image.png
image.png

そして、強制終了したノードAが復旧したと仮定して、ノードAのコンテナを起動します。

起動・起動確認
$ docker-compose start iga1
Starting ha-example-iga1 ... done
$ docker-compose ps
       Name                      Command                 State                       Ports                
----------------------------------------------------------------------------------------------------------
ha-example-iga1       /usr/local/bin/startup.sh       Up (healthy)   0.0.0.0:8080->8080/tcp               
ha-example-iga2       /usr/local/bin/startup.sh       Up (healthy)   0.0.0.0:8081->8080/tcp               
mp-ha-example-db4mp   docker-entrypoint.sh postgres   Up             0.0.0.0:5432->5432/tcp               
mp-ha-example-lb      nginx -g daemon off;            Up             0.0.0.0:443->443/tcp,0.0.0.0:80->80/tcp  

 これで、両方のノードにロードバランシング(スティッキーセッション)が再開されます。

[2] タスク処理の可用性

 続きまして、タスク処理の可用性を確認します。
 midPoint管理コンソールにアクセスし、administratorユーザーでログインします。「サーバータスク画面」に遷移し、ノードの明細に、NodeANodeBのステータスが実行中になっていれば、タスクの分散実行が可能な状態です。そして、テスト用タスクを用意してありますので、「タスク詳細」に遷移します。
image.png

 このテスト用タスクは、ロギングしながら30秒間スリープするだけの処理が書かれているのですが、このタスクをスケジューリングします。ここでは確認がしやすいように、60秒間隔の繰り返しタスクで、何かしらの障害でタスクのスレッドが意図せず終了した場合にはリスタートするよう設定します。
 また、タスクが実行された場合、「実行ステータス」に、実行ノードが表示されます。ここでは、ノードAとなっています。
image.png
image.png

 このタスクが終了する前に、ノードAで障害が発生したと仮定して、ノードAを強制終了します。

強制終了・起動確認
$ docker-compose kill iga1
Killing ha-example-iga1 ... done
$ docker-compose ps
       Name                      Command                 State                       Ports                
----------------------------------------------------------------------------------------------------------
ha-example-iga1       /usr/local/bin/startup.sh       Exit 137                                           
ha-example-iga2       /usr/local/bin/startup.sh       Up (healthy)   0.0.0.0:8081->8080/tcp              
mp-ha-example-db4mp   docker-entrypoint.sh postgres   Up             0.0.0.0:5432->5432/tcp              
mp-ha-example-lb      nginx -g daemon off;            Up             0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp 

 サーバーログ確認すると、ノードAで実行中のテスト用タスクが途中で終了しますが、ノードBタスクが自動リカバリーされていることが確認できます。

ログ確認
$ docker-compose logs -f
ha-example-iga1 | 2019-12-15 06:55:51,869 [MODEL] [midPointScheduler_Worker-7] INFO (com.evolveum.midpoint.expression): ==== doing test-task ==== Start ←'★ノードAでテスト用タスクが開始'
ha-example-iga1 | 2019-12-15 06:55:52,870 [MODEL] [midPointScheduler_Worker-7] INFO (com.evolveum.midpoint.expression): ==== doing test-task ====.
ha-example-iga1 | 2019-12-15 06:55:53,871 [MODEL] [midPointScheduler_Worker-7] INFO (com.evolveum.midpoint.expression): ==== doing test-task ====..
ha-example-iga1 | 2019-12-15 06:55:54,871 [MODEL] [midPointScheduler_Worker-7] INFO (com.evolveum.midpoint.expression): ==== doing test-task ====...
~ (省略) ~
ha-example-iga1 | 2019-12-15 06:56:04,878 [MODEL] [midPointScheduler_Worker-7] INFO (com.evolveum.midpoint.expression): ==== doing test-task ====.........+...
ha-example-iga1 exited with code 137 ←'★テスト用タスク処理の途中でノードAが強制終了された'
ha-example-iga2 | 2019-12-15 06:56:24,319 [] [QuartzScheduler_midPointScheduler-NodeB_ClusterManager] INFO (org.quartz.impl.jdbcjobstore.JobStoreTX): ClusterManager: detected 1 failed or restarted instances.
ha-example-iga2 | 2019-12-15 06:56:24,320 [] [QuartzScheduler_midPointScheduler-NodeB_ClusterManager] INFO (org.quartz.impl.jdbcjobstore.JobStoreTX): ClusterManager: Scanning for instance "NodeA" s failed in-progress jobs. ←'★ノードAでタスクが異常終了したことを検知'
ha-example-iga2 | 2019-12-15 06:56:24,344 [] [QuartzScheduler_midPointScheduler-NodeB_ClusterManager] INFO (org.quartz.impl.jdbcjobstore.JobStoreTX): ClusterManager: ......Deleted 1 complete triggers(s).
ha-example-iga2 | 2019-12-15 06:56:24,344 [] [QuartzScheduler_midPointScheduler-NodeB_ClusterManager] INFO (org.quartz.impl.jdbcjobstore.JobStoreTX): ClusterManager: ......Scheduled 1 recoverable job(s) for recovery.
ha-example-iga2 | 2019-12-15 06:56:24,415 [] [midPointScheduler_Worker-5] INFO (com.evolveum.midpoint.task.quartzimpl.execution.JobExecutor): Recovering resilient task Task(id:1576390139067-0-1, name:test-task, oid:task0000-0000-0000-0000-00000test) ←'★ノードBでテスト用タスクを自動リカバリ'
ha-example-iga2 | 2019-12-15 06:56:25,217 [MODEL] [midPointScheduler_Worker-5] INFO (com.evolveum.midpoint.expression): ==== doing test-task ==== Start ←'★ノードBでテスト用タスクが開始'
ha-example-iga2 | 2019-12-15 06:56:26,352 [MODEL] [midPointScheduler_Worker-5] INFO (com.evolveum.midpoint.expression): ==== doing test-task ====.
ha-example-iga2 | 2019-12-15 06:56:27,353 [MODEL] [midPointScheduler_Worker-5] INFO (com.evolveum.midpoint.expression): ==== doing test-task ====..
ha-example-iga2 | 2019-12-15 06:56:28,354 [MODEL] [midPointScheduler_Worker-5] INFO (com.evolveum.midpoint.expression): ==== doing test-task ====...
~ (省略) ~
ha-example-iga2 | 2019-12-15 06:56:55,387 [MODEL] [midPointScheduler_Worker-5] INFO (com.evolveum.midpoint.expression): ==== doing test-task ====.........+.........+.........+
ha-example-iga2 | 2019-12-15 06:56:55,387 [MODEL] [midPointScheduler_Worker-5] INFO (com.evolveum.midpoint.expression): ==== doing test-task ==== End ←'★ノードBでテスト用タスクが終了'
ha-example-iga2 | 2019-12-15 06:56:55,389 [] [midPointScheduler_Worker-5] INFO (com.evolveum.midpoint.model.impl.scripting.ExecutionContext): Script console message: Executed script on the pipeline

※ ポイントとなる行に、★印付きで解説を記載しています

 このとき、「サーバータスク画面」よりノードの状態を確認すると、ノードAオフとなっており、以降のタスクはノードBで実行されます。
image.png

そして、強制終了したノードAが復旧したと仮定して、ノードAのコンテナを起動します。

起動・起動確認
$ docker-compose start iga1
Starting ha-example-iga1 ... done
$ docker-compose ps
       Name                      Command                 State                       Ports                
----------------------------------------------------------------------------------------------------------
ha-example-iga1       /usr/local/bin/startup.sh       Up (healthy)   0.0.0.0:8080->8080/tcp               
ha-example-iga2       /usr/local/bin/startup.sh       Up (healthy)   0.0.0.0:8081->8080/tcp               
mp-ha-example-db4mp   docker-entrypoint.sh postgres   Up             0.0.0.0:5432->5432/tcp               
mp-ha-example-lb      nginx -g daemon off;            Up             0.0.0.0:443->443/tcp,0.0.0.0:80->80/tcp     

 再度「サーバータスク画面」よりノードの状態を確認すると、ノードB実行中となり、タスクの分散実行が再開されます。
image.png

 なお、今回はタスクの異常終了時に自動リカバリーするシナリオで解説しましたが、実装するタスクによっては、エラー内容や影響範囲を把握せず闇雲に自動リカバリーしたくないケースもあるかと思います。スケジューリング設定の中で少し触れましたが、タスクが実行中に異常停止した場合の動作や、両ノードがダウンしていてスケジュール時刻に起動できなかった場合の動作は、運用要件に合わせて変更可能です。ここでは詳細な解説は割愛しますが、ぜひ、midPointのマニュアルを読みながら、このDocker環境で試して、理解を深めてみてください。

おわりに

 以上で、2つのmidPointサーバーが冗長化されていることを確認できました。今回はmidPointのマニュアルをベースに構築を行ったのですが、アレンジでセッションの共有も行うことが可能です。midPointは「Spring Boot」をベースに構築されていますので、「Spring Session」を利用することで、MemcacheやRedisなどのインメモリデータストアにセッションが共有され、より理想的な冗長構成となります。ロードバランシングの切り替わりタイミングでログイン画面さえも表示させたくないといった高いシステム要求の場合には、障害ポイントが増えることにも注意しながら、採用を検討してみてください。


参考

Clustering / high availability setup
※ 公式のクラスタリング設定のマニュアルです

GitHub Evolveum/midpoint-docker - demo(clustering)
※ 公式のDockerのクラスタリングデモです(非推奨の「JMX」方式で構築されているので参考までに)

Task Manager
※タスクの動作について解説されています。

mark.png

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?