LoginSignup
21
15

More than 3 years have passed since last update.

【KubernetesのPersistentVolume】その2- Dynamic Provisionerを使ってNFSサーバーをPodにmountする

Last updated at Posted at 2019-06-19

概要

KubernetesでPersistentVolume(永続ストレージ)のDynamic Provisionerを使って、外部ストレージをコンテナにmountする。

Dynamic Provisionerを使わない方法については以下を参照。
このページを読む前に、以下の内容を理解しておいたほうがスムーズかと思われる。
【KubernetesのPersistentVolume】その1- 外部ストレージをPodにmountする

目次

前提知識

Dynamic Provisionerとは

Dynamic Provisionerを使うことで、PersistentVolumeを動的に生成することが可能となる。
そのため、予めPersistentVolumeを作成(定義)しておく必要がない。

具体的な設定方法の話をすると、PersistentVolumeを定義せずに、PersistentVolumeClaimを定義するだけで、Volumeを生成しPodにmountすることができる。

  1. PersistentVolumeClaimを定義
  2. Podを定義し、PersistentVolumeClaimと関連付ける
  3. Podを起動 -> Volumeが自動生成されmountされる

Provisionerについて

Dynamic Provisionerでmountするには、Provisionerというものを利用する。
このProvisionerはいくつかの種類があり、ストレージの種類ごと(AWS, GCPなど)にそれぞれ使い分ける。

また、デフォルトでいくつかのProvisionerが用意されている。
利用可能なPorvisionerは以下を参照。
https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner

ただし、今回利用するNFSサーバーには、デフォルトのporvisionerが用意されていない。
そこで、external provisionersというものを利用する。

external provisionersとは

external provisionersは、デフォルトで用意されていないProvisionerをカバーするもので、NFS用のものも用意されている。今回はここで用意されているnfs-clientを利用する。

external provisionersの仕組み

external provisionersの仕組みを簡単に説明すると、NFSの場合は、nfs-clientの下のnfs-client/cmd/nfs-client-provisioner/provisioner.goによって作られるDockerコンテナ(nfs-client/docker/x86_64/Dockerfile)が、NFSのmountなどをやってくれるprovisionerとして動作してくれるようである。

mountされる仕組み

Provisionerを使ったmountの仕組みを理解するのに少し時間がかかったが、以下の用であると理解した。

  1. nfs-provisioner用のPodを作成
  2. サービス用のPodを作成
  3. サービス用Podがnfs-provisioner用のPodを介してNFSサーバーをmountする

ハンズオン

それでは実際に環境構築をする。

環境

  • CentOS 7.6
  • Minikube v1.1.1
  • Kubernetes v1.14.3

ここではMinikubeで構築した環境のPodに、NFSサーバーをmountする。
関連記事:Minikubeを使ってローカルにkubernetes環境を構築

NFSサーバーの構築

まずはmountするためのNFSサーバーを構築する。
手順については以下を参照。

nfs-utilsのインストール

クラスタのホストOS(ここではminikube)に以下をインストール。

$ sudo yum install -y rpcbind nfs-utils

nfs-provisionerの作成

external provisionersを利用して、nfs-provisionerを作成する。

StorageClass

ストレージの種類を定義する。
provisionerという箇所があるが、デフォルトで用意されているProvisionerを利用する場合は、こちらからmountするストレージに合ったProvisionerを指定する。

  • e.g.
    • AWSの場合:provisioner: kubernetes.io/aws-ebs
    • Azureの場合:provisioner: kubernetes.io/azure-file

ただし、今回の用にexternal provisionersを利用する場合は、何でも良いので適当に名前を付ける。
そして、後述のDeploymentの定義のspec.template.spec.containers.env.nameのvalueと同じ名前にして、関連付けられるようにする。

storage-class.yml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  # persitent-volumne-claim.ymlのspec.storageClassNameと合わせる
  name: nfs
# deployment.ymlのspec.template.spec.containers.env.nameのvalueと合わせる
provisioner: lab.hoge.jp/nfs
# Volumeが削除されたときの挙動を定義
# Delete or Retain。デフォルトはDelete。
reclaimPolicy: Retain

PersistentVolumeClaim

PersistentVolumeClaimで、Podが要求するVolumeのspecを定義する。
Dynamic Provisionerを利用する場合は、Volumeは動的に生成されるため、PersistentVolumeを定義する必要はない。

参考:VolumeとPersistentVolumeとPersistentVolumeClaimの違い

persitent-volumne-claim.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  # PVC(PersistentVolumeClaim)のための任意の名前を指定
  name: sample-pvc
  annotations:
    # storage-class.ymlのmetadata.nameと同じ値
    volume.kubernetes.io/storage-class: "nfs"
spec:
  # アクセス権を設定
  accessModes:
    - ReadWriteMany
  # storage-class.ymlのmetadata.nameと合わせる
  # storageClassNameを省略するとHostPathでホストOS上にmountされる
  storageClassName: nfs
  resources:
    requests:
      # 割り当てるstorageの容量
      storage: 1Gi

RBAC

RBAC(Role-based access control)とは、役割ベースのアクセス制御機能。
NFSのprovisionerに与える権限を定義する。
参考:KubernetesのRBACについて

rbac.yml
kind: ServiceAccount
apiVersion: v1
metadata:
  # pod.ymlのspec.serviceAccountNameと合わせる
  name: nfs-client-provisioner

---
# 許可する操作を定義
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

---
# RoleもしくはClusterRoleを関連付けるUserAccountもしくはServiceAcctountを定義
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

Deployment

nfs-porovisionerのDeploymentの定義。

deployment.yml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  # https://qiita.com/MahoTakara/items/a776286e5c4385662df4#%E3%82%B9%E3%83%88%E3%83%A9%E3%83%86%E3%82%B8
  # 古いポッドを新しいポッドに置き換えるための方法
  # defaultはRollingUpdate
  # Recreate 既存のポッドはすべて削除されます。
  strategy:
    type: Recreate
  # nfs-provisionerのPodの定義
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      # https://tech.uzabase.com/entry/2018/03/14/200512
      # これを指定することで、全てのリソースに対する参照all-readerができるようにしています。
      # ちなみに、サービスアカウントを作成するとsecretにca.crt、tokenというデータが作成されます。
      # このsecretはポッドが起動した際に、自動的に/var/run/secrets/kubernetes.io/serviceaccount の配下にマウントされます。
      serviceAccountName: nfs-client-provisioner
      # nfs-provisionerのコンテナの定義
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          # コンテナ内のmountの定義
          volumeMounts:
            # 以下のspec.template.spec.volumes.nameと合わせる
            - name: nfs-client-root
              # コンテナ内でNFSをmountさせるPATH
              mountPath: /persistentvolumes
          env:
            # storage-class.ymlのprovisionerと同じ値にする
            - name: PROVISIONER_NAME
              value: lab.hoge.jp/nfs
            # NFSサーバーのアドレス
            - name: NFS_SERVER
              value: xxx.xxx.xxx.xxx
            # NFSサーバーのmountするPATH
            - name: NFS_PATH
              value: /var/share/nfs
      # コンテナ外のmountの定義
      volumes:
        - name: nfs-client-root
          nfs:
            # NFSサーバーのアドレス
            server: xxx.xxx.xxx.xxx
            # NFSサーバーのmountするPATH
            path: /var/share/nfs

nfs-provisionerを作成

これでnfs-provisioner用のPodが作成される。

$ sudo kubectl apply -f storage-class.yml \
                     -f persitent-volumne-claim.yml \
                     -f rbac.yml \
                     -f deployment.yml
storageclass.storage.k8s.io/nfs created
persistentvolumeclaim/sample-pvc created
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
deployment.extensions/nfs-client-provisioner created

nfs-provisioner作成後確認

Pod, Deployment, ReplicaSetを確認

nfs-provisionerのPod, Deployment, ReplicaSetが作成されたことを確認。

$ sudo kubectl get all
NAME                                          READY   STATUS    RESTARTS   AGE
+pod/nfs-client-provisioner-657f86599c-xhfsm   1/1     Running   0          11s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   97m

NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
+deployment.apps/nfs-client-provisioner   1/1     1            1           11s

NAME                                                DESIRED   CURRENT   READY   AGE
+replicaset.apps/nfs-client-provisioner-657f86599c   1         1         1       11s

StorageClass, PersistentVolumeClaim, PersistentVolumeを確認

以下の用になっていることを確認

  • StorageClassが作成された。
  • PersistentVolumeClaimは作成されているがSTATUSがPendingのまま。
  • PersistentVolumeは作成されていない。
$ sudo kubectl get sc,pv,pvc
NAME                                             PROVISIONER                AGE
+storageclass.storage.k8s.io/nfs                  lab.hoge.jp/nfs            4m9s
storageclass.storage.k8s.io/standard (default)   k8s.io/minikube-hostpath   19m

NAME                               STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
+persistentvolumeclaim/sample-pvc   Pending                                      nfs            4m9s

mountされているか確認

nfs-provisionerコンテナ内から、NFSサーバーのmountしたディレクトリが見えるか確認。

NFSサーバーのmountする場所にテスト用ファイルを作成する。

$ sudo echo 'This is a sample.' > /var/share/nfs/sample.txt

作成されたnfs-client-provisionerのPodのNFS_PATHの中を確認すると、sample.txtが見える。

$ sudo kubectl exec -ti nfs-client-provisioner-657f86599c-xhfsm ls /persistentvolumes
sample.txt

$ sudo kubectl exec -ti nfs-client-provisioner-657f86599c-xhfsm cat /persistentvolumes/sample.txt
This is a sample.

これでnfs-provisionerの作成は完了。

Podを作成してNFSサーバーをmountする

次に、Podを作成して、nfs-provisionerを介してNFSサーバーの領域をmountする。

NFSサーバーのmountされるディレクトリのpermissionを変更

nfs-provisionerが、NFSサーバーのmountディレクトリの下に、nfsnobodyというユーザーでディレクトリを作成するため、権限を与える必要がある。

$ sudo chmod 777 /var/share/nfs

権限を与えないと、mount時にmkdirできずに以下のエラーが発生する。

$ sudo kubectl describe persistentvolumeclaim/sample-pvc
# **snip**
Events:
  Type       Reason                Age                   From                                                                                          Message
  ----       ------                ----                  ----                                                                                          -------
  Normal     Provisioning          101s (x4 over 3m26s)  lab.hoge.jp/nfs_nfs-client-provisioner-657f86599c-5mp5r_91c30fd0-922e-11e9-9954-0242c0a8f904  External provisioner is provisioning volume for claim "default/sample-pvc"
  Warning    ProvisioningFailed    101s (x4 over 3m26s)  lab.hoge.jp/nfs_nfs-client-provisioner-657f86599c-5mp5r_91c30fd0-922e-11e9-9954-0242c0a8f904  
failed to provision volume with StorageClass "nfs": unable to create directory to provision new pv: 
mkdir /persistentvolumes/default-sample-pvc-pvc-8ff59f6d-922e-11e9-afb4-fa163e42f6bd: permission denied

  Normal     ExternalProvisioning  9s (x16 over 3m29s)   persistentvolume-controller                                                                   waiting for a volume to be created, either by external provisioner "lab.hoge.jp/nfs" or manually created by system administrator
Mounted By:  <none>

Podを定義

pod.yml
kind: Pod
apiVersion: v1
metadata:
  name: nginx-pod
spec:
  # rbac.ymlのmetadata.nameと合わせる
  # これでRBACと関連付けられる
  serviceAccountName: nfs-client-provisioner
  containers:
  # Dockerコンテナの名前
  - name: nginx-container
    # 利用するDockerイメージ
    image: nginx
    # 公開するDockerコンテナのポート
    ports:
      - containerPort: 80
    # Dockerコンテナ内のmountポイント
    volumeMounts:
      # 以下のspec.volumes.nameと合わせる
      - name: nfs-pvc
        mountPath: "/mnt"
  # Never or OnFailure
  restartPolicy: OnFailure
  # mountする外部ストレージの設定
  volumes:
    # 上記のspec.containers.volumeMounts.nameと合わせる
    - name: nfs-pvc
      persistentVolumeClaim:
        # persitent-volumne-claim.ymlのmetadatal.nameと合わせる
        # これでPersistentVolumeClaimと関連付けられる
        claimName: sample-pvc

Podを作成

$ sudo kubectl apply -f pod.yml
pod/nginx-pod created

Pod確認

nginx-podというPodが作成されたことを確認。

$ sudo kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-657f86599c-xhfsm   1/1     Running   0          19m
+nginx-pod                                 1/1     Running   0          13s

PersistentVolumeClaim, PersistentVolumeを確認

以下の用になっていることを確認。

  • PersistentVolumeClaimのSTATUSがBoundになった。
  • PersistentVolumeが作成された。
$ sudo kubectl get pvc,pv
NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
+persistentvolumeclaim/sample-pvc   Bound    pvc-b3ee5521-9253-11e9-b851-fa163e42f6bd   1Gi        RWX            nfs            20m

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS   REASON   AGE
+persistentvolume/pvc-b3ee5521-9253-11e9-b851-fa163e42f6bd   1Gi        RWX            Retain           Bound    default/sample-pvc   nfs                     20m

describeすることでどこにmountされているのか分かる。

$ sudo kubectl describe persistentvolume/pvc-b3ee5521-9253-11e9-b851-fa163e42f6bd
Name:            pvc-b3ee5521-9253-11e9-b851-fa163e42f6bd
Labels:          <none>
Annotations:     pv.kubernetes.io/provisioned-by: lab.hoge.jp/nfs
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    nfs
Status:          Bound
Claim:           default/sample-pvc
Reclaim Policy:  Retain
Access Modes:    RWX
VolumeMode:      Filesystem
Capacity:        1Gi
Node Affinity:   <none>
Message:
Source:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    xxx.xxx.xxx.xxx
    Path:      /var/share/nfs/default-sample-pvc-pvc-b3ee5521-9253-11e9-b851-fa163e42f6bd
    ReadOnly:  false
Events:        <none>

mountされているか確認

NFSサーバーでの作業

NFSサーバーに以下のディレクトリが作成されている。

$ ls -l /var/share/nfs/
drwxrwxrwx 2 nfsnobody nfsnobody  6 Jun 19 14:33 default-sample-pvc-pvc-b3ee5521-9253-11e9-b851-fa163e42f6bd

作成されたディレクトリの下にテスト用ファイルを作成。

$ cd /var/share/nfs/default-sample-pvc-pvc-b3ee5521-9253-11e9-b851-fa163e42f6bd
$ echo 'This is a sample in PersistenVolume.' > persistent-volume.txt

Podを確認

Pod内のmountされたディレクトリを確認する。
NFSサーバーの/var/share/nfs/default-sample-pvc-pvc-b3ee5521-9253-11e9-b851-fa163e42f6bdの中と同じファイルが見えていればOK。

$ sudo kubectl exec -it nginx-pod ls /mnt
persistent-volume.txt

$ sudo kubectl exec -it nginx-pod cat /mnt/persistent-volume.txt
This is a sample in PersistenVolume.

関連記事

参考

21
15
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
21
15