<div><img src="https://top-fwz1.mail.ru/counter?id=3548135;js=na" style="position:absolute;left:-9999px;" alt="Top.Mail.Ru" /></div>
Публичное облако на базе VMware с управлением через vCloud Director
Вход / Регистрация

Kubernetes Volumes: как работают и как подключать в подах через volumeMounts и PVC

Александр Бархатов
Александр Бархатов
Технический писатель
26 июня 2025 г.
5
14 минут чтения
Средний рейтинг статьи: 5

Тома в Kubernetes — это ключевой механизм для управления данными в контейнерах. Они позволяют сохранять данные между перезапусками контейнеров, делиться файлами между подами и подключать внешние хранилища. Сегодня мы подробно разберем, как работают Volumes в Kubernetes, и на практике создадим несколько их типов, включая emptyDir, hostPath и PersistentVolume.

Что такое Kubernetes Volumes и зачем они нужны 

Kubernetes Volumes — это объект в кластере Kubernetes, предназначенный для управления данными в контейнерах. Контейнеры по своей природе являются эфемерными, то есть их состояние не сохраняется после перезапуска или удаления. Это создает проблему для приложений, которым требуется постоянное хранение данных, таких как базы данных, файлы конфигурации или кэш. Kubernetes Volumes решают данную проблему, предоставляя способ хранения данных, доступных для контейнеров в поде, и управления ими на уровне кластера.

Основная задача томов — обеспечить постоянное хранение данных, их доступность между перезапусками контейнеров и возможность совместного использования данных между контейнерами в одном поде. Тома также позволяют подключать внешние хранилища, такие как облачные диски, NFS или локальные директории, к контейнерам. Без использования механизма volumes данные, записанные в контейнер, будут потеряны при его перезапуске, так как файловая система контейнера является временной.

Тома в Kubernetes также упрощают управление конфигурацией. Например, с помощью томов можно монтировать файлы конфигурации, таких объектов, как ConfigMap или Secret, что позволяет динамически обновлять настройки приложения без необходимости пересборки образа контейнера.

cloud

Преимущества использования томов в Kubernetes

  • Постоянное хранение данных: данные сохраняются даже после перезапуска пода или контейнера.
  • Совместное использование данных: несколько контейнеров в одном поде могут использовать один и тот же том для доступа и обмена данными.
  • Гибкость: поддержка множества типов хранилищ, от локальных директорий до облачных решений.
  • Управление конфигурацией: интеграция с объектами ConfigMap и Secret для передачи конфиденциальных данных или настроек.

В Kubernetes тома связываются с подами через указание спецификации в YAML или JSON манифестах. Они определяют, где и как данные будут доступны контейнерам.

Предварительные требования

Далее мы будем рассматривать практическую часть для которой нам понадобится кластер Kubernetes. Арендовать готовый кластер можно с помощью сервиса Kubernetes в облаке. Для работы с сервисами достаточно одной master-ноды и одной worker-ноды с минимальной конфигурацией.

После заказа кластера он будет готов к использованию в течение нескольких минут. kubeconfig для подключения к кластеру будет сгенерирован и доступен в разделе «Дашборд».

Основные типы томов в Kubernetes

Kubernetes поддерживает различные типы томов, каждый из которых подходит для определенных сценариев использования. Рассмотрим наиболее распространенные типы томов и их особенности на практике.

emptyDir

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

Image2

Проверим что под был успешно запущен:

kubectl get pods -n emptydir-volume

Image23

Как можно увидеть на скриншоте выше, под был успешно запущен и его статус отображается как Running.

Далее подключаемся к контейнеру при помощи команды:

kubectl exec -it nginx-deployment-b8789c9cb-9xnv4 -n emptydir-volume -- /bin/bash

Где nginx-deployment-b8789c9cb-9xnv4 это имя пода. Не забудьте заменить на нужное — у вас будет свое уникальное имя.

Внутри контейнера проверяем наличие директории /cache:

ls -l /

Image15

Директория была успешно создана. Теперь попробуем создать файл, чтобы проверить, что возможна запись:

echo "test k8s emptydir" > /cache/new-test-file.txt

Проверяем наличие файла а также выводим его содержимое:

ls /cache && cat /cache/new-test-file.txt

Image24

Файл был успешно создан и запись успешно проходит.

Далее выходим из контейнера при помощи команды:

exit

Как мы уже подчеркивали ранее, том 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

Image7

Проверяем что ранее созданная директория осталась на месте:

ls /

Image13

Также проверим, что ранее созданный файл new-test-file.txt остался:

Image25

Файл testfile.txt остался на месте, так как emptyDir сохраняется на уровне пода.

hostPath

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

Image16

Проверим что поды были успешно запущены:

kubectl get pods -n hostpath-testing

Image3

Как можно увидеть на скриншоте выше, поды были успешно запущены и их статусы отображается как Running.

Далее подключаемся ко второму поду с именем reader и выводим содержимое файла demo.txt:

kubectl exec reader -n hostpath-testing -- cat /host/demo.txt

Image11

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

ConfigMap

ConfigMap — это объект, используемый для хранения неконфиденциальных данных в формате ключ-значение. Он предназначен для передачи конфигурационных параметров в поды, таких как настройки приложения, переменные окружения или конфигурационные файлы, без необходимости встраивать их в образ контейнера.

Рассмотрим использование ConfigMap на практике. В конфигурации ниже задействован образ с веб-сервером Nginx, для которого будет использован файл nginx.conf (основной конфигурационный файл Nginx). ConfigMap используется как том (config-volume), монтируя файл nginx.conf в директорию /etc/nginx/conf.d контейнера в режиме только для чтения:

apiVersion: v1
kind: Namespace
metadata:
  name: nginx-configmap
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: nginx-configmap
data:
  nginx.conf: |
    events {}
    http {
        server {
            listen 80;
            server_name localhost;
            root /usr/share/nginx/html;
            index index.html index.htm;
            location = /50x.html {
                root /usr/share/nginx/html;
            }
        }
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  namespace: nginx-configmap
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-app
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      containers:
      - name: nginx
        image: nginx:1.26.0
        ports:
        - containerPort: 80
        volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
      volumes:
      - name: config-volume
        configMap:
          name: nginx-config

Сохраняем конфигурацию выше в файл с именем nginx-configmap.yaml и применяем:

kubectl apply -f nginx-configmap.yaml

Image20

Проверим что поды были успешно запущены:

kubectl get pods -n nginx-configmap

Image10

Как можно увидеть на скриншоте выше, поды были успешно запущены и их статусы отображается как Running.

Далее подключаемся к контейнеру при помощи команды:

kubectl exec -it nginx-app-687d4c5ddf-2pfjz -n nginx-configmap -- /bin/bash

Где nginx-app-687d4c5ddf-2pfjz это имя пода. Не забудьте заменить на нужное — у вас будет свое уникальное имя.

Внутри контейнера отобразим файл nginx.conf для которого мы поменяли конфигурацию:

cat /etc/nginx/nginx.conf

Image21

Как можно увидеть на скриншоте выше, ранее проброшенная конфигурация была успешно применена. 

Работа с PersistentVolume (PV) и PersistentVolumeClaim (PVC)

Для приложений, требующих постоянного хранения, Kubernetes предоставляет механизмы PersistentVolume (PV) и PersistentVolumeClaim (PVC).

PersistentVolume — это объект, представляющий ресурс хранения в кластере Kubernetes. Он может быть как физическим, так и логическим ресурсом, например, NFS, блоком в облачном хранилище или локальным диском.

PersistentVolumeClaim — это запрос от пользователя или приложения на использование хранилища. PVC запрашивает определенный объем хранилища и режим доступа. Kubernetes связывает PVC с подходящим PV, если он доступен, или динамически создает PV при помощи StorageClass.

Создание PV

В качестве ресурса для PV мы воспользуемся дополнением CSI S3 от хостинг-провайдера Timeweb Cloud.

CSI S3 — это плагин для Kubernetes, который позволяет монтировать S3-бакеты как тома хранения для контейнеров. Он поддерживает динамическое выделение бакетов и их монтирование через FUSE (например, с использованием GeeseFS или rclone). Более подробно с CSI S3 можно ознакомиться перейдя по ссылке.

Для начала необходимо установить плагин CSI S3. Для этого переходим в раздел «Дополнения» на странице управления кластером и находим плагин с именем «CSI S3»: 

Image8

На странице плагина создаем новый бакет или используем существующий (если он был арендован ранее):

Image5

После этого нажимаем на кнопку «Установить» и дожидаемся установки плагина.

Для проверки установки выполним команду ниже:

kubectl get storageclass csi-s3 -o yaml

В ответ должна отобразиться информация о подключенном бакете:

Image26

Создание PVC

После того мы создали объект типа 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

Image14

Далее проверяем что объект PersistentVolumeClaim был успешно создан:

kubectl get persistentvolumeclaim -n test-pv-and-pvc

Image18

Подключение 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

Image19

Проверяем что все объекты были успешно созданы и под запущен:

kubectl get all -n test-pv-and-pvc

Image12

Далее проверим что ранее примонтированный том доступен в контейнере. Для этого подключаемся к контейнеру при помощи команды:

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

Внутри контейнера выполняем команду:

df -h

Image1

Директория /usr/share/nginx/html была успешно примонтирована.

Теперь возвращаемся в веб-интерфейс хранилище S3 в панели управления:

Image9

Далее переходим в раздел «Объекты»:

Image22

Открываем корневую директорию хранилища и нажимаем на кнопку «Загрузить файл»:

Image6

В качестве примера загрузим какой-нибудь файл. Например, картинку в формате SVG:

Image4

Подключаемся к контейнеру еще раз:

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:

cd usr/share/nginx/html

и проверяем наличие ранее загруженного файла:

Image17

Файл успешно отобразился.

Подготовили для вас выгодные тарифы на облачные серверы

Лучшие практики при работе с томами в Kubernetes

  • Используйте PVC для постоянного хранения данных: Даже если вы работаете с локальным хранилищем, использование PVC упрощает управление и делает конфигурацию переносимой.
  • Ограничивайте доступ с помощью accessModes: Выбирайте подходящий режим доступа (ReadWriteOnce, ReadOnlyMany, ReadWriteMany) в зависимости от потребностей приложения.
  • Избегайте hostPath для production-систем: hostPath привязывает под к конкретному узлу, что может нарушить переносимость и отказоустойчивость.
  • Используйте ConfigMap для конфигурации: Это позволяет отделить конфигурацию от кода.
  • Мониторьте использование хранилища: Убедитесь, что тома не переполняются, особенно для emptyDir, который ограничен ресурсами узла.
  • Используйте StorageClass для автоматизации: Это упрощает масштабирование и управление хранилищем в больших кластерах.

Частые ошибки при работе с томами в Kubernetes

  • Неправильно назначенные права доступа: Если контейнер не имеет прав на запись в том, это может привести к ошибкам. Например, при использовании hostPath убедитесь, что директория на узле доступна для записи.
  • Отсутствие StorageClass: Без StorageClass динамическое выделение PV невозможно, что приводит к ручному управлению хранилищем.
  • Переполнение диска при использовании типа emptyDir: Так как emptyDir использует диск узла, его переполнение может повлиять на стабильность кластера.
  • Игнорирование ресурса cleanup PV: После удаления PVC соответствующий PV может остаться в кластере, если не настроена политика регенерации (reclaimPolicy).

Заключение

Kubernetes Volumes — это мощный инструмент для работы с данными в кластере, обеспечивающий гибкость и удобство управления конфигурацией. Знание типов томов, их принципов работы и лучших практик упрощает взаимодействие приложений с файлами. Чтобы обеспечить стабильность и высокую производительность системы, важно учитывать особенности каждого типа тома и избегать типичных ошибок.

26 июня 2025 г.
5
14 минут чтения
Средний рейтинг статьи: 5

Читайте также

Хотите внести свой вклад?
Участвуйте в нашей контент-программе за
вознаграждение или запросите нужную вам инструкцию
img-server
Пока нет комментариев