Storage

В данном практическом занятии рассмотрим работу с постоянным хранилищем посредством ресурсов PersistentVolume, PersistentVolumeClaim и StorageClass.

Persistent Volume

Создадим ресурс PersistentVolume, который будет использовать файловую систему хоста, на котором он будет расположен.

$ k apply -f - << EOF
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-volume
spec:
  storageClassName: manual
  capacity:
    storage: 100Mi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"
EOF

В данном примере в параметрах указано:

  • storageClassName: manual - имя StorageClass, указано явно для будущего связывания с pvc

  • capacity.storage - размер тома

  • accessModes - режим подключения тома к подам

  • hostPath.path - путь на ноде, по которому будут храниться данные

После создания можно увидеть его состояние:

$ k get pv
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-volume   100Mi      RWO            Retain           Available           manual                  12s

Также из вывода видно, что reclaim policy задано как Retain, означающая, что после удаления pv данные в нем не будут удалены. А также status - Available, означающий, что том готов к подключению.

Persistent Volume Claim

Теперь необходимо создать ресурс PersistentVolumeClaim, который можно рассматривать как запрос на том с определенными характеристиками(размер, параметры доступа, тип хранилища и т.д.), который можно использовать непосредственно в поде.

$ k apply -f - << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 50Mi
EOF

После создания можно увидеть состояние pvc:

$ k get pvc
NAME       STATUS   VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pv-claim   Bound    pv-volume   100Mi      RWO            manual         2s

Можно заметить интересную особенность: при создании pvc мы указали требуемый нам размер - 50Mi, при этом параметр capacity - 100Mi. Дело в том, что при создании pvc ищется любой подходящий по параметрам pv, в том числе большего размера. Если теперь посмотреть список pv, то мы увидим, что он теперь связан с созданным pvc:

$ k get pv
NAME      CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM            STORAGECLASS REASON AGE
pv-volume 100Mi    RWO          Retain         Bound  default/pv-claim manual              21m

PVC in Pod

Теперь созданный pvc можно использовать в параметре spec.volumes пода:

$ k apply -f - << EOF
apiVersion: v1
kind: Pod
metadata:
  name: pv-pod
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - mountPath: "/usr/share/nginx/html"
      name: pv-storage
  volumes:
  - name: pv-storage
    persistentVolumeClaim:
      claimName: pv-claim
EOF

После создания можно создать файл в нашем pv выполнив команду внутри контейнера:

$ k exec -it pv-pod -- /bin/sh -c 'echo "hello" > /usr/share/nginx/html/index.html'

Далее можно убедиться, что файл корректно создан обратившись к nginx либо через port-forward, либо с использованием Service и Ingress. Также можно воспользоваться специальным сабресурсом /proxy у пода, сделав запрос через api kubernetes:

$ k get --raw /api/v1/namespaces/default/pods/pv-pod/proxy
hello

Создадим еще один под, который также будет использовать данный pvc:

$ k apply -f - << EOF
apiVersion: v1
kind: Pod
metadata:
  name: pv-pod-new
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - mountPath: "/usr/share/nginx/html"
      name: pv-storage
  volumes:
  - name: pv-storage
    persistentVolumeClaim:
      claimName: pv-claim
EOF

После его запуска также сделаем запрос к nginx:

$ k get po
NAME         READY   STATUS    RESTARTS   AGE
pv-pod       1/1     Running   0          11m
pv-pod-new   1/1     Running   0          10s
$ k get --raw /api/v1/namespaces/default/pods/pv-pod-new/proxy
hello

Как видно, под запустился и также смонтировал данный том не смотря на режим ReadWriteOnce. Это связано с тем, что режим ReadWriteOnce позволяет монтировать pv, если поды находятся на одной ноде. Если требуется запретить данную возможность, то существует режим ReadWriteOncePod.

Также можем удалить созданные нами ресурсы и убедиться, что данные остались на ноде согласно политике Retain:

$ k delete pvc --all
persistentvolumeclaim "pv-claim" deleted
$ k delete pv --all
persistentvolume "pv-volume" deleted
$ k delete po --all
pod "pv-pod" deleted
pod "pv-pod-new" deleted
$ docker exec  -it kind-control-plane /bin/sh -c 'cat /mnt/data/index.html'
hello

Storage Class

В kind при создании кластера также устанавливается local-path-provisioner, который позволяет динамически нарезать pv на нодах. Для их использования создается StorageClass:

$ k get sc
NAME               PROVISIONER           RECLAIMPOLICY VOLUMEBINDINGMODE    ALLOWVOLUMEEXPANSION AGE
standard (default) rancher.io/local-path Delete        WaitForFirstConsumer false                14d

Так как данный Storage Class используется по умолчанию, то можно создавать pvc без указания параметра storageClassName. Таким образом нам достаточно создать pvc и под, а pv создастся автоматически:

$ k apply -f - << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-claim-sc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 150Mi
---
apiVersion: v1
kind: Pod
metadata:
  name: pv-pod-sc
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - mountPath: "/usr/share/nginx/html"
      name: pv-storage
  volumes:
  - name: pv-storage
    persistentVolumeClaim:
      claimName: pv-claim-sc
EOF
$ k get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   REASON   AGE
pvc-828145c8-2e48-4046-b96f-d3cadbece5d8   150Mi      RWO            Delete           Bound    default/pv-claim-sc   standard                28s

$ k get pvc
NAME          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pv-claim-sc   Bound    pvc-828145c8-2e48-4046-b96f-d3cadbece5d8   150Mi      RWO            standard       36s
$ k get po
NAME        READY   STATUS    RESTARTS   AGE
pv-pod-sc   1/1     Running   0          38s