Экосистема Kubernetes очень динамична и включает в себя различные компоненты, взаимодействующие между собой. Управление хранением данных в Kubernetes является отдельной задачей, в рамках которой вводятся понятия Persistent Volumes (постоянных томов, PVs) и Persistent Volume Claims (запросов на выделение постоянного тома, PVCs). 

В этой статье мы рассмотрим, как с помощью Storage Class (классов хранилища) автоматически предоставлять NFS (Network File System) в качестве постоянного тома для Kubernetes. Для автоматизации мы будем использовать Ansible для настройки сервера NFS и Terraform вместе с Helm для настройки NFS-клиента. 

Начальные условия

  1. Работающий кластер Kubernetes.

  2. Helm, установленный на вашей локальной машине или в кластере Kubernetes

  3. Ansible, установленный на локальной машине

  4. Terraform, установленный на локальной машине.

Настройка NFS-сервера с помощью Ansible

  1. Создайте плейбук Ansible для настройки NFS-сервера. Пример:

---
- hosts: nfs-server
  become: yes
  tasks:
    - name: Update all packages
      apt:
        update_cache: yes

    - name: Install NFS server package
      apt: 
        name: nfs-kernel-server
        state: present

    - name: Create a directory to share
      file:
        path: /var/nfs_share
        state: directory
        mode: '777'

    - name: Modify ownership & permissions of the shared directory
      file:
        path: /var/nfs_share
        owner: nobody
        group: nogroup
        mode: '777'

    - name: Add the directory to the NFS configuration file
      lineinfile:
        path: /etc/exports
        line: '/var/nfs_share *(rw,sync,no_subtree_check,no_root_squash)'

    - name: Export the shared directory and restart NFS service
      command:
        cmd: exportfs -a && systemctl restart nfs-kernel-server

Запустите плейбук с помощью Ansible. Вот пример того, как это может выглядеть в вашей командной оболочке:

ansible-playbook -i inventory.ini nfs_server.yaml

Этот плейбук установит NFS-сервер на целевой хост, создаст и сконфигурирует общий каталог (NFS-экспорт), и перезапустит службу NFS.

Настройка NFS-клиента с помощью Terraform и Helm

Для развертывания Helm Charts в кластере Kubernetes можно использовать Terraform. Ниже приведен пример сценария Terraform для установки NFS-клиента с использованием Helm-чарта nfs-subdir-external-provisioner.

  1. Установите провайдер Terraform для работы с Helm:

provider "helm" {
  kubernetes {
    config_path = "~/.kube/config"
  }
}
  1. Добавьте репозиторий, содержащий Helm-чарт “nfs-subdir-external-provisioner”:

data "helm_repository" "nfs" {
  name = "nfs-subdir-external-provisioner"
  url  = "https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/"
}
  1. Установите клиент NFS provisioner. Замените шаблоны <nfs-server> и <nfs-path> на IP-адрес вашего NFS-сервера и путь к экспортированному NFS-каталогу:

resource "helm_release" "nfs_client_provisioner" {
  name       = "nfs-client-provisioner"
  repository = data.helm_repository.nfs.metadata[0].name
  chart      = "nfs-subdir-external-provisioner"
  set {
    name  = "nfs.server"
    value = "<nfs-server>"
  }
  set {
    name  = "nfs.path"
    value = "<nfs-path>"
  }
}
  1. Выполните сценарий Terraform. Вот пример того, как это может выглядеть в вашей среде:

terraform init
terraform apply

Сценарий Terraform инициализирует Helm-провайдер, добавит Helm-репозиторий, содержащий nfs-subdir-external-provisioner и установит NFS client provisioner в кластер Kubernetes.

Проверка установки

  1. Проверьте, запущен ли NFS client provisioner:

kubectl get pods

Вы должны увидеть pod с названием nfs-client-provisioner-... в статусе RUNNING.

  1. Проверьте, создан ли Storage Class:

kubectl get sc

В списке должен появиться Storage Class с именем nfs-client (или тем именем, которое вы указали при установке).

Теперь, когда вы создаете Persistent Volume Claim со Storage Class “nfs-client”, Kubernetes будет динамически предоставлять Persistent Volume, используя указанный вами NFS-сервер и путь.

Установка Postgresql с помощью провайдера

Создадим ресурс Terraform helm_release для установки чарта PostgreSQL:

data "helm_repository" "bitnami" {
  name = "bitnami"
  url  = "https://charts.bitnami.com/bitnami"
}

resource "helm_release" "postgresql" {
  name       = "postgresql"
  chart      = "bitnami/postgresql"
  repository = data.helm_repository.bitnami.metadata[0].name
  set {
    name  = "persistence.storageClass"
    value = "nfs-client"
  }
  set {
    name  = "persistence.size"
    value = "1Gi"
  }
}

Этот Helm-чарт создаст Deployment c базой данных PostgreSQL, которая использует PersistentVolumeClaim для хранения данных. PVC использует Storage Class nfs-client, задействующий сервер NFS и путь, указанные в нашем предыдущем сценарии Terraform.

После добавления вышеуказанных ресурсов в сценарий Terraform, вы можете применить конфигурацию:

terraform apply

После завершения работы сценария убедитесь, что Kubernetes Deployment и Service для PostgreSQL запущены:

kubectl get deployments
kubectl get svc

Чтобы дополнительно убедиться в том, что данные PostgreSQL действительно хранятся на NFS-сервере, можно проверить точки подключения пода:

kubectl describe pod <postgresql-pod-name>

Вы увидите подключение (mount) для /bitnami/postgresql, а его PersistentVolumeClaim должен использовать класс хранения NFS.

Текст подготовлен при помощи инженеров Southbridge

От редакции

Говорить об Ansible можно очень много: этим-то мы и планируем заняться! Уже 10 августа пройдет первая встреча из цикла «IaC с Ansible». Наши инженеры поделятся подходами и покажут практическую сторону дела —  решения, которые использовали в реальном продакшене. И их можно забрать в своё пользование! 

Первая встреча пройдет 10 августа.

Зарегистрироваться на встречи можно по этой ссылке: https://southbridge.io/iac-ansible-southbridge

Комментарии (1)


  1. atshaman
    03.08.2023 07:25
    +3

    Не очень понятна цель упражнения - раздать nfs со сторажки в кластер - ок, норм, пусть и не самый сладкий сахарн.

    Делать самому... отказоустойчиовсти у решения нет - single point of failure на пустом месте. Делать nfs поверх кластеризованной ФС - того же gluster'а конечно можно - но прям такоЭ. Использовать для stateful-приложений, которые самостоятельно умеют в кластеризацию и репликацию данных - нуууу ооок, но не проще ли тогда local persistent volumes обмазаться - в плане удобства работы\управления\отказоустойчивости то на то будет минус оверхед на nfs. Опять же надо на структуру хранения смотреть - nfsv4 прям не любит большое количество файлов в одном каталоге, в tencent cloud для аналогичного сетапа прям непосредственная рекомендация - приколачивайте гвоздями nfsv3.

    Если уж nfs нам зачем-то нужен - то почему kernel реализация, а не nfs-ganesha? Последний определенно быстрее и лучше себя ведет при разрывах связи - с ним я с ситуацией "полного зависания сервера" не сталкивался, а вот с kernel nfs - было.

    В общем, троллейбус из буханки конечно почти как настоящий - но зачем?