やりたいこと
Kubernetes環境でCSI Snapshotで使用したい。調べてみると、Kubernetes 1.17段階ではSnapshot機能はBetaであり、対応しているストレージドライバも少ない。その中で使えそうなのはHost Path Driverだったので、これを使って構成してみる。
Kubernetesインストール
環境
Host OS: CentOS 7.6 (Minimum) x 1 (Master,worker兼用)
Kubernetes: 1.17
インストール
基本的には以下のサイトを参考に実施。
Steps for Installing Kubernetes on CentOS 7
手を加える必要のあったところ。
- 上から順番に進めると、kubeadm initの前にkubectl applyがあるが、そこは逆にする。
- /etc/sysctl.d/master_node_nameにiptablesの設定をいれるようになっているが、/etc/sysctl.confに入れないと読み取られなかった。
1に関しては、そうしないと以下のエラーで失敗する。
[root@base yum.repos.d]# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
The connection to the server localhost:8080 was refused - did you specify the right host or port?
2に関しては、以下のようにあるので、元のままでもよいように思うが…追及できていない。
# sysctl settings are defined through files in
# /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/.
エラーメッセージは以下。
[root@base yum.repos.d]# kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=10.118.37.193
W0116 13:07:26.298286 8566 validation.go:28] Cannot validate kube-proxy config - no validator is available
W0116 13:07:26.298297 8566 validation.go:28] Cannot validate kubelet config - no validator is available
[init] Using Kubernetes version: v1.17.1
[preflight] Running pre-flight checks
[WARNING Firewalld]: firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables contents are not set to 1
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher
シングルノード構成での注意
デフォルトでは、Masterノードはコンテナを実行しない設定になっているので、その解除が必要。
https://qiita.com/nykym/items/dcc572c21885543d94c8
[root@master-node csi-driver-host-path]# kubectl describe node master-node.devops.local
Name: master-node.devops.local
Roles: master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=master-node.devops.local
kubernetes.io/os=linux
node-role.kubernetes.io/master=
Annotations: flannel.alpha.coreos.com/backend-data: {"VtepMAC":"ca:e4:6a:bb:8f:3e"}
flannel.alpha.coreos.com/backend-type: vxlan
flannel.alpha.coreos.com/kube-subnet-manager: true
flannel.alpha.coreos.com/public-ip: 10.118.37.193
kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Thu, 16 Jan 2020 13:51:55 +0900
Taints: node-role.kubernetes.io/master:NoSchedule
以下のコマンドでTaintsの設定を変更する。
[root@master-node csi-driver-host-path]# kubectl taint nodes master-node.devops.local node-role.kubernetes.io/master:NoSchedule-
node/master-node.devops.local untainted
設定しないと、SystemのNamespaceでないpodはPendingになる(以下は失敗例)。
[root@master-node csi-driver-host-path]# kubectl describe snapshot-controller-0
Name: snapshot-controller-0
Namespace: default
Priority: 0
Node: <none>
Labels: app=snapshot-controller
controller-revision-hash=snapshot-controller-66b4bc9b7d
statefulset.kubernetes.io/pod-name=snapshot-controller-0
Annotations: <none>
Status: Pending
IP:
IPs: <none>
Controlled By: StatefulSet/snapshot-controller
Containers:
snapshot-controller:
Image: quay.io/k8scsi/snapshot-controller:v2.0.0-rc4
Port: <none>
Host Port: <none>
Args:
--v=5
--leader-election=false
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from snapshot-controller-token-g4mr9 (ro)
Conditions:
Type Status
PodScheduled False
Volumes:
snapshot-controller-token-g4mr9:
Type: Secret (a volume populated by a Secret)
SecretName: snapshot-controller-token-g4mr9
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 86s (x36 over 51m) default-scheduler 0/1 nodes are available: 1 node(s) had taints that the pod didn't tolerate.
HostPath driver
基本的にはこちらのgithubレポジトリのREADMEを参考に実施。
https://github.com/kubernetes-csi/csi-driver-host-path
ただし、前提条件の記載やスナップショット作成用のyamlが上記レポジトリのものでは動かなかったので、以下も参考にした。
https://kubernetes.io/blog/2019/12/09/kubernetes-1-17-feature-cis-volume-snapshot-beta/
まずは前提となる以下をインストールする。
- Kubernetes Volume Snapshot CRDs
- Volume snapshot controller
[root@master-node gitrepo]# git clone https://github.com/kubernetes-csi/external-snapshotter.git
[root@master-node gitrepo]# cd external-snapshotter/
[root@master-node external-snapshotter]# ls config/crd/
snapshot.storage.k8s.io_volumesnapshotclasses.yaml snapshot.storage.k8s.io_volumesnapshotcontents.yaml snapshot.storage.k8s.io_volumesnapshots.yaml
[root@master-node external-snapshotter]# kubectl create -f config/crd
customresourcedefinition.apiextensions.k8s.io/volumesnapshotclasses.snapshot.storage.k8s.io created
customresourcedefinition.apiextensions.k8s.io/volumesnapshotcontents.snapshot.storage.k8s.io created
customresourcedefinition.apiextensions.k8s.io/volumesnapshots.snapshot.storage.k8s.io created
[root@master-node external-snapshotter]#
[root@master-node external-snapshotter]#
[root@master-node external-snapshotter]# kubectl create -f deploy/kubernetes/snapshot-controller
serviceaccount/snapshot-controller created
clusterrole.rbac.authorization.k8s.io/snapshot-controller-runner created
clusterrolebinding.rbac.authorization.k8s.io/snapshot-controller-role created
role.rbac.authorization.k8s.io/snapshot-controller-leaderelection created
rolebinding.rbac.authorization.k8s.io/snapshot-controller-leaderelection created
statefulset.apps/snapshot-controller created
[root@master-node external-snapshotter]#
次に、HostPathドライバー本体をインストール。
[root@master-node ~]# mkdir gitrepo
[root@master-node ~]# cd gitrepo/
[root@master-node gitrepo]#
[root@master-node gitrepo]# yum install -y git
[root@master-node gitrepo]# git clone https://github.com/kubernetes-csi/csi-driver-host-path.git
[root@master-node gitrepo]# cd csi-driver-host-path/
[root@master-node csi-driver-host-path]# deploy/kubernetes-1.17/deploy-hostpath.sh
ボリューム作成
[root@master-node csi-driver-host-path]# for i in ./examples/csi-storageclass.yaml ./examples/csi-pvc.yaml ./examples/csi-app.yaml; do kubectl apply -f $i; done
storageclass.storage.k8s.io/csi-hostpath-sc created
persistentvolumeclaim/csi-pvc created
pod/my-csi-app created
[root@master-node csi-driver-host-path]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-93a40c63-0eab-47c8-92ee-34f8db56f125 1Gi RWO Delete Bound default/csi-pvc csi-hostpath-sc 22h
[root@master-node csi-driver-host-path]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
csi-pvc Bound pvc-93a40c63-0eab-47c8-92ee-34f8db56f125 1Gi RWO csi-hostpath-sc 22h
[root@master-node csi-driver-host-path]#
スナップショット作成
[root@master-node csi-driver-host-path]# kubectl apply -f examples/csi-snapshot.yaml
error: error validating "examples/csi-snapshot.yaml": error validating data: [ValidationError(VolumeSnapshot.spec): unknown field "snapshotClassName" in io.k8s.storage.snapshot.v1beta1.VolumeSnapshot.spec, ValidationError(VolumeSnapshot.spec.source): unknown field "kind" in io.k8s.storage.snapshot.v1beta1.VolumeSnapshot.spec.source, ValidationError(VolumeSnapshot.spec.source): unknown field "name" in io.k8s.storage.snapshot.v1beta1.VolumeSnapshot.spec.source]; if you choose to ignore these errors, turn validation off with --validate=false
ここで失敗した理由は、exampleにあるsnapshot作成のyamlのパラメータ名などが違った。正しくは以下。
apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshot
metadata:
name: new-snapshot-demo
spec:
volumeSnapshotClassName: csi-hostpath-snapclass
source:
persistentVolumeClaimName: csi-pvc
[root@master-node csi-driver-host-path]# kubectl apply -f examples/csi-snapshot.yaml
volumesnapshot.snapshot.storage.k8s.io/new-snapshot-demo created
[root@master-node csi-driver-host-path]# kubectl get volumesnapshot
NAME AGE
new-snapshot-demo 105s
リストア
リストアする際はスナップショットを元に新しいボリューム(PVC)を作成し、それを使用する形になる。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: hpvc-restore
spec:
storageClassName: csi-hostpath-sc
dataSource:
name: new-snapshot-demo
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
kind: Pod
apiVersion: v1
metadata:
name: my-csi-app-with-snapshot-2
spec:
containers:
- name: my-frontend-2
image: busybox
volumeMounts:
- mountPath: "/data"
name: my-csi-volume
command: [ "sleep", "1000000" ]
volumes:
- name: my-csi-volume
persistentVolumeClaim:
claimName: hpvc-restore
テストとして、スナップショットが作成された状態から、ソースボリューム内のテストファイルを削除し、
スナップショットから生成したボリュームにファイルが残っていることを確認する。
[root@master-node csi-driver-host-path]# kubectl apply -f examples/csi-restore.yaml
persistentvolumeclaim/hpvc-restore created
[root@master-node csi-driver-host-path]# kebeubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
csi-pvc Bound pvc-93a40c63-0eab-47c8-92ee-34f8db56f125 1Gi RWO csi-hostpath-sc 23h
hpvc-restore Bound pvc-a636c44c-77b8-49a2-bc27-dafd32d30406 1Gi RWO csi-hostpath-sc 8s
[root@master-node csi-driver-host-path]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-93a40c63-0eab-47c8-92ee-34f8db56f125 1Gi RWO Delete Bound default/csi-pvc csi-hostpath-sc 23h
pvc-a636c44c-77b8-49a2-bc27-dafd32d30406 1Gi RWO Delete Bound default/hpvc-restore csi-hostpath-sc 10s
[root@master-node csi-driver-host-path]# cp -p kubectl exec -it my-csi-app /bin/sh
/ # / #
/ #
/ #
/ #
/ # ls /data/ # ls /data// # ls /data/hello-world
/data/hello-world
/ # rm /data/hello-world
/ # ls /data/
/ #
/ #
/ # exit
[root@master-node csi-driver-host-path]# kubectl apply -f csi-app_changeVolume.yaml
pod/my-csi-app-with-snapshot-2 created
[root@master-node csi-driver-host-path]# kubectl exec -it my-csi-app-with-snapshot-2 /bin/sh
/ # / #
/ #
/ # ls /da/ # ls /data/
hello-world
/ # / # ls /data/he/ # ls /data/hello-world
/data/hello-world
/ # cat /data/hello-world
詳しく見る
PVCとは
A PersistentVolumeClaim (PVC) is a request for storage by a user. It is similar to a Pod. Pods consume node resources and PVCs consume PV resources. Pods can request specific levels of resources (CPU and Memory). Claims can request specific size and access modes (e.g., they can be mounted once read/write or many times read-only).
すなわち、PVCとはどのようなボリュームが欲しいか、を記載した定義であって、実際に使用されるボリューム(PV)はこの定義に沿ってStorage Classから割り当てられる。
Storage Classとは
A StorageClass provides a way for administrators to describe the “classes” of storage they offer. Different classes might map to quality-of-service levels, or to backup policies, or to arbitrary policies determined by the cluster administrators. Kubernetes itself is unopinionated about what classes represent. This concept is sometimes called “profiles” in other storage systems.
Storage Classとはどのようなストレージからボリュームを払い出すか、を記載した定義。
provisionerというパラメータを持ち、そこでどのプラグイン(バックエンド)からストレージの提供を受けるかが定義される。
実際どのように定義されているか
csi-appというpodは、my-csi-volumeというPVCを/dataにマウントしている。
my-csi-volume自体は同じyaml内で定義されていて、csi-pvcという名前のPersistent Volume Claim(PVC)に対してつけた名前(ラベル)。
kind: Pod
apiVersion: v1
metadata:
name: my-csi-app
spec:
containers:
- name: my-frontend
image: busybox
volumeMounts:
- mountPath: "/data"
name: my-csi-volume
command: [ "sleep", "1000000" ]
volumes:
- name: my-csi-volume
persistentVolumeClaim:
claimName: csi-pvc
csi-pvcというPVCは以下のyamlで定義されている。サイズと読み書き権限について記載がある。また元になるStorage Classについて指定がある。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: csi-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: csi-hostpath-sc
Storage Classについては以下で定義されている。provisionerとして、hostpathを使用している。
hostpath.csi.k8s.ioは、HostPathドライバのインストール時(deploy/kubernetes-1.17/deploy-hostpath.sh)に構成される。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-hostpath-sc
provisioner: hostpath.csi.k8s.io
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true
HostPathドライバは以下のように設定されており、ボリュームの実体の置き場所も記載されている。
[root@master-node csi-driver-host-path]# kubectl describe pod csi-hostpathplugin-0
Volumes:
csi-data-dir:
Type: HostPath (bare host directory volume)
Path: /var/lib/csi-hostpath-data/
HostPathType: DirectoryOrCreate
[root@master-node csi-driver-host-path]# ls /var/lib/csi-hostpath-data/
af6400b6-391a-11ea-9916-669818be6e8d dd805657-3919-11ea-9916-669818be6e8d.tgz e2df0611-3854-11ea-9916-669818be6e8d
[root@master-node csi-driver-host-path]# ls /var/lib/csi-hostpath-data/af6400b6-391a-11ea-9916-669818be6e8d/
hello-world
[root@master-node csi-driver-host-path]# ls /var/lib/csi-hostpath-data/e2df0611-3854-11ea-9916-669818be6e8d/