OKE のボリュームプラグインを FlexVolume から CSI に切り替える

カバー

[!] この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Oracle Cloud Infrastructure (以下 OCI) の Kubernetes のサービスである Container Engine for Kubernetes (以下 OKE) を利用しています。OKE で永続ボリュームとして PersistentVolume (以下 PV) を利用していますが、Kubernetes v1.23 で、今まで利用してきたボリュームプラグインの FlexVolume が Deprecated になりました。あわせて OKE でも v1.24 からデフォルトのボリュームプラグインが FlexVolume から CSI に変更になりました (Release Note)。今回は OKE 上で PV のボリュームプラグインを FlexVolume から CSI へ移行した手順を紹介します。

移行前の構成

  • Deployment や StatefulSet で管理している Pod に永続ボリュームを接続している
  • 永続ボリュームは PersistentVolumeClaim (以下 PVC) から FlexVolume の PV を動的プロビジョニングで払い出して利用している

また、検証で利用したそれぞれのツールのバージョンは以下のとおりです。

移行手段

移行手段の候補として以下 3 つの方法を挙げます。

  • 【パターン A】Block Volume を複製して PV を静的プロビジョニングで払い出して利用する方法
  • 【パターン B】Block Volume を再利用して PV を CSI で作り直す方法
  • 【パターン C】パターン B+動的プロビジョニングで払い出した PV と認識させる方法

【パターン A】Block Volume を複製して PV を静的プロビジョニングで払い出して利用する方法

OCI の公式ドキュメントには FlexVolume の場合は「Creating a PVC From an Existing Block Volume or A Backup」に手順がありましたが、CSI についてはドキュメントに記載がありませんでした。OCI のサポートに問い合わせたところ、複製した Block Volume を参照して PV を静的に作成して紐づける手順の回答をいただいたため、こちらの手順を紹介します。

  1. Deployment の削除

    永続ボリュームへの書き込みを止めるため、一度 Deployment との接続を停止します。

    ## 永続ボリュームを使用していた旧 Deployment を削除して、PV との紐づけを解除する
    $ kubectl delete deployment old-deploy
  2. Block Volume の複製

    動的プロビジョニングの設定により、PVC を削除すると、参照していた Block Volume が削除されるため、先にデータを格納した Block Volume を複製します。複製して作成した Block Volume の OCID を控えておきます。

  3. 旧 PVC の削除

    PVC を削除すると動的プロビジョニングのため、PV および紐づく Block Volume が削除されます。

    ## 旧 PVC を削除する
    $ kubectl delete pvc old-pvc
    persistentvolumeclaim "old-pvc" deleted
    
    ## 一覧から old-pvc の削除を確認する
    $ kubectl get pvc
    No resources found in default namespace.
    
    ## PV の一覧から削除されていることを確認する
    $ kubectl get pv
    No resources found.
  4. 新 PV の作成

    CSI のボリュームハンドルの指定で複製した Block Volume を紐づけて PV を作成します。

    ## PV のマニフェストを作成する
    $ vim ./new-pv.yaml
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: new-pv
    spec:
      storageClassName: "oci-bv"  # OCI の CSI の StorageClass を選択
      claimRef:  # 他の PVC の要求から紐づかないよう、PVC を指定する (Namespace: default の new-pvc に紐づける)
        namespace: default
        name: new-pvc
      capacity:
        storage: 50Gi  # 複製前の PV と同じ値
      accessModes:
        - ReadWriteOnce
      csi:
        driver: blockvolume.csi.oraclecloud.com  # OCI の CSI のドライバを選択
        volumeHandle: <Block Volume の OCID>  # 複製した Block Volume の OCID
    ## PV を展開する
    $ kubectl apply -f ./new-pv.yaml
    persistentvolume/new-pv created
    
    ## 展開した PV を確認する
    $ kubectl get pv
    NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM             STORAGECLASS   REASON      AGE
    new-pv   50Gi       RWO            Retain           Available   default/new-pvc   oci-bv                     16s
  5. 新 PVC の作成

    手順 4. で作成した PV を指定して PVC を作成します。

    ## PVC のマニフェストを作成する
    $ vim ./new-pvc.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: new-pvc
    spec:
      storageClassName: "oci-bv"  # OCI の CSI の StorageClass を選択
      accessModes:
      - ReadWriteOnce
      volumeName: new-pv  # 上で作成した PV の名前
      resources:
        requests:
          storage: 50Gi
    ## PVC を展開する
    $ kubectl apply -f ./new-pvc.yaml
    persistentvolumeclaim/new-pvc created
    
    ## 展開した PVC を確認する
    $ kubectl get pvc
    NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    new-pvc   Bound    new-pv   50Gi       RWO            oci-bv         27s
    
    ## PV のステータスも確認する (STATUS: Bound となり、紐づいたことが確認できる)
    $ kubectl get pv
    NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON      AGE
    new-pv   50Gi       RWO            Retain           Bound    default/new-pvc   oci-bv                     4m49s
  6. Deployment の展開

    作成した PVC を利用して Deployment の Pod と Block Volume を紐づけます。

    ## Deployment のマニフェストを作成する
    ## (サンプルとして /mount-pvc に PVC をマウントした ubuntu の Pod を作成する)
    $ vim ./new-deploy.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: new-deploy
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: new-deploy
      template:
        metadata:
          labels:
            app: new-deploy
        spec:
          containers:
          - name: ubuntu
            image: ubuntu:20.04
            command: [ "/bin/bash", "-c", "--" ]
            args: [ "while true; do sleep 30; done;" ]  # sleep を繰り返して稼働したままにする
            volumeMounts:
            - name: pvc
              mountPath: "/mount-pvc"
          volumes:
          - name: pvc
            persistentVolumeClaim:
              claimName: new-pvc  # 上で作成した PVC の名前に変更する
    ## Deployment (Pod) を展開する
    $ kubectl apply -f ./new-deploy.yaml
    deployment.apps/new-deploy created
    
    ## Pod の展開を確認する
    $ kubectl get pod
    NAME                          READY   STATUS    RESTARTS   AGE
    new-deploy-xxxxxxxxxx-yyyyy   1/1     Running   0          4m43s
    
    ## Pod のコンテナにアクセスしてデータが復元されているか確認する
    $ kubectl exec -it new-deploy-xxxxxxxxxx-yyyyy -- /bin/bash
    ## PVC の中のファイルを確認する
    root@new-deploy-xxxxxxxxxx-yyyyy:/# ls /mount-pvc/
    test.txt
    ## ファイルの中身を確認する
    root@new-deploy-xxxxxxxxxx-yyyyy:/# cat /mount-pvc/test.txt
    test
    ## 確認できたため、コンテナからログアウトする
    root@new-deploy-xxxxxxxxxx-yyyyy:/# exit
    exit

これで FlexVolume から CSI に移行することができました。

【パターン B】Block Volume を再利用して PV を CSI で作り直す方法

次に、Block Volume を複製する手間を省き、再利用できるようにパターン A の手順を変更します。PVC の削除時に PV および Block Volume も削除されてしまう原因は、動的プロビジョニングで払い出した PV の ReclaimPolicy が Delete に設定されているためです。ReclaimPolicy を Retain にすることで動的プロビジョニングで払い出した PV でも削除されないようにすることが可能です。

  1. 旧 PV の修正

    ## 動的プロビジョニングで払い出した PV を確認する
    ## (RECLAIM POLICY が Delete になっている)
    $ kubectl get pv
    NAME                                     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
    ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa   50Gi       RWO            Delete           Bound    default/old-pvc   oci                     69s
    
    ## 一時的に ReclaimPolicy を Delete から Retain に変更する (マニフェストの該当部分以外は一部省略)
    $ kubectl edit pv ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa
    spec:
      flexVolume:
        driver: oracle/oci
        fsType: ext4
      # persistentVolumeReclaimPolicy: Delete  # Retain に変更する
      persistentVolumeReclaimPolicy: Retain
      storageClassName: oci  # FlexVolume
    ## 保存すると設定が更新される
    persistentvolume/ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa edited
    
    ## PV のポリシーを確認する
    ## (RECLAIM POLICY が Retain になっている)
    $ kubectl get pv
    NAME                                     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
    ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa   50Gi       RWO            Retain           Bound    default/old-pvc   oci                     8m43s
  2. 旧 PV, PVC の削除

    PV の設定を変更し、PVC, PV それぞれを削除しても Block Volume は残るようになりました。 それぞれ削除して確認します。

    ## PVC を削除する
    $ kubectl delete pvc old-pvc
    persistentvolumeclaim "old-pvc" deleted
    
    ## PV を削除する
    $ kubectl delete pv ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa
    persistentvolume "ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa" deleted
    
    ## PV の削除を確認する
    $ kubectl get pv
    No resources found.
    
    ## OCI の Block Volume 一覧を確認する
    ## aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee という名前の Block Volume が削除されず残っている
    $ oci bv volume list --compartment-id <コンパートメント OCID> --sort-order DESC | jq -r '.data[] | [."display-name", ."id"] | @csv'
    "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee","ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa"
  3. 新 PV の作成、新 PVC の作成、Deployment の修正

    以順はパターン A と同じ手順となります。

【パターン C】パターン B+動的プロビジョニングで払い出した PV と認識させる方法

当社の運用では静的プロビジョニングで BV を残して運用する手順となりました。FlexVolume から CSI への移行にあたり、動的プロビジョニングの削除時のように PVC 削除時に BV まで一緒に削除される挙動に戻すとなると工夫が必要なため、その手順について紹介します。

  1. 旧 PV の修正、PV, PVC の削除

    旧 PV の修正、PV, PVC の削除まではパターン B と同じ手順となります。

  2. 新 PV の作成

    動的プロビジョニングで払い出した PV と自分で Block Volume と紐づけた静的プロビジョニングで払い出した PV の差分を確認すると、Annotation にフラグが付いていることに気づきました。新 PV を作成する際、以下の修正をすることで動的プロビジョニングで払い出した場合と同様になることを確認しました。

    ## パターン A (および、手順を省略したパターン B) で利用した PV のマニフェストを修正する
    $ vim ./new-pv.yaml
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: new-pv
      annotations:
        pv.kubernetes.io/provisioned-by: blockvolume.csi.oraclecloud.com  # 追加 (動的プロビジョニングで作成した場合のフラグ)
    spec:
      storageClassName: "oci-bv"
      persistentVolumeReclaimPolicy: Delete  # 修正 (動的プロビジョニングと同様に、PV 削除時に Block Volume も削除するポリシーに変更する)
      claimRef:
        namespace: default
        name: new-pvc
      capacity:
        storage: 50Gi
      accessModes:
        - ReadWriteOnce
      csi:
        driver: blockvolume.csi.oraclecloud.com
        volumeHandle: <Block Volume の OCID>
    ## PV を展開する
    $ kubectl apply -f ./new-pv.yaml
    persistentvolume/new-pv created
    
    ## PV の展開を確認する
    $ kubectl get pv
    NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM             STORAGECLASS   REASON      AGE
    new-pv   50Gi       RWO            Delete           Available   default/new-pvc   oci-bv                     6s
  3. 新 PVC の作成、Deployment の修正

    新 PVC の作成 以降の手順もパターン A、パターン B と同じ手順になります。

PVC 削除時に動的プロビジョニングと同じ挙動をするか確認

最後に、検証として、パターン C で作成した PV が動的プロビジョニングで払い出した場合と同様に、紐づいた Block Volume が削除されるかを確認するため、PVC を削除します。

## 対象のリソースを確認する
$ kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
new-pvc   Bound    new-pv   50Gi       RWO            oci-bv         19m
$ kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
new-pv   50Gi       RWO            Delete           Bound    default/new-pvc   oci-bv                  19m

## PV の情報を確認する
$ kubectl get pv new-pv -o yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  annotations:
    pv.kubernetes.io/provisioned-by: blockvolume.csi.oraclecloud.com  # 追加したアノテーション
  name: new-pv
spec:
  csi:
    driver: blockvolume.csi.oraclecloud.com
    volumeHandle: ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa  # 紐づく Block Volume の OCID
  persistentVolumeReclaimPolicy: Delete

## OCI の Block Volume 一覧を確認する
$ oci bv volume list --compartment-id <コンパートメント OCID> --sort-order DESC | jq -r '.data[] | [."display-name", ."id"] | @csv'
"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee","ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa"

## Block Volume の情報を取得する (該当箇所以外は一部省略して表記)
$ oci bv volume get --volume-id ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa
{
  "data": {
    "id": "ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa",
    "lifecycle-state": "AVAILABLE",  # ステータスが使用可能になっている
  },
}

## Deployment を削除して Pod と PV との紐づきを解除する
$ kubectl get pod
NAME                          READY   STATUS    RESTARTS   AGE
new-deploy-xxxxxxxxxx-yyyyy   1/1     Running   0          19m

$ kubectl delete deploy new-deploy
deployment.apps "new-deploy" deleted

## それぞれリソース一覧から削除されていることを確認する
$ kubectl get deployment
No resources found in default namespace.
$ kubectl get pod
No resources found in default namespace.

## PVC を削除してみる
$ kubectl delete pvc new-pvc
persistentvolumeclaim "new-pvc" deleted

## PVC 一覧から削除を確認する
$ kubectl get pvc
No resources found in default namespace.

## 削除した PVC に紐づいた PV の削除も確認する
$ kubectl get pv
No resources found.

## 削除した PV に紐づいた Block Volume の情報を確認する (該当箇所以外は一部省略して表記)
$ oci bv volume get --volume-id ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa
{
  "data": {
    "id": "ocid1.volume.oc1.ap-tokyo-1.aaaaaaaaaa",
    "lifecycle-state": "TERMINATED",  # ステータスが削除済になる (OCI コンソール上はステータスが「終了済」と表記)
  },
}

以上で動的プロビジョニングで作成した場合と同様に、PVC の削除のみで、紐づく PV および Block Volume が削除されるようになりました。

おわりに

今回は OKE のバージョンアップにあたり、Deprecated になった FlexVolume の PV を CSI に移行する手順を紹介しました。CSI を利用した PV のリストア手順や、動的プロビジョニングと静的プロビジョニングとの切り替えは OCI 公式のドキュメントにも記載が今のところないため、同じような悩みを抱えている方の手助けになれれば幸いです。


TOP
アルファロゴ 株式会社アルファシステムズは、ITサービス事業を展開しています。このブログでは、技術的な取り組みを紹介しています。X(旧Twitter)で更新通知をしています。