OpenShift Cluster Application Migration tool を動かしてみた件

本記事は、[OpenShift Advent Calendar 2019](https://qiita.com/advent-calendar/2019/openshift) の6日目です。

# はじめに
OpenShift Container Platform (OCP) 4.2 のリリースから少し遅れた 2019/10/31 に Cluster Application Migration (CAM) tool が GA (General Availability) になりました。

OCP 4 では OCP 3 から大幅にアーキテクチャが変更になったこともあり、OCP 3 から OCP 4 へアップグレードすることができないため、以下の2つのマイグレーションツールが提供されています。

* Control Plane Migration Assistant (CPMA) 
* Cluster Application Migration (CAM) tool 

本記事では、OCP 3 クラスタ上のアプリケーションのマイグレーションを行う、後者の Cluster Application Migration (CAM) tool について紹介したいと思います。


# Cluster Application Migration (CAM) tool とは
Cluster Application Migration (CAM) tool は、オープンソースプロジェクトの [Velero](https://github.com/vmware-tanzu/velero) と [Restic](https://restic.net/) をベースとした、OCP 上のアプリケーションのマイグレーションを行うツールです。本記事の執筆時点 (2019年12月) では、OCP 3.7 以上から OCP 4.2 へのアプリケーションマイグレーションをサポートしています。

Cluster Application Migration tool のアーキテクチャは以下の通りです。

![スクリーンショット 2019-11-29 10.37.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/06fc385e-32de-147c-d9f9-dbf68b27fbd2.png)

Velero がマイグレーション元/先の OCP クラスタにそれぞれインストールされ、Amazon S3 互換のオブジェクトストレージである Replication repository を経由して、PV (Persistent Volume) 内のデータやアプリケーションコンテナイメージなどをマイグレーションすることができます。


# Cluster Application Migration (CAM) tool を動かしてみた
ここからは実際に Cluster Application Migration tool を動かしながら説明したいと思います。

## マイグレーション対象のアプリケーション
ここでは "Node.js + MongoDB" のテンプレートを利用し "migration-test" プロジェクトに作成した、以下の簡単なサンプルアプリケーションをマイグレーション対象とします。

```console

$ oc get all -n migration-test
NAME                                  READY     STATUS      RESTARTS   AGE
pod/mongodb-1-qvp9q                   1/1       Running     0          13m
pod/nodejs-mongo-persistent-1-6rvb6   1/1       Running     0          11m
pod/nodejs-mongo-persistent-1-build   0/1       Completed   0          13m

NAME                                              DESIRED   CURRENT   READY     AGE
replicationcontroller/mongodb-1                   1         1         1         13m
replicationcontroller/nodejs-mongo-persistent-1   1         1         1         11m

NAME                              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)     AGE
service/mongodb                   ClusterIP   172.30.201.103   <none>        27017/TCP   13m
service/nodejs-mongo-persistent   ClusterIP   172.30.99.50     <none>        8080/TCP    13m

NAME                                                         REVISION   DESIRED   CURRENT   TRIGGERED BY
deploymentconfig.apps.openshift.io/mongodb                   1          1         1         config,image(mongodb:3.4)
deploymentconfig.apps.openshift.io/nodejs-mongo-persistent   1          1         1         config,image(nodejs-mongo-persistent:latest)

NAME                                                     TYPE      FROM      LATEST
buildconfig.build.openshift.io/nodejs-mongo-persistent   Source    Git       1

NAME                                                 TYPE      FROM          STATUS     STARTED          DURATION
build.build.openshift.io/nodejs-mongo-persistent-1   Source    Git@e59fe75   Complete   13 minutes ago   2m21s

NAME                                                     DOCKER REPO                                                               TAGS      UPDATED
imagestream.image.openshift.io/nodejs-mongo-persistent   docker-registry.default.svc:5000/migration-test/nodejs-mongo-persistent   latest    11 minutes ago

NAME                                               HOST/PORT                                                              PATH      SERVICES                  PORT      TERMINATION   WILDCARD
route.route.openshift.io/nodejs-mongo-persistent   nodejs-mongo-persistent-migration-test.apps.GUID.example.opentlc.com             nodejs-mongo-persistent   <all>                   None
```


## 前提条件
OCP 3 から OCP 4 クラスタへアプリケーションをマイグレーションするためには、以下の前提条件を事前に満たす必要があります。

* マイグレーション元/先の OCP クラスタに対して cluster-admin 権限を持っていること
* OCP 3 クラスタへの操作のため docker (もしくは podman) がインストールされていること
* Replication repository に利用するため Amazon S3 互換のオブジェクトストレージが用意されていること
* マイグレーション元の OCP クラスタにおいて古いバージョンの ImageStream (nodejs:6 など) を利用している場合、マイグレーション先の OCP クラスタに対して ImageStream が事前に追加されていること

上記の他にも OCP 3 から OCP 4 へマイグレーションする上で、アーキテクチャの変更から考慮することがありますが、以下のURLに考慮ポイントが記載されていますのでご確認ください。

1.2.2. Migration considerations
https://access.redhat.com/documentation/en-us/openshift_container_platform/4.2/html-single/migration/index#migration-considerations


## CAM Operator のインストール
Cluster Application Migration tool では、マイグレーション元/先のそれぞれの OCP クラスタに対して、CAM Operator をインストールする必要があります。

### マイグレーション元の OCP 3 クラスタに CAM Operator をインストール
まずは、以下のコマンドを実行し Red Hat Container Registry にログインします。

```console
# docker login registry.redhat.io
```

次に、以下の2つのコマンドを実行することで、CAM Operator をインストールするために必要なマニフェストファイルをダウンロードします。

```console
# docker cp $(docker create registry.redhat.io/rhcam-1-0/openshift-migration-rhel7-operator:v1.0):/operator.yml ./
# docker cp $(docker create registry.redhat.io/rhcam-1-0/openshift-migration-rhel7-operator:v1.0):/controller-3.yml ./
```

ダウンロードしたマニフェストファイルから、CAM Operator の Custom Resource を生成します。

```console
$ oc create -f operator.yml 
namespace/openshift-migration created
rolebinding.rbac.authorization.k8s.io/system:deployers created
rolebinding.rbac.authorization.k8s.io/system:image-builders created
rolebinding.rbac.authorization.k8s.io/system:image-pullers created
serviceaccount/migration-operator created
customresourcedefinition.apiextensions.k8s.io/migrationcontrollers.migration.openshift.io created
role.rbac.authorization.k8s.io/migration-operator created
rolebinding.rbac.authorization.k8s.io/migration-operator created
clusterrolebinding.rbac.authorization.k8s.io/migration-operator created
deployment.apps/migration-operator created

$ oc create -f controller-3.yml 
migrationcontroller.migration.openshift.io/migration-controller created
```

これで OCP 3 クラスタに CAM Operator のインストールが完了します。以下のコマンドにより正常に CAM Operator がインストールされたことも確認できます。

```console
$ oc get po -n openshift-migration
NAME                                  READY     STATUS    RESTARTS   AGE
migration-operator-69d58b9796-qznlz   2/2       Running   0          1m
restic-2lw8h                          1/1       Running   0          1m
restic-2qv2r                          1/1       Running   0          1m
restic-5nd9c                          1/1       Running   0          1m
restic-65xhr                          1/1       Running   0          1m
restic-67kgb                          1/1       Running   0          1m
restic-jzbrn                          1/1       Running   0          1m
restic-kcp4c                          1/1       Running   0          1m
restic-vnf2d                          1/1       Running   0          1m
velero-d5c888f7d-nvtjh                1/1       Running   0          1m
```

### マイグレーション先の OCP 4.2 クラスタに CAM Operator をインストール
マイグレーション先の OCP 4 クラスタへの CAM Operator のインストールは OperatorHub からインストールすることができます。

まずは、Web コンソールの Administration -> Namespaces から「Create Namespace」ボタンを押下します。Name に "openshift-migration" を入力して「Create」ボタンを押下することで、CAM Operator をインストールする Namespace を作成します。

次に、Operators -> OperatorHub からフィルタに "Cluster Application Migration Operator" を入力し、表示された "Cluster Application Migration Operator" を選択します。

![スクリーンショット 2019-11-29 12.46.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/c26f0401-99ae-1652-710b-f6a6a377a008.png)

「Install」ボタンを押下し、Create Operator Subscription 画面において、デフォルト設定のまま「Subscribe」ボタンを押下します

![スクリーンショット 2019-11-29 12.48.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/e48d8b15-41d6-67a4-686f-33459420e892.png)

Installed Operators 画面が表示されたら、Provided APIs 列の "View 12 more..." リンクを押下します。続いて「Create New」ボタンから「Migration Controller」を選択します。

![スクリーンショット 2019-11-29 12.53.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/abfd9453-5b88-d82c-6a81-8837a30fbc75.png)

Create Migration Controller 画面が表示されますので「Create」ボタンを押下します。

![スクリーンショット 2019-11-29 13.00.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/ff87a451-e8a5-a0df-e29e-62df6a7a99f4.png)

Workloads -> Pods から全ての Pod が Running になっていれば CAM Operator のインストールは完了です。


## OCP 3 クラスタに CORS (Cross-Origin Resource Sharing) の設定を追加
OCP 4 クラスタ上の Cluster Application Migration tool から OCP 3 の API サーバとの接続を許可するため、OCP 3 クラスタに対して CORS (Cross-Origin Resource Sharing) の設定を追加する必要があります。

まずは、マイグレーション先の OCP 4 クラスタにおいて、以下のコマンドにより CORS の設定内容を生成します。

```console
$ oc get -n openshift-migration route/migration -o go-template='(?i)//{{ .spec.host }}(:|\z){{ println }}' | sed 's,\.,\\.,g'
(?i)//migration-openshift-migration\.apps\.cluster-GUID\.sandboxXXXX\.opentlc\.com(:|\z)
```

次に、マイグレーション元の OCP 3 クラスタのそれぞれの Master ノードの `/etc/origin/master/master-config.yaml` に対して、上記のコマンドにより取得した文字列を corsAllowedOrigins に追加します。

```/etc/origin/master/master-config.yaml 
(省略)
corsAllowedOrigins:
- (?i)//127\.0\.0\.1(:|\z)
- (?i)//localhost(:|\z)
- (?i)//192\.168\.0\.66(:|\z)
- (?i)//172\.30\.0\.1(:|\z)
- (?i)//kubernetes\.default(:|\z)
- (?i)//kubernetes\.default\.svc\.cluster\.local(:|\z)
- (?i)//kubernetes(:|\z)
- (?i)//openshift\.default(:|\z)
- (?i)//loadbalancer\.d6bb\.internal(:|\z)
- (?i)//openshift\.default\.svc(:|\z)
- (?i)//loadbalancer\.d6bb\.example\.opentlc\.com(:|\z)
- (?i)//master1\.d6bb\.internal(:|\z)
- (?i)//openshift\.default\.svc\.cluster\.local(:|\z)
- (?i)//kubernetes\.default\.svc(:|\z)
- (?i)//openshift(:|\z)
- (?i)//migration-openshift-migration\.apps\.cluster-GUID\.sandboxXXXX\.opentlc\.com(:|\z)
(省略)
```

CORS の設定を有効化するため、以下のコマンドにより OCP 3 クラスタのそれぞれの Master ノードの kubelet を再起動します。

```console
# /usr/local/bin/master-restart api
# /usr/local/bin/master-restart controllers
```

CORS が正常に設定されているかどうかは、以下のコマンド実行例のように HTTP レスポンスコード 204 が返ってくることで確認できます。

```console
$ curl -v -k -X OPTIONS \
> "(OCP 3 クラスタの URL)/apis/migration.openshift.io/v1alpha1/namespaces/openshift-migration/migclusters" \
> -H "Access-Control-Request-Method: GET" \
> -H "Access-Control-Request-Headers: authorization" \
> -H "Origin: (OCP 4 クラスタ上の CAM Web コンソールの URL)" 

 (中略)

< HTTP/1.1 204 No Content
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Requested-With, If-Modified-Since
< Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE, PATCH
< Access-Control-Allow-Origin: https://migration-openshift-migration.apps.cluster-GUID.sandboxXXXX.opentlc.com
< Access-Control-Expose-Headers: Date
< Cache-Control: no-store
< Date: Thu, 28 Nov 2019 01:56:43 GMT
< 
* Connection #0 to host loadbalancer.GUID.example.opentlc.com left intact
```

## CAM Web コンソールの操作
ここまでの手順で Cluster Application Migration tool のインストールと設定が完了しましたので、続いて CAM Web コンソールからの操作手順を説明していきます。

### マイグレーション元 OCP 3 クラスタの追加
OCP 4 クラスタから以下のコマンドの実行結果から取得したURLをブラウザに入力し、CAM Web コンソールを開きます。

```console
$ oc get route/migration -n openshift-migration -o go-template="{{.spec.host}}"
migration-openshift-migration.apps.cluster-GUID.sandboxXXXX.opentlc.com
```

ログイン画面が表示されますので、OCP 4 クラスタの認証情報を利用してログインしてください。

次に、Cluster Application Migration tool に OCP 3 クラスタを追加するため、OCP 3 クラスタにおいて以下のコマンドを実行しトークンを取得します。

```console
$ oc sa get-token mig -n openshift-migration
```

CAM Web コンソールにおいて Clusters -> Add cluster から、それぞれ以下の値を入力し「Add Cluster」ボタンを押下します。

* Cluster Name: (OCP 3 クラスタ名)
* Url:  (OCP 3 クラスタの URL)
* Service account token:    (上記のコマンドにより取得したトークン)

![スクリーンショット 2019-11-29 15.06.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/99835c53-2c33-3f67-85bb-2e893cb34952.png)

"Connection successful" と表示されたら、マイグレーション元の OCP 3 クラスタの追加は完了です。

### Replication repository の追加
次に、アプリケーションコンテナイメージや PV (Persistent Volume) 内のデータなどをマイグレーションするための Replication repository を追加します。

CAM Web コンソールにおいて Repositories -> Add repository から、それぞれ以下の値を入力し「Add Repository」ボタンを押下します。

* Repository Name:    (任意のレポジトリ名)
* S3 Bucket Name:     (Amazon S3 のバケット名)
* S3 Bucket Region:   (AWSのリージョン)
* S3 Endpoint:    (Amazon S3 のエンドポイントの URL)
* S3 Provider Access Key: (AWSのアクセスキー)
* S3 Provider Secret Access Key:  (AWSのシークレットアクセスキー)

![スクリーンショット 2019-11-29 16.30.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/b1af1658-36df-1d20-107c-5a2381742ded.png)

”Connection successful" と表示されたら、Replication repository の追加は完了です。

### マイグレーションプランの上限の緩和
一つのマイグレーションプランには、デフォルトで以下の上限値が設定されています。

* 10 namespaces
* 100 Pods
* 100 persistent volumes

上記の上限を超えてマイグレーションを行いたい場合には、OCP 4 クラスタにおいて以下のコマンドを実行し、MigrationController の Custom Resource を編集する必要があります。

```console
$ oc edit migrationcontroller -n openshift-migration
```

### マイグレーションプランの作成
Plans -> Add plan からマイグレーションプランを作成していきます。

Plan Name に任意のマイグレーションプラン名を入力し「Next」ボタンを押下します。

![スクリーンショット 2019-11-29 15.23.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/466429ec-739f-af6d-b428-7f8fd59807a0.png)

Source Cluster に先程登録した OCP 3 クラスタを選択し、Replication repository にも先程登録した Replication repository を選択し、Target Cluster にデフォルトで登録されている "host" を選択します。

![スクリーンショット 2019-11-29 15.27.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/8b165339-6b83-df5d-0c5d-ac53fe236c39.png)

本画面の下部にマイグレーション対象のプロジェクトを選択する画面が表示されますので、マイグレーション対象のプロジェクト (この例では "migration-test") を選択し「Next」ボタンを押下します。

![スクリーンショット 2019-11-29 15.29.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/dea789b8-db23-b00d-1ec8-13d6eff135dc.png)

マイグレーション対象の PV (Persistent Volume) が表示されるので、Type 欄に Copy/Move のいずれかを選択し「Next」ボタンを押下します。

![スクリーンショット 2019-11-29 15.31.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/ab93f845-f265-6815-627b-db5968d7d678.png)

ここで選択した Copy/Move は PV (Persistent Volume) に格納されたデータのマイグレーション方式を指定するものです。Copy を選択した場合、Replication repository にデータがコピーされ、マイグレーション先 OCP 4 クラスタに新規作成した PV (Persistent Volume) にデータがコピーされます。これに対して Move を選択した場合には、マイグレーション元の OCP 3 クラスタから PV (Persistent Volume) がアンマウントされ、同じリモートボリュームを利用した PV (Persistent Volume) がマイグレーション先の OCP 4 クラスタに新規作成されます。

新規作成される PV (Persistent Volume) の StorageClass を選択し「Finish」ボタンを押下します。

![スクリーンショット 2019-11-29 18.31.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/c85ac8d8-0c0c-239c-f7dd-de0547230e15.png)

これでマイグレーションプランの作成が完了となりますが、マイグレーションプランが作成された CAM Web コンソールは以下の通りです。

![スクリーンショット 2019-11-29 15.39.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/c349e109-dad0-f46b-7fd8-813c17289142.png)


### マイグレーションの実行
ここまででマイグレーションを行うための設定が全て完了したので、ようやくマイグレーションを実行することができます。

Cluster Application Migration tool におけるマイグレーションのプロセスは以下の図の通りです。

![スクリーンショット 2019-11-29 15.52.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/f3e6b165-66b4-96ef-505a-5b96119601fd.png)

"Stage" プロセスでは、マイグレーション元 OCP 3 クラスタからのデータコピーが行われ、この間マイグレーション元 OCP 3 クラスタの停止は発生しません。"Migrate" プロセスでは、オプションの設定によりマイグレーション元 OCP 3 クラスタのアプリケーションが停止し、マイグレーション先 OCP 4 クラスタへのマイグレーションが実行されます。

CAM Web コンソールでは、Plans から「Stage」ボタンを押下することで、マイグレーション元 OCP 3 クラスタからのデータコピーが開始されます。

![スクリーンショット 2019-11-29 16.02.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/f0b33174-dab6-553c-dbfb-004da2eeb7fd.png)

Last Status 欄に "Stage Succeeded" が表示されたら、「Migrate」ボタンを押下することで OCP 4 クラスタへのマイグレーションを開始します。マイグレーション実施中のマグレーション元の OCP 3 クラスタの停止を防ぐ場合には、"Don't halt transactions on the source while migrating" にチェックを入れて、「Migrate」ボタンを押下します。

![スクリーンショット 2019-11-29 16.22.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/20ba7f6c-2cc0-df0a-6601-7014140a2f88.png)

Last Status 欄に "Closed" と表示されたら、OCP 4 クラスタへのマイグレーションは完了です。

![スクリーンショット 2019-11-29 16.27.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/afe8139e-30a4-688c-fcc0-7f03642f8381.png)


## サンプルアプリケーションのマイグレーションの確認
最後にマイグレーション対象の "Node.js + MongoDB" テンプレートを利用したサンプルアプリケーションが OCP 4 クラスタにマイグレーションされていることを確認します。

マイグレーション先の OCP 4 クラスタから、以下のコマンドにより対象のサンプルアプリケーションが正常にマイグレーションされたことを確認できます。

```console
$ oc get all,pv -n migration-test 
NAME                                   READY   STATUS      RESTARTS   AGE
pod/mongodb-1-7rrfx                    1/1     Running     0          127m
pod/mongodb-1-deploy                   0/1     Completed   0          127m
pod/nodejs-mongo-persistent-1-build    0/1     Completed   0          127m
pod/nodejs-mongo-persistent-1-deploy   0/1     Completed   0          127m
pod/nodejs-mongo-persistent-2-deploy   0/1     Completed   0          125m
pod/nodejs-mongo-persistent-2-svvsp    1/1     Running     0          125m

NAME                                              DESIRED   CURRENT   READY   AGE
replicationcontroller/mongodb-1                   1         1         1       127m
replicationcontroller/nodejs-mongo-persistent-1   0         0         0       127m
replicationcontroller/nodejs-mongo-persistent-2   1         1         1       125m

NAME                              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)     AGE
service/mongodb                   ClusterIP   172.30.135.243   <none>        27017/TCP   127m
service/nodejs-mongo-persistent   ClusterIP   172.30.252.153   <none>        8080/TCP    127m

NAME                                                         REVISION   DESIRED   CURRENT   TRIGGERED BY
deploymentconfig.apps.openshift.io/mongodb                   1          1         1         config,image(mongodb:3.4)
deploymentconfig.apps.openshift.io/nodejs-mongo-persistent   2          1         1         config,image(nodejs-mongo-persistent:latest)

NAME                                                     TYPE     FROM   LATEST
buildconfig.build.openshift.io/nodejs-mongo-persistent   Source   Git    1

NAME                                                 TYPE     FROM          STATUS     STARTED       DURATION
build.build.openshift.io/nodejs-mongo-persistent-1   Source   Git@e59fe75   Complete   2 hours ago   1m42s

NAME                                                     IMAGE REPOSITORY                                                                          TAGS     UPDATED
imagestream.image.openshift.io/nodejs-mongo-persistent   image-registry.openshift-image-registry.svc:5000/migration-test/nodejs-mongo-persistent   latest   2 hours ago

NAME                                               HOST/PORT                                                                          PATH   SERVICES                  PORT    TERMINATION   WILDCARD
route.route.openshift.io/nodejs-mongo-persistent   nodejs-mongo-persistent-migration-test.apps.cluster-GUID.sandboxXXXX.opentlc.com          nodejs-mongo-persistent   <all>                 None

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS   REASON   AGE
persistentvolume/pvc-a7259657-1276-11ea-88f6-0e2402e84846   1Gi        RWO            Delete           Bound    migration-test/mongodb   gp2                     148m
```


# さいごに
本記事では、Cluster Application Migration tool について紹介しました。
提供されているもう一つのマイグレーションツールである "Control Plane Migration Assistant (CPMA)" については、今回の OpenShift Advent Calendar 2019 において他の方が記事を書かれるそうです。ご興味ある方は "Control Plane Migration Assistant (CPMA)" について紹介した記事もご確認ください。


# 参考
* [Migrating your applications to OpenShift 4](https://blog.openshift.com/migrating-your-applications-to-openshift-4/)
* [Migrating from OpenShift Container Platform 3 to 4](https://access.redhat.com/documentation/en-us/openshift_container_platform/4.2/html-single/migration/index)