Материал подготовлен командой Simple-Server для администраторов VPS и выделенных серверов. Команды и пути проверяйте на тестовой машине перед production.
Что такое Kubernetes Volumes и зачем они нужны
Kubernetes Volumes — это объект в кластере Kubernetes, предназначенный для управления данными в контейнерах. Контейнеры по своей природе являются эфемерными, то есть их состояние не сохраняется после перезапуска или удаления. Это создает проблему для приложений, которым требуется постоянное хранение данных, таких как базы данных, файлы конфигурации или кэш. Kubernetes Volumes решают данную проблему, предоставляя способ хранения данных, доступных для контейнеров в поде, и управления ими на уровне кластера.
Основная задача томов — обеспечить постоянное хранение данных, их доступность между перезапусками контейнеров и возможность совместного использования данных между контейнерами в одном поде. Тома также позволяют подключать внешние хранилища, такие как облачные диски, NFS или локальные директории, к контейнерам. Без использования механизма volumes данные, записанные в контейнер, будут потеряны при его перезапуске, так как файловая система контейнера является временной.
Тома в Kubernetes также упрощают управление конфигурацией. Например, с помощью томов можно монтировать файлы конфигурации, таких объектов, как ConfigMap или Secret, что позволяет динамически обновлять настройки приложения без необходимости пересборки образа контейнера.
Преимущества использования томов в Kubernetes
- Постоянное хранение данных : данные сохраняются даже после перезапуска пода или контейнера.
- Совместное использование данных : несколько контейнеров в одном поде могут использовать один и тот же том для доступа и обмена данными.
- Гибкость : поддержка множества типов хранилищ, от локальных директорий до облачных решений.
- Управление конфигурацией : интеграция с объектами
ConfigMapиSecretдля передачи конфиденциальных данных или настроек.
В Kubernetes тома связываются с подами через указание спецификации в YAML или JSON манифестах. Они определяют, где и как данные будут доступны контейнерам.
Предварительные требования
Далее мы будем рассматривать практическую часть для которой нам понадобится кластер Kubernetes. Арендовать готовый кластер можно с помощью сервиса Kubernetes в облаке. Для работы с сервисами достаточно одной master-ноды и одной worker-ноды с минимальной конфигурацией.
После заказа кластера он будет готов к использованию в течение нескольких минут. kubeconfig для подключения к кластеру будет сгенерирован и доступен в разделе «Дашборд».
Основные типы томов в Kubernetes
Kubernetes поддерживает различные типы томов, каждый из которых подходит для определенных сценариев использования. Рассмотрим наиболее распространенные типы томов и их особенности на практике.
emptyDir — это временный том в Kubernetes, который создается при запуске пода и существует только в течение его жизненного цикла. Данные в emptyDir хранятся на узле кластера, где выполняется под, и удаляются при завершении работы пода (например, при его перезапуске или удалении). Этот тип тома подходит для временных данных, таких как кэш, промежуточные результаты обработки или для обмена данными между контейнерами внутри одного пода.
Пример конфигурации emptyDir приведен ниже:
apiVersion: v1
kind: Namespace
metadata:
name: emptydir-volume
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: emptydir-volume
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.26.0
ports:
- containerPort: 80
volumeMounts:
- name: temp-storage
mountPath: /cache # Путь до директории внутри контейнера, куда монтируется emptyDir
volumes:
- name: temp-storage
emptyDir: {}Мы выбрали образ веб-сервера Nginx, для которого emptyDir используется как временное хранилище. Оно подходит для кэширования данных или хранения лог-файлов, которые не требуют долговременного сохранения.
Сохраняем конфигурацию выше в файл с именем nginx-emptydir.yaml и применяем:
kubectl apply -f nginx-emptydir.yamlПроверим что под был успешно запущен:
kubectl get pods -n emptydir-volumeКак можно увидеть на скриншоте выше, под был успешно запущен и его статус отображается как Running.
Далее подключаемся к контейнеру при помощи команды:
kubectl exec -it nginx-deployment-b8789c9cb-9xnv4 -n emptydir-volume -- /bin/bashГде nginx-deployment-b8789c9cb-9xnv4 это имя пода. Не забудьте заменить на нужное — у вас будет свое уникальное имя.
Внутри контейнера проверяем наличие директории /cache:
Директория была успешно создана. Теперь попробуем создать файл, чтобы проверить, что возможна запись:
echo "test k8s emptydir" > /cache/new-test-file.txtПроверяем наличие файла а также выводим его содержимое:
ls /cache && cat /cache/new-test-file.txtФайл был успешно создан и запись успешно проходит.
Далее выходим из контейнера при помощи команды:
Как мы уже подчеркивали ранее, том emptyDir удаляется при удалении пода, но сохраняется при перезапуске контейнера внутри пода (если под не удаляется). Чтобы проверить это, сымитируем сбой, завершив основной процесс в контейнере при помощи команды:
kubectl exec nginx-deployment-b8789c9cb-9xnv4 -c nginx -n emptydir-volume -- sh -c "kill 1"Далее снова подключаемся к контейнеру:
kubectl exec -it nginx-deployment-b8789c9cb-9xnv4 -n emptydir-volume -- /bin/bashГде nginx-deployment-b8789c9cb-9xnv4 это имя пода. Не забудьте заменить на нужное — у вас будет свое уникальное имя. Чтобы узнать имя пода можно выполнить команду:
kubectl get po -n emptydir-volumeПроверяем что ранее созданная директория осталась на месте:
Также проверим, что ранее созданный файл new-test-file.txt остался:
Файл testfile.txt остался на месте, так как emptyDir сохраняется на уровне пода.
hostPath позволяет монтировать директорию или файл с узла кластера в контейнер. Этот тип тома полезен для доступа к системным файлам узла, например, логам или конфигурациям. Однако использование hostPath требует осторожности, так как оно привязывает под к конкретному узлу.
Рассмотрим работу hostPath на практике. Для этого создадим два пода. В первом поде с именем writer мы создадим файл demo.txt, который будет храниться в директории /host. В файл будет записана строка «Hello from writer». С помощью второго пода с именем reader мы прочитаем файл demo.txt, который был создан в первом поде. Опция DirectoryOrCreate означает, что заданный путь для директории должен существовать либо, если он отсутствует, должна быть создана новая директория. Конфигурация подов приведена ниже:
apiVersion: v1
kind: Namespace
metadata:
name: hostpath-testing
---
apiVersion: v1
kind: Pod
metadata:
name: writer
namespace: hostpath-testing
spec:
containers:
- name: writer
image: busybox
command: [ "sh", "-c", "echo Hello from writer > /host/demo.txt && sleep 3600" ]
volumeMounts:
- name: host-volume
mountPath: /host
volumes:
- name: host-volume
hostPath:
path: /tmp/demo
type: DirectoryOrCreate
restartPolicy: Never
---
apiVersion: v1
kind: Pod
metadata:
name: reader
namespace: hostpath-testing
spec:
containers:
- name: reader
image: busybox
command: [ "sleep", "3600" ]
volumeMounts:
- name: host-volume
mountPath: /host
volumes:
- name: host-volume
hostPath:
path: /tmp/demo
type: Directory
restartPolicy: NeverСохраняем конфигурацию выше в файл с именем hostpath-testing.yaml и применяем:
kubectl apply -f hostpath-testing.yamlПроверим что поды были успешно запущены:
kubectl get pods -n hostpath-testingКак можно увидеть на скриншоте выше, поды были успешно запущены и их статусы отображается как Running.
Далее подключаемся ко второму поду с именем reader и выводим содержимое файла demo.txt:
kubectl exec reader -n hostpath-testing -- cat /host/demo.txtКак можно заметить на скриншоте выше, содержимое файла было успешно выведено.
ConfigMap — это объект, используемый для хранения неконфиденциальных данных в формате ключ-значение. Он предназначен для передачи конфигурационных параметров в поды, таких как настройки приложения, переменные окружения или конфигурационные файлы, без необходимости встраивать их в образ контейнера.
Рассмотрим использование ConfigMap на практике. В конфигурации ниже задействован образ с веб-сервером Nginx, для которого будет использован файл nginx.conf (основной конфигурационный файл Nginx). ConfigMap используется как том (config-volume), монтируя файл nginx.conf в директорию /etc/nginx/conf.d контейнера в режиме только для чтения:
Сохраняем конфигурацию выше в файл с именем nginx-configmap.yaml и применяем:
kubectl apply -f nginx-configmap.yamlПроверим что поды были успешно запущены:
kubectl get pods -n nginx-configmapКак можно увидеть на скриншоте выше, поды были успешно запущены и их статусы отображается как Running.
Далее подключаемся к контейнеру при помощи команды:
kubectl exec -it nginx-app-687d4c5ddf-2pfjz -n nginx-configmap -- /bin/bashГде nginx-app-687d4c5ddf-2pfjz это имя пода. Не забудьте заменить на нужное — у вас будет свое уникальное имя.
Внутри контейнера отобразим файл nginx.conf для которого мы поменяли конфигурацию:
cat /etc/nginx/nginx.confКак можно увидеть на скриншоте выше, ранее проброшенная конфигурация была успешно применена.
Работа с PersistentVolume (PV) и PersistentVolumeClaim (PVC)
Для приложений, требующих постоянного хранения, Kubernetes предоставляет механизмы PersistentVolume (PV) и PersistentVolumeClaim (PVC).
PersistentVolume — это объект, представляющий ресурс хранения в кластере Kubernetes. Он может быть как физическим, так и логическим ресурсом, например, NFS, блоком в облачном хранилище или локальным диском.
PersistentVolumeClaim — это запрос от пользователя или приложения на использование хранилища. PVC запрашивает определенный объем хранилища и режим доступа. Kubernetes связывает PVC с подходящим PV, если он доступен, или динамически создает PV при помощи StorageClass.
В качестве ресурса для PV мы воспользуемся дополнением CSI S3 от хостинг-провайдера Simple-Server.
CSI S3 — это плагин для Kubernetes, который позволяет монтировать S3-бакеты как тома хранения для контейнеров. Он поддерживает динамическое выделение бакетов и их монтирование через FUSE (например, с использованием GeeseFS или rclone). Более подробно с CSI S3 можно ознакомиться перейдя по ссылке.
Для начала необходимо установить плагин CSI S3. Для этого переходим в раздел «Дополнения» на странице управления кластером и находим плагин с именем «CSI S3»:
На странице плагина создаем новый бакет или используем существующий (если он был арендован ранее):
После этого нажимаем на кнопку «Установить» и дожидаемся установки плагина.
Для проверки установки выполним команду ниже:
kubectl get storageclass csi-s3 -o yamlВ ответ должна отобразиться информация о подключенном бакете:
После того мы создали объект типа PV, создадим PVC. Пример конфигурации приведен ниже:
apiVersion: v1
kind: Namespace
metadata:
name: test-pv-and-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: csi-s3-pvc
namespace: test-pv-and-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
storageClassName: csi-s3Манифест выше определяет PersistentVolumeClaim с именем csi-s3-pvc и запрашивает 5 ГБ хранилища с режимом доступа ReadWriteMany, который разрешает множественным подам читать и записывать данные одновременно используя класс хранения csi-s3.
Сохраняем конфигурацию выше в файл с именем pvc-testing.yaml и применяем:
kubectl apply -f pvc-testing.yamlДалее проверяем что объект PersistentVolumeClaim был успешно создан:
kubectl get persistentvolumeclaim -n test-pv-and-pvcПодключение PVC в Deployment
Чтобы приложение могло использовать PVC, его необходимо подключить в манифесте Deployment. Пример ниже демонстрирует, как контейнер с образом Nginx использует подключенный PVC:
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-pvc-nginx-deployment
namespace: test-pv-and-pvc
spec:
replicas: 1
selector:
matchLabels:
app: nginx-app
template:
metadata:
labels:
app: nginx-app
spec:
containers:
- name: nginx-test-container
image: nginx:1.26.0
volumeMounts:
- name: s3-storage
mountPath: /usr/share/nginx/html
volumes:
- name: s3-storage
persistentVolumeClaim:
claimName: csi-s3-pvcКонтейнер монтирует том s3-storage по пути /usr/share/nginx/html, который связан с PersistentVolumeClaim под названием csi-s3-pvc.
Сохраняем конфигурацию выше в файл с именем pvc-deployment-connect.yaml и применяем:
kubectl apply -f pvc-deployment-connect.yamlПроверяем что все объекты были успешно созданы и под запущен:
kubectl get all -n test-pv-and-pvcДалее проверим что ранее примонтированный том доступен в контейнере. Для этого подключаемся к контейнеру при помощи команды:
kubectl exec -it test-pvc-nginx-deployment-5fd656dd6d-5r6sr -n test-pv-and-pvc -- /bin/bashГде test-pvc-nginx-deployment-5fd656dd6d-5r6sr это имя пода. Не забудьте поменять на свое. Имя пода можно узнать при помощи команды:
kubectl get po -n test-pv-and-pvcВнутри контейнера выполняем команду:
Директория /usr/share/nginx/html была успешно примонтирована.
Теперь возвращаемся в веб-интерфейс хранилище S3 в панели управления:
Далее переходим в раздел «Объекты»:
Открываем корневую директорию хранилища и нажимаем на кнопку «Загрузить файл»:
В качестве примера загрузим какой-нибудь файл. Например, картинку в формате SVG:
Подключаемся к контейнеру еще раз:
kubectl exec -it test-pvc-nginx-deployment-5fd656dd6d-5r6sr -n test-pv-and-pvc -- /bin/bashГде test-pvc-nginx-deployment-5fd656dd6d-5r6sr это имя пода. Не забудьте поменять на свое.
Переходим в директорию usr/share/nginx/html:
и проверяем наличие ранее загруженного файла:
Файл успешно отобразился.
Нужен сервер для практики? Арендуйте VPS/VDS в России — root-доступ, NVMe, DDoS-защита и поддержка 24/7.