midPointで構築する「冗長構成」実践編

# はじめに
　システム要求の度合により手厚さは変わりますが、どんなシステムも実運用をする上で、**一定の可用性の確保は必要不可欠**です。ここでは「[3日目 midPointで構築するシステムの構成例](https://qiita.com/n1330/items/c6cc10d1a3afb4397774#%E5%86%97%E9%95%B7%E6%A7%8B%E6%88%90)」でご紹介した冗長構成を実践していきます。
　また、今回はDockerを利用した環境構築を行っていきます。Docker実行環境があれば簡単に動かすことができますので、動くものベースに理解を深めていただければと思います。

<table><tr><th>:information_source: GitHubに公開しています</th></tr><tr><td>本稿で紹介するDocker ビルドファイルは、以下のGitHubに公開しています。ぜひこちらも合わせてご参照ください。<BR>
・<a href="https://github.com/openstandia/midpoint-dockerfiles" target="_blank">https://github.com/openstandia/midpoint-dockerfiles</a>
</td></tr></table>

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

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

　なお、「共有データベース」の可用性については、SPOF（Single Point Of Failure）とならないように、何らかの方式で可用性が確保されているものとします。実際には、クラウドのマネージドサービスDB（Amazon RDSなど）を利用したり、Active/Standby構成を組むなどの対処を行う必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/e0f69cd4-a442-559f-5ba7-8175c4959f9a.png)

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

|コンテナ名|コンテナ名（物理名）|ポート<BR>(外部ポート:コンテナポート)|役割|利用イメージ|補足|
|:--|:--|:--|:--|:--|:--|
|LBコンテナ|mp-ha-example-lb|443:443<BR>80:80|ロードバランサー（SSLアクセレータ）|fuww/alpine-nginx-sticky|SSLを復号し、構成されるIGAコンテナへロードバランシング（スティッキーセッション）するように構成|
|IGAコンテナ#1|mp-ha-example-iga1|8080:8080|midPoint本体(ノードA)|evolveum/midpoint:4.0.1|公式midPointのDockerイメージに、あらかじめ準備したmidPoint初期設定をインポートするように構成|
|IGAコンテナ#2|mp-ha-example-iga2|8081:8080|midPoint本体(ノードB)|〃|〃|
|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）がインストールされていることが、前提条件となります。

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

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

* [Install Docker CE](https://docs.docker.com/install/)
* [Install Docker Compose](https://docs.docker.com/compose/install/)

　Dockerは、さまざまなOSに対応しているので、任意の環境にインストールしてください。また、必要に応じて、DockerのHTTP/HTTPSプロキシの通し方について記載された「[HTTP/HTTPS proxy](https://docs.docker.com/engine/admin/systemd/#/http-proxy)」を参照し、設定を行ってください。

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

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

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

  * [Clustering / high availability setup](https://wiki.evolveum.com/pages/viewpage.action?pageId=11075783)

　要約すると、以下の2STEPの作業が発生します。
　**STEP1：**　共有データベースの設定をする
　**STEP2：**　クラスタリング設定をする（クラスタモードをオンにし、クラスタ設定項目を設定する）

<table><tr><th>:information_source: POINT</th></tr><tr><td>共有データベースの例として記載がある`PostgreSQL`の他、`MySQL`、`Oracle`、`SQLServer`など、主要データベースに対応しています。<BR>また、3.9以前のノード間通信は、`JMX`方式を採用していましたが、セキュリティの懸念により、4.0から`REST`方式が追加されました。4.0でも`JMX`方式の設定も可能ですが、非推奨となっていますので、`REST`方式を選択してください。
</td></tr></table>

また、クラスタリング設定で使用するパラメーターとその説明を以下に記載しておきます。

|パラメーター|必須|説明|備考|
|:--|:--|:--|:--|
|-Dmidpoint.taskManager.clustered|〇|タスクのクラスターモードを指定します。ONにするには、`true`を指定します。|　|
|-Dmidpoint.nodeId|〇|ノード識別子を指定します。|　|
|-Dmidpoint.nodeIdSource|　|ノード識別子のソースを指定します。Autoscaling可能な環境などで、明示的なノードIDが定義できないケースに利用します。|　|
|-Dmidpoint.hostname|　|ローカルホスト名を指定します。指定しない場合、OSのホスト名が使用されます。|通常、この情報を指定する必要はありません。|
|-Dmidpoint.httpPort|　|ローカルHTTPポートを指定します。指定しない場合、8080ポートが使用されます。 |通常、この情報を指定する必要はありません。|
|-Dmidpoint.url|　|ノード間通信用のURLを指定します。指定しない場合、https://`LOCAL_HOSTNAME`:8080/midpointが使用されます。|通常、この情報を指定する必要はありません。|

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

#### 共有データベースの設定
  * https://github.com/openstandia/midpoint-dockerfiles/blob/mp-ha-example4qiita/mp-ha-example/docker-compose.yml#L78-L88
  * https://github.com/openstandia/midpoint-dockerfiles/blob/mp-ha-example4qiita/mp-ha-example/docker-compose.yml#L116-L126

<table><tr><th>:information_source: POINT</th></tr><tr><td>オフィシャルDockerイメージは、環境変数`REPO_***`を指定することでデータベース設定が可能です。<BR>
また、Dockerを利用されない方は、以下のように起動オプションで設定できます。<BR>
<a href="https://github.com/Evolveum/midpoint-docker/blob/575ba7120dca8e3801175540a42ee2894d20e31a/container_files/usr-local-bin/start-midpoint.sh#L26-L41" target="_blank">https://github.com/Evolveum/midpoint-docker/blob/575ba7120dca8e3801175540a42ee2894d20e31a/container_files/usr-local-bin/start-midpoint.sh#L26-L41</a></td></tr></table>

#### クラスタリングの設定
  * https://github.com/openstandia/midpoint-dockerfiles/blob/mp-ha-example4qiita/mp-ha-example/docker-compose.yml#L93
  * https://github.com/openstandia/midpoint-dockerfiles/blob/mp-ha-example4qiita/mp-ha-example/docker-compose.yml#L131
<table><tr><th>:information_source: POINT</th></tr><tr><td>オフィシャルDockerイメージは、環境変数`MP_JAVA_OPTS`の中に、クラスタ設定項目を指定することで、クラスタリングの設定が可能です。</td></tr></table>


## 構築手順

　まずは、このDockerホストとなるCentOSへFQDNでアクセスできるように、クライアントマシンのhostsファイルに設定を追加します。

```txt:hosts
xxx.xxx.xxx.xxx iga.example.com
```
※「xxx.xxx.xxx.xxx」の部分はCentOSのIPアドレスです。

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

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

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

```bash:ビルド・起動
$ 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
```

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

```bash:起動確認
$ 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コンテナを停止する場合には、以下のコマンドを実行します。

```bash:停止
$ 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］ 画面処理の可用性](https://qiita.com/naokiiiii/private/cd067c495e14754ec332#1-%E7%94%BB%E9%9D%A2%E5%87%A6%E7%90%86%E3%81%AE%E5%8F%AF%E7%94%A8%E6%80%A7)  
　スティッキーセッションでロードバランシングされた側のノードがダウンした場合でも、残りのノードにロードバランシングされ、画面処理が継続されることを確認します。ただし、セッションは共有されていないので、再度ログインを求められます。
* [［2］ タスク処理の可用性](https://qiita.com/naokiiiii/private/cd067c495e14754ec332#2-%E3%82%BF%E3%82%B9%E3%82%AF%E5%87%A6%E7%90%86%E3%81%AE%E5%8F%AF%E7%94%A8%E6%80%A7)  
　タスクが実行中のノードがダウンした場合でも、残りのノードでタスクが自動リカバリーされ、タスク処理が継続されることを確認します。

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

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

**ログイン画面(ノードAにロードバランシングされている)**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/09ec55d8-6f31-08e1-3fc4-13eed9c65bc0.png)

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

**ユーザー一覧画面（新規ユーザー登録前）**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/33bf16a7-156b-af4f-4341-0178f8a5fc31.png)
**新規ユーザー登録画面(新規ユーザー登録入力)**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/a496a901-7c09-502e-a2c3-67070654b1a4.png)
**ユーザー一覧画面（新規ユーザー登録後）**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/9ef2fc89-de2d-86da-e8dc-191b606eba2b.png)

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

```bash:強制終了・起動確認
$ 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/5f6935ce-7c6b-2c86-8d73-8ae333f545f1.png)
**ログイン画面（ノードBにロードバランシングされている）**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/e759064f-5b3d-f9a0-d1b6-5f88e8934b10.png)
**ホーム画面（再ログイン後はホーム画面に戻ってしまう）**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/b99eae82-d08d-ddb8-46e3-acd467f3f0f6.png)
**ユーザー一覧画面（データが共有されている）**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/35480151-35d7-d33c-5f6b-94c7813e6140.png)

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

```bash:起動・起動確認
$ 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`ユーザーでログインします。「サーバータスク画面」に遷移し、ノードの明細に、ノードAとノードBのステータスが`実行中`になっていれば、タスクの分散実行が可能な状態です。そして、テスト用タスクを用意してありますので、「タスク詳細」に遷移します。

**タスク画面（両ノードで分散実行が可能な状態）**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/67e16dc2-43df-6b5d-2a96-40997afbdc53.png)

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

**タスク詳細画面（スケジューリング設定）**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/a1be4123-5c8d-786e-a2c5-84b6d7ea8b55.png)
**タスク詳細画面（タスクがノードAで実行中）**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/07200679-7b83-9c38-090e-e9b8fbc72f64.png)

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

```bash:強制終了・起動確認
$ 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`で**タスクが自動リカバリーされていること**が確認できます。

```bash:ログ確認
$ 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`で実行されます。

**タスク画面（ノードBの片肺運転状態）**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/b82fb667-24e1-5d75-ae9b-75e5357c0302.png)

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

```bash:起動・起動確認
$ 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207022/da0d88f1-5768-2ad2-4faa-b03d1f6e0f03.png)

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

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

---
# 参考
[Clustering / high availability setup](https://wiki.evolveum.com/pages/viewpage.action?pageId=11075783)
※ 公式のクラスタリング設定のマニュアルです

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

[Task Manager](https://wiki.evolveum.com/display/midPoint/Task+Manager)
※タスクの動作について解説されています。

[![mark.png](https://github.com/k-tamura/cocha-icons/raw/master/designed_by_cocha_icons.gif)](https://github.com/k-tamura/cocha-icons)