Маємо Helm-чарт VictoriaLogs, в якому заданий PVC з розміром в 30 GB, якого нам стало вже замало, і його треба збільшити.
Але проблема полягає в тому, що .spec.volumeClaimTemplates[*].spec.resources.requests.storage в STS являється immutable, тобто ми не можемо просто змінити size через values.yaml, бо це призведе до помилки “Forbidden: updates to statefulset spec for fields other than ‘replicas’, ‘ordinals’, ‘template’, ‘updateStrategy’, ‘revisionHistoryLimit’, ‘persistentVolumeClaimRetentionPolicy’ and ‘minReadySeconds’ are forbidden“.
Values чарту виглядають зараз так:
victoria-logs-single:
server:
persistentVolume:
enabled: true
storageClassName: gp2-retain
size: 30Gi
retentionPeriod: 7d
І при дефолтному типі StatefulSet в чарті для створення PVC використовується volumeClaimTemplates:
...
volumeClaimTemplates:
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: server-volume
...
spec:
...
resources:
requests:
storage: {{ $app.persistentVolume.size }}
...
Якби замість STS був тип Deployment – то в чарті VictoriaLogs це призвело б до створення окремого PVC – pvc.yaml.
Можна було б просто самому створити окремий PVC, і підключати його через value existingClaim, аде PersistentVolume вже є, створювати новий і переносити дані не хочеться (хоча при потребі – можна, див. VictoriaMetrics: міграція даних VMSingle та VictoriaLogs між кластерами Kubernetes, але буде даунтайм), тому подивимось, як ми можемо це вирішити інакше – без видалення Pods і без зупинки сервісу.
Зміст
storageClassName та AllowVolumeExpansion
storageClass, який використовується для створення Persistent Volume має підтримувати AllowVolumeExpansion – див. Volume expansion:
$ kk describe storageclass gp2-retain Name: gp2-retain ... Provisioner: kubernetes.io/aws-ebs Parameters: <none> AllowVolumeExpansion: True MountOptions: <none> ReclaimPolicy: Retain VolumeBindingMode: WaitForFirstConsumer ...
У нас цей storageClass створюється при створенні EKS кластеру з простого маніфесту:
...
resource "kubectl_manifest" "storageclass_gp2_retain" {
yaml_body = <<YAML
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp2-retain
provisioner: kubernetes.io/aws-ebs
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
YAML
}
...
Хоча для Terraform є окремий ресурс storage_class.
Та й kubernetes.io/aws-ebs вже deprecated (OMG, since Kubernetes 1.17!), пора б оновити на ebs.csi.aws.com.
Але це будемо фіксити пізніше, зараз задача – просто збільшити диск.
Reproducing the issue
Для тесту напишемо власний STS з volumeClaimTemplates:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: demo-sts
spec:
serviceName: demo-sts-svc
replicas: 1
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "sleep 3600"]
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: gp2-retain
resources:
requests:
storage: 1Gi
В volumeClaimTemplates задаємо storageClassName та розмір 1 гігабайт.
Деплоїмо:
$ kk apply -f test-sts-pvc.yaml statefulset.apps/demo-sts created
Перевіряємо PVC:
$ kk get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE data-demo-sts-0 Bound pvc-31a9a547-7547-4d34-bb2d-2c7015b9e0f3 1Gi RWO gp2-retain <unset> 15s
Тепер, якщо ми захочемо збільшити розмір через volumeClaimTemplates з 1Gi до 2Gi:
...
volumeClaimTemplates:
...
resources:
requests:
storage: 2Gi
То отримаємо помилку:
$ kk apply -f test-sts-pvc.yaml The StatefulSet "demo-sts" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'ordinals', 'template', 'updateStrategy', 'revisionHistoryLimit', 'persistentVolumeClaimRetentionPolicy' and 'minReadySeconds' are forbidden
The Fix
Але ми можемо це обійти дуже просто:
- редагуємо PVC вручну – задаємо новий розмір
- видаляємо STS з
--cascade=orphan– див. Delete owner objects and orphan dependents - створюємо STS заново
- …
- profit!
Спробуємо.
Note: перед змінами в дисках – не забуваємо про бекапи!
Редагуємо PVC вручну – міняємо resources.requests.storage з 1Gi на 2Gi:
Перевіряємо Events цього PVC:
$ kk describe pvc data-demo-sts-0 ... Normal ExternalExpanding 40s volume_expand CSI migration enabled for kubernetes.io/aws-ebs; waiting for external resizer to expand the pvc Normal Resizing 40s external-resizer ebs.csi.aws.com External resizer is resizing volume pvc-31a9a547-7547-4d34-bb2d-2c7015b9e0f3 Normal FileSystemResizeRequired 35s external-resizer ebs.csi.aws.com Require file system resize of volume on node
І ще через кілька секунд – готово:
... Normal FileSystemResizeSuccessful 19s kubelet
Перевіряємо CAPACITY:
$ kk get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE data-demo-sts-0 Bound pvc-31a9a547-7547-4d34-bb2d-2c7015b9e0f3 2Gi RWO gp2-retain <unset> 4m7s
2Gi, все ОК.
І в самому Pod тепер теж маємо 2 гігабайти:
$ kk exec -ti demo-sts-0 -- df -h /data Filesystem Size Used Available Use% Mounted on /dev/nvme7n1 1.9G 24.0K 1.9G 0% /data
Але якщо ми спробуємо задеплоїти зміни в volumeClaimTemplates.spec.resources.requests.storage ще раз – все одно будемо ловити помилку:
$ kk apply -f test-sts-pvc.yaml The StatefulSet "demo-sts" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'ordinals', 'template', 'updateStrategy', 'revisionHistoryLimit', 'persistentVolumeClaimRetentionPolicy' and 'minReadySeconds' are forbidden
Тому видаляємо сам STS, але залишаємо всі його dependent об’єкти:
$ kubectl delete statefulset demo-sts --cascade=orphan statefulset.apps "demo-sts" deleted
Перевіряємо чи живий Pod:
$ kk get pod NAME READY STATUS RESTARTS AGE demo-sts-0 1/1 Running 0 3m13s
І тепер просто створюємо STS заново, вже з новим значенням в volumeClaimTemplates.spec.resources.requests.storage:
$ kk apply -f test-sts-pvc.yaml statefulset.apps/demo-sts created
Готово.
