Доступ до файлової системи хосту для Persistent Volume в Kind
Кубернетіс вже перестає бути чимось таким з чим працюють лише інженери платформи. Все більше і більше застосунків загортаються в контейнери та запускаються в контейнерних середовищах. Що робити, якщо з певних причин у вас немає доступу до хмарної платформи, але треба вести розробку застосунку, який працюватиме в хмарі? Ви можете скористатись Kind для локального розгортання Кубернетіс.
Kind — це інструмент для запуску локальних кластерів Kubernetes з використанням «вузлів» контейнерів Docker. В першу чергу kind був розроблений для тестування самого Kubernetes, але може бути використаний для локальної розробки або CI.
Для запуску Kind вам знадобиться docker, podman або інший рушій для роботи з контейнерами. Ви можете звернутись до Швидкого початку роботи з Kind на офіційному сайті.
Створення кластера
Отже, ми маємо встановлений Kind та середовище для роботи з контейнерами, kubectl
– інструмент командного рядка для виконання маніпуляцій з кластером.
Для створення локального кластера скористаємось командою kind create cluster
.
Ви завжди можете отримати потрібну довідку скориставшись командою виду kind [command] --help
.
Ми створили свій локальний кластер з іменем kind-kind
. Це стандартне імʼя, яке використовує kind, якщо параметр -n назва
або --name назва
не вказано.
Крім використання ключів для kind
ми можемо використати маніфест для створення кластера з потрібними нам параметрами.
cat <<EOF > kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: my-super-cluster
nodes:
- role: control-plane
- role: worker
extraMounts:
- hostPath: /path/to/local/data
containerPath: /data
# - role: worker
# - role: worker
# extraMounts:
# - hostPath: /path/to/local/data/dump
# containerPath: /data/dump
# - hostPath: /path/to/local/data/diff
# containerPath: /data/diff
☝️ тут ми можемо зазначити кількість потрібних вузлів, їх роль та, головне, в нашому випадку, — шлях у локальній файловій системі, який ми будемо монтувати у вузли нашого кластера та використовувати, як систему зберігання для наших Постійних Томів (Persistent Volumes). Див Extra Mounts в документації Kind.
Застосуємо нашу конфігурацію для створення кластера
kind create cluster --config kind-config.yaml
Creating cluster "kind" ...
✓ Ensuring node image (kindest/node:v1.32.2) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-my-super-cluster"
You can now use your cluster with:
kubectl cluster-info --context kind-my-super-cluster
Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂
Перевіримо, що файлову систему хосту змонтовано у вузол worker нашого кластера.
docker container inspect osm-cluster-worker \
| jq '[{"Name": .[0].Name,
"BindMounts": (
.[] |
.Mounts[] |
select(.Type == "bind")
)}]'
І бачимо, що все ОК, файлову систему змонтовано.
[
{
"Name": "/my-super-cluster-worker",
"BindMounts": {
"Type": "bind",
"Source": "/host_mnt/path/to/local/data",
"Destination": "/data",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
},
{
"Name": "/my-super-cluster-worker",
"BindMounts": {
"Type": "bind",
"Source": "/lib/modules",
"Destination": "/lib/modules",
"Mode": "ro",
"RW": false,
"Propagation": "rprivate"
}
}
]
Створення PersistentVolume та PersistentVolumeClaim
Створимо маніфест для Постійного Тому
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-super-cluster-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
hostPath:
path: "/data"
storageClassName: my-storageclass
А також створимо Заявку PersistentVolumeClaim яку будемо використовувати для монтування Постійного Тому в робочі навантаження.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-super-cluster-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: my-storageclass
Тепер найголовніше 🥁, потрібно створити StorageClass, який дозволить нам явно повʼязати Заявку PVC з Постійним Томом PV.
Примітка: Зверніть увагу що kind створює стандартний StorageClass під час створення кластера. Однак цей StorageClass не задовольняє нашим вимогам маючи
reclaimPolicy:Delete
.
kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
standard (default) rancher.io/local-path Delete WaitForFirstConsumer false 80m
Це означає, що вміст нашого Постійного Тому буде очищатись після його розмонтування з пода, а це не те що нам треба.
Створимо наш StorageClass в кластері.
kubectl apply -f - <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: my-storageclass
provisioner: rancher.io/local-path
parameters:
nodePath: /data
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
EOF
storageclass.storage.k8s.io/my-storageclass created
Перевіримо наш StorageClass.
kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
my-storageclass rancher.io/local-path Retain WaitForFirstConsumer false 5m27s
standard (default) rancher.io/local-path Delete WaitForFirstConsumer false 91m
І зробимо його типовим, на про всяк випадок
kubectl patch storageclass my-storageclass -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
а StorageClass standard
навпаки, зробимо звичайним.
kubectl patch storageclass standard -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
Переглянемо поточні відомості про StorageClass
kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
my-storageclass (default) rancher.io/local-path Retain WaitForFirstConsumer false 12m
standard rancher.io/local-path Delete WaitForFirstConsumer false 98m
Використання PersistentVolumeClaim в поді
Застосуємо маніфести PV та PVC в кластері.
kubectl apply -f pv.yaml -f pvc.yaml
Створимо под, який використовує Заявку на постійний том для зберігання даних.
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: debug-pod
spec:
containers:
- name: debug-container
image: busybox:latest
command: ["sh", "-c", "sleep 3600"]
volumeMounts:
- mountPath: "/data"
name: my-super-cluster
volumes:
- name: my-super-cluster
persistentVolumeClaim:
claimName: my-super-cluster-pvc
EOF
Перевіримо що Заявка PVC має привʼязку до PV та використовується в нашому тестовому поді
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
my-super-cluster-pv 100Gi RWO Retain Bound default/my-super-cluster-pvc my-storageclass <unset> 9m20s
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
my-super-cluster-pvc Bound my-super-cluster-pv 100Gi RWO my-storageclass <unset> 8m48s
Зверніть увагу що статус PV та PVC має значення Bound
, що означає що Заявку було успішно звʼязано з Постійним Томом.
kubectl describe pod
Name: debug-pod
Namespace: default
Priority: 0
Service Account: default
Node: kind-control-plane/172.20.0.4
Start Time: Fri, 04 Apr 2025 18:17:09 +0300
Labels: <none>
Annotations: <none>
Status: Running
IP: 10.244.0.5
IPs:
IP: 10.244.0.5
Containers:
debug-container:
Container ID: containerd://d030a6edfc13c314853f22efc505990bbbb8e3954ed1c9887b9c7b3be575a0be
Image: busybox:latest
Image ID: docker.io/library/busybox@sha256:37f7b378a29ceb4c551b1b5582e27747b855bbfaa73fa11914fe0df028dc581f
Port: <none>
Host Port: <none>
Command:
sh
-c
sleep 3600
State: Running
Started: Fri, 04 Apr 2025 18:17:13 +0300
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/data from my-super-cluster (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-5wdzj (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
my-super-cluster:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: my-super-cluster-pvc
ReadOnly: false
kube-api-access-5wdzj:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 8m36s default-scheduler Successfully assigned default/debug-pod to kind-control-plane
Normal Pulling 8m36s kubelet Pulling image "busybox:latest"
Normal Pulled 8m32s kubelet Successfully pulled image "busybox:latest" in 3.395s (3.395s including waiting). Image size: 1855985 bytes.
Normal Created 8m32s kubelet Created container: debug-container
Normal Started 8m32s kubelet Started container debug-container
Наш под було успішно створено і він працює.
Отримаємо доступ до термінала в нашому поді та перевіримо, що том змонтований у нашій файловій системі і все працює належним чином.
kubectl exec -it debug-pod -- sh
/ # ls -l / | grep data
drwxr-xr-x 2 root root 4096 Apr 4 15:17 data
/ # touch /data/somefile.txt
/ # ls -l /data
total 0
-rw-r--r-- 1 root root 0 Apr 4 15:31 somefile.txt
/ #
/ # exit
Тепер перегляньте файлову систему хосту змонтовану у вузол worker нашого кластера і ви побачите там тільки що створений файл somefile.txt
.
Підсумки
Ми створили Заявку на використання Постійного Тому в робочому навантажені, яка використовує Клас Зберігання (StorageClass) для звʼязування Заявки з Томом. Постійний том використовує систему зберігання наявну на вузлі нашого кластера. Система зберігання вузла кластера базується на файловій системі хосту, на якому розгорнуто наш кластер.
У такий спосіб ми можемо надійно зберігати та повторно використовувати дані розміщені в Постійному Томі в робочих навантаження нашого кластера, які за своєю природою мають обмежений життєвий цикл. Окрім цього ми також можемо передавати в наші робочі навантаження попередньо створені дані з нашого хосту та використовувати їх в подах.
Очищення
Для очищення (вилучення) кластера скористайтесь наступною командою.
kind delete cluster --name kind-my-super-cluster
Deleting cluster "kind-my-super-cluster" ...
Зачекайте допоки Kind видаліть кластер. За потреби видаліть створені файли у файловій системі хосту.