Як перемістити або змінити налаштування PersistentVolume в k8s?
September 30, 2022
Одразу попереджаю, що інформація з цього посту може не працювати для деяких класів сторейджів.
В k8s робота зі сторейджем складається з трьох складових:
- опис самого сторейджа за допомогою
PersistentVolume
(PV). Цей об’єкт описує тип сторейджа і вказує k8s як взаємодіяти зі сторейджем. Задача цього об’єкта абстрагувати k8s від деталей імплементації того чи іншого сторейджа в тому чи іншому клауді і т.д. - опис
PersistentVolumeClaim
(PVC). Цей об’єкт вже описує вимоги до сторейджа на рівні вашого аплікейшена. - об’явити прив’язку до стореджа на рівні конфігурації pod (поле
.spec.volume
) і далі вказати в якому контейнері і за яким шляхом замаунтити цей вольюм (.spec.containers.volumeMounts
).
В цілому взаємодія зі стором мало чим відрізняється від взаємодії з іншими
об’єктами k8s, але є один нюанс. Справа в тому, що деякі поля PersistentVolume
імутабельні. Через це ви можете отримати помилки “field is immutable”:
{
"error": {
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "PersistentVolume \"pvc-b6be57df-83ec-4a69-98cf-1153f1b72448\" is invalid: nodeAffinity: Invalid value: core.VolumeNodeAffinity{Required:(*core.NodeSelector)(0xf695f60)}: field is immutable",
"reason": "Invalid",
"details": {
"name": "pvc-b6be57df-83ec-4a69-98cf-1153f1b72448",
"kind": "PersistentVolume",
"causes": [
{
"reason": "FieldValueInvalid",
"message": "Invalid value: core.VolumeNodeAffinity{Required:(*core.NodeSelector)(0xf695f60)}: field is immutable",
"field": "nodeAffinity"
}
]
},
"code": 422
},
"messages": [
"PersistentVolume \"pvc-b6be57df-83ec-4a69-98cf-1153f1b72448\" is invalid: nodeAffinity: Invalid value: core.VolumeNodeAffinity{Required:(*core.NodeSelector)(0xf695f60)}: field is immutable"
],
"isUsedForNotification": false
}
Отже у вас можуть виникати проблеми у випадку коли ви захочете змінити namespace
або nodeAffinity
PV (наприклад, коли ви змінили назву ноди k8s).
Перш ніж почати робити будь-які дії, краще зробити бекап даних, а також
заборонити k8s видаляти PV. Це можно зробити додавши поле
.spec.persistentVolumeReclaimPolicy: 'Retain'
в специфікацію VP або за
допомогою команди:
kubectl patch pv <PV_name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
Наступним кроком треба вигрузити специфікації для усіх потрібних PVC:
kubectl get pvc <PVC_name> -o yaml > PVC_name.yaml
Після цього можна відв’язати PVC від PV. Для цього треба відредагувати кожний PV:
kubectl edit pv <PV_name>
і там видаляємо два поля: .spec.claimRef.uid
та
.spec.claimRef.resourceVersion
. Після цього всі PV перейдуть у статус
Released
.
Тепер потрібно видалити всі PVC:
kubectl delete pvc <PVC_name> --force
Можливо вам ще потрібно буде видалити і пов’язані з ними поди. Це пов’язано з захистом через
finalizers: [kubernetes.io/pvc-protection]
в конфігруації PVC. Альтернативно можна відредагувати PVC і прибрати звідти фіналайзер.
Якщо вам потрібно відредагувати не тільки PersistentVolumeClaim
, а ще й
PersistentVolume
(наприклад, nodeAffinity
), то тоді вигрузити конфіг PV
і
після цього видалити PV
з кластера:
kubectl get pv <PV_name> -o yaml > PV_name.yaml
kubectl delete pv <PV_name> --force
Наступним кроком вносимо потрібні правки в yaml
, які ми вигрузили на
попередніх етапах. Якщо ваша мета змінити назву ноди, зверніть увагу також на
анотацію volume.kubernetes.io/selected-node
в PV. Далі приміняємо ці файли на
кластері:
kubectl apply -f PV_name.yaml PVC_name.yaml
# або з неймспейсом
kubectl apply -f PV_name.yaml PVC_name.yaml -n new_namespace
Після цього k8s має автоматично з’єднати нові PersistentVolume
з відповідним
PersistentVolumeClaim
і відповідно PV
отримає статус Bound
. Статус PV
можна перевірити наступною командою:
kubectl get pv <PV_name>