LoginSignup
73
62

More than 5 years have passed since last update.

Kubernetes のストレージについて調べる

Posted at

作業メモ。

Kubernetes完全ガイド impress top gearシリーズを読みながら手元で確認した時のメモ。

環境

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.3", GitCommit:"2bba0127d85d5a46ab4b778548be28623b32d0b0", GitTreeState:"clean", BuildDate:"2018-05-28T20:03:09Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"11+", GitVersion:"v1.11.5-eks-6bad6d", GitCommit:"6bad6d9c768dc0864dab48a11653aa53b5a47043", GitTreeState:"clean", BuildDate:"2018-12-06T23:13:14Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}

Kubernetes 環境としては EKS を利用。

Volume/PersistentVolume(PV)/PersistentVolumeClaim(PVC)の違い

Volume

Volume は予め用意されたボリュームをマニュフェストに直接指定することで利用可能となる。そのため、Kubernetes 上で新規にボリュームを作成したり、既存のボリュームを削除することは出来ない。例えば Node 上の任意のパスをマウントすること出来たりする。

PersistentVolume(PV)

PersistentVolume(以降 PV) は永続化領域として確保される Volume。
PV は個別にリソースを作成して利用する必要があり、後述する PersistentVolumeClaim(以降 PVC)経由で利用する。

PersistentVolumeClaim(PVC)

Claim(要求する)という意味の通り、作成された PV リソースからアサインするためのリソース。PV はクラスタにボリュームを登録するだけなので Pod から利用する場合には PVC を定義する必要がある。
また、Dynamic プロビジョニングを行うことで事前に PV を作成せず、PVC が作成された際に動的に PV を作成する事ができる。

以降ではそれぞれを試してみる。

Volume

Volumes

Kubernetes では Volume を抽象化して Pod と疎結合なりソースとして定義している。様々な種類が提供されており、クラウドサービスのボリュームもサポートされている。

Types of Volumes

今回は Pod 用の一時的なディスクとして利用可能な emptyDir とホスト(ノード)の任意のパスをマウントできる hostPath を使ってみる。

emptyDir

emptyDir

emptyDir は Pod 用の一時的なディスク領域として利用可能であり、Pod が terminate されると削除される。

以下のマニュフェストで試す。

emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}
$kubectl apply -f emptydir.yaml
pod "test-pd" created

# エラー
$kubectl exec -it test-pd -- /bin/sh
rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:262: starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory"

command terminated with exit code 126

Scratch から作っているので /bin/sh もないみたい。

kubernetes/test/images/test-webserver/Dockerfile

image を nginx にしてから再度 apply.

# /cache がマウントされている
$kubectl exec -it test-pd -- df -h
Filesystem      Size  Used Avail Use% Mounted on
overlay          20G  3.4G   17G  17% /
tmpfs           1.9G     0  1.9G   0% /dev
tmpfs           1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/nvme0n1p1   20G  3.4G   17G  17% /cache
shm              64M     0   64M   0% /dev/shm
tmpfs           1.9G   12K  1.9G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs           1.9G     0  1.9G   0% /sys/firmware

# テストファイルを作成
$ kubectl exec -it test-pd -- touch /cache/test.txt

# ファイルが存在する
$kubectl exec -it test-pd -- ls /cache/
test.txt

# Pod を削除
$kubectl delete -f emptydir.yaml
pod "test-pd" deleted

# 再作成
$kubectl apply -f emptydir.yaml
pod "test-pd" created

# ファイルはない
$kubectl exec -it test-pd -- ls /cache/

hostPath

hostPath

hostPath を利用することで Kubernetest ノード(ホスト)の任意の領域をマウントできる。
以下では /tmp をマウントしてみる

hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: nginx
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # directory location on host
      path: /tmp
      # this field is optional
      type: Directory
$ kubectl apply -f hostpath.yaml
pod "test-pd" created

# /test-pd にマウント
$kubectl exec -it test-pd -- df -h
Filesystem      Size  Used Avail Use% Mounted on
overlay          20G  3.4G   17G  17% /
tmpfs           1.9G     0  1.9G   0% /dev
tmpfs           1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/nvme0n1p1   20G  3.4G   17G  17% /test-pd
shm              64M     0   64M   0% /dev/shm
tmpfs           1.9G   12K  1.9G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs           1.9G     0  1.9G   0% /sys/firmware

# ファイルを作成
$kubectl exec -it test-pd -- touch /test-pd/test.txt

# ファイルが存在
$kubectl exec -it test-pd -- ls /test-pd/
systemd-private-857b4e69b79c4039a8d0e50db7fa36bd-chronyd.service-zdQfQx
test.txt

# Pod が動作している Node を確認
$kubectl describe pod test-pd |grep Node
Node:               ip-172-31-0-56.ap-northeast-1.compute.internal/172.31.0.56
Node-Selectors:  <none>

# Pod を削除
$ kubectl delete pod test-pd
pod "test-pd" deleted

# Node にSSH ログインして /tmp を確認するとファイルが確認できる。Pod が削除されてもファイルは消えない
$ls /tmp/
systemd-private-857b4e69b79c4039a8d0e50db7fa36bd-chronyd.service-zdQfQx
test.txt

上記のように Pod が削除されても Node のファイルは削除されない。
ただし、Node が複数存在する場合、再度 Pod を起動した場合に同じ Node 上で動作するかは分からない。

PersistentVolume(PV)

Persistent Volumes

PersistentVolume(PV) は永続化領域として確保される Volume。
PV は個別にリソースを作成して利用する必要があり、後述する PersistentVolumeClaim(PVC)経由で利用する。

今回は PV を個別に作成する。
自分の実行環境が AWS なので以下を見て試す。

Persistent Storage Using AWS Elastic Block Store

# 予め EBS を作成
$aws ec2 create-volume --size=10 --volume-type=gp2 --availability-zone ap-northeast-1c
{
    "AvailabilityZone": "ap-northeast-1c",
    "CreateTime": "2019-01-01T21:59:55.000Z",
    "Encrypted": false,
    "Size": 5,
    "SnapshotId": "",
    "State": "creating",
    "VolumeId": "vol-0af3eacd9228e23a0",
    "Iops": 100,
    "Tags": [],
    "VolumeType": "gp2"
}

上記で作成した volume-id を利用してマニュフェストファイルを作成する。

pv.yaml
apiVersion: "v1"
kind: "PersistentVolume"
metadata:
  name: "pv0001"
spec:
  capacity:
    storage: "5Gi"
  accessModes:
    - "ReadWriteOnce"
  awsElasticBlockStore:
    fsType: "ext4"
    volumeID: "vol-0af3eacd9228e23a0"

上記を apply して作成する。

# pv を作成
$ kubectl apply -f pv.yaml
persistentvolume "pv0001" created

# pv リソースが存在する
$kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
pv0001    10Gi       RWO            Retain           Available                                      6s                                     14s

なお、上記場合、pv リソースを削除しても EBS は削除されないので別途削除が必要。

# pv を削除
$kubectl delete pv pv0001
persistentvolume "pv0001" deleted

# pv は削除済み
$ kubectl get pv
No resources found.

# EBS は削除されない 
$aws ec2 describe-volumes --volume-ids vol-0af3eacd9228e23a0
{
    "Volumes": [
        {
            "Attachments": [],
            "AvailabilityZone": "ap-northeast-1c",
            "CreateTime": "2019-01-01T21:59:55.943Z",
            "Encrypted": false,
            "Size": 10,
            "SnapshotId": "",
            "State": "available",
            "VolumeId": "vol-0af3eacd9228e23a0",
            "Iops": 100,
            "VolumeType": "gp2"
        }
    ]
}

# 必要に応じて削除する
$aws ec2 delete-volume --volume-id vol-0af3eacd9228e23a0

# 削除確認
$ aws ec2 describe-volumes --volume-ids vol-0af3eacd9228e23a0

An error occurred (InvalidVolume.NotFound) when calling the DescribeVolumes operation: The volume 'vol-0af3eacd9228e23a0' does not exist.

PersistentVolumeClaim(PVC)

PersistentVolumeClaims

PVC は PV の要求を行うリソース。
前途の PV は PVC 経由でマニュフェストから要求され、利用する。
PVC は要求された内容(容量、ラベル)から適切な PV を探し、Volume を割り当てる。

プロビジョニングの方法として2種類あり、前途のように予め PV を作成する方法を Static、PVC が作成(つまり Volume の要求があった)際に動的に PV を作成する Dynamic の2種類がある。

Dynamic を利用することで事前に PV や必要なストレージ(EBSなど)を作る手間を省くことが出来る。
今回は上記 Dynamic のプロビジョニングを試す。

StorageClass を作成する

Storage Classes

PVC をマニュフェストに記載する際に StorageClass を指定する。
StorageClass ではどの Provider(GCEPersistentDisk なのか AWSElasticBlockStore なのかなど)であるかなど利用の際の設定を記載する。

EKS では gp2 という StorageClass が予め作成されている。

ストレージクラス

$kubectl describe storageclass gp2
Name:            gp2
IsDefaultClass:  Yes
Annotations:     kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"},"name":"gp2","namespace":""},"parameters":{"fsType":"ext4","type":"gp2"},"provisioner":"kubernetes.io/aws-ebs"}
,storageclass.kubernetes.io/is-default-class=true
Provisioner:           kubernetes.io/aws-ebs
Parameters:            fsType=ext4,type=gp2
AllowVolumeExpansion:  <unset>
MountOptions:          <none>
ReclaimPolicy:         Delete
VolumeBindingMode:     Immediate
Events:                <none>

別途 StorageClass の作成なども可能だが今回は上記を利用する。

PVC を作成する

PVC を作成してみる。

pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi
  storageClassName: gp2
# pvc を作成
$kubectl apply -f pvc.yaml
persistentvolumeclaim "myclaim" created

# pvc を確認
$kubectl get pvc
NAME      STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myclaim   Bound     pvc-9a73a51a-0ed3-11e9-b090-0ae6cc179478   8Gi        RWO            gp2            1m

# 少し時間が経つと pv も作成される
$kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM             STORAGECLASS   REASON    AGE
pvc-9a73a51a-0ed3-11e9-b090-0ae6cc179478   8Gi        RWO            Delete           Bound     default/myclaim   gp2                      1m

# describe すると詳細が分かる
$kubectl describe pv pvc-9a73a51a-0ed3-11e9-b090-0ae6cc179478
Name:            pvc-9a73a51a-0ed3-11e9-b090-0ae6cc179478
Labels:          failure-domain.beta.kubernetes.io/region=ap-northeast-1
                 failure-domain.beta.kubernetes.io/zone=ap-northeast-1c
Annotations:     kubernetes.io/createdby=aws-ebs-dynamic-provisioner
                 pv.kubernetes.io/bound-by-controller=yes
                 pv.kubernetes.io/provisioned-by=kubernetes.io/aws-ebs
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    gp2
Status:          Bound
Claim:           default/myclaim
Reclaim Policy:  Delete
Access Modes:    RWO
Capacity:        8Gi
Node Affinity:   <none>
Message:
Source:
    Type:       AWSElasticBlockStore (a Persistent Disk resource in AWS)
    VolumeID:   aws://ap-northeast-1c/vol-05129125c1e7e8696
    FSType:     ext4
    Partition:  0
    ReadOnly:   false
Events:         <none>

# volume id から EBS を確認.Tag に Kubernetes の情報が記載されている
$ aws ec2 describe-volumes --volume-ids vol-05129125c1e7e8696
{
    "Volumes": [
        {
            "Attachments": [],
            "AvailabilityZone": "ap-northeast-1c",
            "CreateTime": "2019-01-02T21:16:15.189Z",
            "Encrypted": false,
            "Size": 8,
            "SnapshotId": "",
            "State": "available",
            "VolumeId": "vol-05129125c1e7e8696",
            "Iops": 100,
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "kubernetes-dynamic-pvc-9a73a51a-0ed3-11e9-b090-0ae6cc179478"
                },
                {
                    "Key": "kubernetes.io/created-for/pvc/name",
                    "Value": "myclaim"
                },
                {
                    "Key": "kubernetes.io/created-for/pv/name",
                    "Value": "pvc-9a73a51a-0ed3-11e9-b090-0ae6cc179478"
                },
                {
                    "Key": "kubernetes.io/created-for/pvc/namespace",
                    "Value": "default"
                },
                {
                    "Key": "kubernetes.io/cluster/eks-first-cluster",
                    "Value": "owned"
                }
            ],
            "VolumeType": "gp2"
        }
    ]
}

Pod から利用する

Claims As Volumes

Pod から PVC つまりボリュームを利用する場合、claimName を指定する。

kind: Pod
apiVersion: v1
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: nginx
      volumeMounts:
      - mountPath: "/var/www/html"
        name: mypd
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: myclaim
# pod を作成
$ kubectl apply -f pod-pvc.yaml
pod "mypod" created

# Pod では /var/www/html がマウントされており、pvc で要求した 8G
$kubectl exec -it mypod -- df -h
Filesystem      Size  Used Avail Use% Mounted on
overlay          20G  3.4G   17G  17% /
tmpfs           1.9G     0  1.9G   0% /dev
tmpfs           1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/nvme0n1p1   20G  3.4G   17G  17% /etc/hosts
shm              64M     0   64M   0% /dev/shm
/dev/nvme1n1    7.8G   36M  7.7G   1% /var/www/html
tmpfs           1.9G   12K  1.9G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs           1.9G     0  1.9G   0% /sys/firmware

# pod が動いている node を確認
$ kubectl describe pod mypod |grep Node
Node:               ip-172-31-0-56.ap-northeast-1.compute.internal/172.31.0.56
Node-Selectors:  <none>

# 該当する EC2 の BlockDeviceMappings を確認.pvc より作成された volume vol-05129125c1e7e8696 が EC2 にアタッチされている
$aws ec2 describe-instances --filters "Name=network-interface.addresses.private-ip-address,Values=172.31.0.56"
()
                   "Architecture": "x86_64",
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/xvda",
                            "Ebs": {
                                "AttachTime": "2018-12-20T02:33:55.000Z",
                                "DeleteOnTermination": true,
                                "Status": "attached",
                                "VolumeId": "vol-0347b33bce60e7776"
                            }
                        },
                        {
                            "DeviceName": "/dev/xvdbb",
                            "Ebs": {
                                "AttachTime": "2019-01-02T21:27:04.000Z",
                                "DeleteOnTermination": false,
                                "Status": "attached",
                                "VolumeId": "vol-05129125c1e7e8696"
                            }
                        }
                    ],

リソースを削除する

検証が終わったので削除しつつ、挙動を確認する。

# Pod を削除
$kubectl delete pod mypod
pod "mypod" deleted

# EBS が EC2 からデタッチされている
$ aws ec2 describe-instances --filters "Name=network-interface.addresses.private-ip-address,Values=172.31.0.56"
()
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/xvda",
                            "Ebs": {
                                "AttachTime": "2018-12-20T02:33:55.000Z",
                                "DeleteOnTermination": true,
                                "Status": "attached",
                                "VolumeId": "vol-0347b33bce60e7776"
                            }
                        }
                    ],

# EC2 からでタッチされているが EBS は存在する
$aws ec2 describe-volumes --volume-ids vol-05129125c1e7e8696 |grep State
            "State": "available",

# pvc を削除
$kubectl delete pvc myclaim
persistentvolumeclaim "myclaim" deleted

# pv も削除される
$ kubectl get pv
No resources found.

# EBS も削除される
$aws ec2 describe-volumes --volume-ids vol-05129125c1e7e8696

An error occurred (InvalidVolume.NotFound) when calling the DescribeVolumes operation: The volume 'vol-05129125c1e7e8696' does not exist.

上記のように PVC が削除された際に EBS も削除される挙動は StorageClass の ReclaimPolicy が Delete であるため。
ReclaimPoliyc を Retain にすれば EBS は削除されない。

73
62
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
73
62