unbound immediate PersistentVolumeClaims

2021年10月05日2021年10月07日

本番で稼働しているkubernetes環境と同じk8sをローカルにも構築したくて奮闘したお話です。
簡単に纏めるとmanifestで実在しないstorageClassを指定していたことが原因でした。

環境

  • macos
  • docker-kubernetes v1.21.1


エラー内容

$ kubectl get pod -n logging
NAME          READY   STATUS    RESTARTS   AGE
kafka-0       0/1     Pending   0          3h33m

これだと何が原因か分かりづらいので詳細を確認します。

PODを確認

$ kubectl describe pod -n logging kafka-0

~~~~~PODの情報が色々出力されている~~~~~

Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  33s (x2 over 35s)  default-scheduler  0/1 nodes are available: 1 pod has unbound immediate PersistentVolumeClaims.

最後にEventsが出力されていますが内容的には、PVCの準備に失敗している感じがします。

PVCを確認

$ kubectl get pvc -n logging             
NAME           STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
data-kafka-0   Pending                                      ssd            91s


こちらも同じようにPendingなので詳細を確認します。

$ kubectl describe pvc -n logging data-kafka-0

~~~~~PVCの情報が色々出力されている~~~~~

Events:
  Type     Reason              Age                 From                         Message
  ----     ------              ----                ----                         -------
  Warning  ProvisioningFailed  29s (x2 over 2m8s)  persistentvolume-controller  Failed to provision volume with StorageClass "ssd": failed to get GCE GCECloudProvider with error <nil>


ssdというStorageClassをmanifestで指定しているようですね。
今回はローカルで構築しているのでdefaultのStorageClassを利用するように変更します。

StorageClassを確認

$ kubectl get sc                             
NAME                 PROVISIONER            RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
hostpath (default)   docker.io/hostpath     Delete          Immediate           false                  7m48s


defaultが設定されているのでPVCでは、StorageClassを指定しなくても使用することができます。

PVCのstorage-classの定義を削除

# manifest
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: kafka
  namespace: logging

~~~~~PODの情報を色々定義している~~~~~

  volumeClaimTemplates:
  - metadata:
      name: data
#      annotations:
#        volume.beta.kubernetes.io/storage-class: "ssd"
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

コメントアウトしている部分が今回削除したところです。

StatefulSetの削除

PVCの定義情報を変更したため、StatefulSetを削除しておきます。

$ kubectl delete sts -n logging kafka  
statefulset.apps "kafka" deleted


ちなみにstsを削除せずにapplyだけすると怒られます。
怖いコワイ。

$ kubectl apply -f kafka/30-statefulset.yml 
The StatefulSet "kafka" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'template', and 'updateStrategy' are forbidden


PVCの削除

PVCもssdからローカルのdefaultに変更するため、削除しておきます。

$ kubectl delete pvc -n logging data-kafka-0               
persistentvolumeclaim "data-kafka-0" deleted


再apply

$ kubectl apply -f kafka.yml 
statefulset.apps/kafka created


しばらくするとkafkaが立ち上がります。

$ kubectl get pod -n logging    
NAME          READY   STATUS    RESTARTS   AGE
kafka-0       1/1     Running   4          4m57s
kafka-1       1/1     Running   4          4m51s
kafka-2       1/1     Running   5          4m43s


PVCとは

manifestにvolumeClaimTemplatesを定義しておくと、勝手にPVも作ってくれる優れものです。
annotationsを定義することでStorageClassを指定することができます。

  volumeClaimTemplates:
  - metadata:
      name: data
#      annotations:
#        volume.beta.kubernetes.io/storage-class: "ssd"
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi


PVの定義もmanifestに含めることができるのが利点ですね。

$ kubectl get pv                
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                      STORAGECLASS   REASON   AGE
pvc-9829216c-ea0d-49dc-bc9e-2d6ee4d7e2a7   1Gi        RWO            Delete           Bound    logging/data-kafka-1       hostpath                16m
pvc-abe043dc-e26f-4ce3-a3e5-0818b2ed5694   1Gi        RWO            Delete           Bound    logging/data-kafka-2       hostpath                15m
pvc-ef598b49-8924-4a3e-8ad3-3df62e9d0403   1Gi        RWO            Delete           Bound    logging/data-kafka-0       hostpath                16m


まとめ

なんかkubernetesのエラーハンドリングみたいになりましたが、ローカルではdefaultのStorageClassを使うのがいいなと思いました。
(provisionerをローカル用に変更すれば良いだけなんですけどね。)
PVCはPVを勝手に作るボリューム定義書と覚えればいいでしょう。

このブログではインフラや情シスのさりげない日常を記録しています。
お困りごとも相談にのりますので、お問い合わせフォームからお気軽にお問い合わせください。