
Jeśli uruchamiasz aplikacje stanowe (stateful) w Kubernetes, jednym z typowych wyzwań jest zapewnienie trwałej, współdzielonej przestrzeni dyskowej dostępnej dla wielu obciążeń.
Trwałe wolumeny Kubernetes zazwyczaj wykorzystują pamięć blokową w trybie ReadWriteOnce. Niektóre aplikacje wymagają jednak współdzielonego systemu plików, który obsługuje dostęp ReadWriteMany (RWX).
OVHcloud File Storage udostępnia zarządzane udziały NFS, z których aplikacje działające w Kubernetes mogą dynamicznie korzystać za pośrednictwem sterownika Manila CSI.
W tym artykule pokażemy, jak zintegrować OVHcloud File Storage z usługą OVHcloud Managed Kubernetes Service (MKS) za pomocą Manila CSI i przetestować możliwości współdzielenia danych w trybie RWX.
OVHcloud File Storage

OVHcloud Public Cloud File Storage to w pełni zarządzana usługa współdzielonego przechowywania plików, przeznaczona do obsługi aplikacji cloud native uruchamianych na instancjach Public Cloud i w klastrach Kubernetes.
Usługa opiera się na OpenStack Manila i udostępnia współdzielone wolumeny NFSv3, które można jednocześnie montować na wielu serwerach. Jest to rozwiązanie odpowiednie dla aplikacji wymagających dostępu ReadWriteMany (RWX). Pojemność wolumenów wynosi od 150 GiB do 10 TiB, a ich wydajność rośnie liniowo wraz z przydzieloną przestrzenią dyskową, co zapewnia przewidywalną wydajność.
Usługa jest w pełni zarządzana, dlatego nie musisz samodzielnie uruchamiać ani utrzymywać serwera NFS. Usługą File Storage możesz zarządzać przez Panel klienta OVHcloud, API, CLI i Terraform. Sterownik Manila CSI umożliwia natomiast dynamiczne tworzenie współdzielonych wolumenów bezpośrednio z klastra Kubernetes.
Dlaczego warto korzystać z Manila CSI?
Container Storage Interface (CSI) to standardowy mechanizm integracji zewnętrznych systemów przechowywania danych w Kubernetes.
Zamiast ręcznie konfigurować montowanie zasobów NFS i wolumeny PersistentVolume, możesz użyć sterownika Manila CSI. Umożliwia on dynamiczne tworzenie udziałów i zarządzanie nimi za pomocą obiektów Kubernetes, takich jak StorageClass (SC), PersistentVolumeClaim (PVC) i PersistentVolume (PV).
Wymagania wstępne
Przed rozpoczęciem wykonaj następujące czynności:
- Utwórz projekt OVHcloud Public Cloud
- Utwórz klaster OVHcloud Managed Kubernetes Service (MKS) i podłącz go do sieci prywatnej
- Zainstaluj Terraform CLI
- Zainstaluj kubectl CLI
Konfiguracja Manila CSI krok po kroku
W tym przykładzie wykorzystamy istniejący klaster MKS w regionie EU-WEST-PAR, działający w sieci prywatnej z wydzieloną podsiecią. Wykonaj następujące kroki:
- Utwórz użytkownika Public Cloud dla sterownika Manila CSI
- Zainstaluj sterownik CSI NFS
- Zainstaluj sterownik Manila CSI
- Utwórz obiekt Secret, który umożliwia sterownikowi Manila CSI uwierzytelnianie w OpenStack i zarządzanie zasobami Manila w klastrze
- Utwórz sieć dla współdzielonych zasobów plikowych
- Utwórz obiekt ConfigMap z konfiguracją sterownika Manila CSI
- Utwórz klasę StorageClass csi-manila-nfs, która umożliwia sterownikowi Manila CSI dynamiczne tworzenie udziałów Manila i udostępnianie ich jako wolumenów Kubernetes
Do wdrożenia tej architektury wykorzystamy Terraform.
Utwórz plik provider.tf i wprowadź poniższe dane:
terraform {
required_providers {
helm = {
source = "hashicorp/helm"
}
kubectl = {
source = "alekc/kubectl"
version = "2.1.6"
}
ovh = {
source = "ovh/ovh"
}
}
}
provider "helm" {
kubernetes = {
host = data.ovh_cloud_project_kube.mks_cluster.kubeconfig_attributes[0].host
client_certificate = base64decode(data.ovh_cloud_project_kube.mks_cluster.kubeconfig_attributes[0].client_certificate)
client_key = base64decode(data.ovh_cloud_project_kube.mks_cluster.kubeconfig_attributes[0].client_key)
cluster_ca_certificate = base64decode(data.ovh_cloud_project_kube.mks_cluster.kubeconfig_attributes[0].cluster_ca_certificate)
}
}
provider "kubectl" {
host = data.ovh_cloud_project_kube.mks_cluster.kubeconfig_attributes[0].host
client_certificate = base64decode(data.ovh_cloud_project_kube.mks_cluster.kubeconfig_attributes[0].client_certificate)
client_key = base64decode(data.ovh_cloud_project_kube.mks_cluster.kubeconfig_attributes[0].client_key)
cluster_ca_certificate = base64decode(data.ovh_cloud_project_kube.mks_cluster.kubeconfig_attributes[0].cluster_ca_certificate)
load_config_file = false
}Ustaw zmienne środowiskowe zawierające dane uwierzytelniające dla dostawcy Terraform OVHcloud:
# OVHcloud provider needed keys
export OVH_ENDPOINT="ovh-eu"
export OVH_APPLICATION_KEY="xxx"
export OVH_APPLICATION_SECRET="xxx"
export OVH_CONSUMER_KEY="xxx"
export OVH_CLOUD_PROJECT_SERVICE="xxx"Utwórz plik variables.tf.template i wprowadź poniższe dane:
variable "service_name" {
default = "$OVH_CLOUD_PROJECT_SERVICE"
}
variable "mks_cluster_id" {
default = "<your_mks_cluster_id>"
}⚠️ W pliku zastąp identyfikator MKS identyfikatorem istniejącego klastra MKS.
Zmień wartość zmiennej środowiskowej OVH_CLOUD_PROJECT_SERVICE w pliku variables.tf:
envsubst < variables.tf.template > variables.tfUtwórz plik nfs_share.tf i wprowadź poniższe dane:
data "ovh_cloud_project_kube" "mks_cluster" {
service_name = var.service_name
kube_id = var.mks_cluster_id
}
data "ovh_cloud_network_private_vrack_subnet" "mks_cluster_subnet" {
service_name = var.service_name
network_id = data.ovh_cloud_project_kube.mks_cluster.private_network_id
id = data.ovh_cloud_project_kube.mks_cluster.nodes_subnet_id
}
# CSI Manila
module "csi_manila" {
source = "git::https://github.com/ovh/public-cloud-examples.git//containers-orchestration/managed-kubernetes/install-csi-manila/modules/ovhcloud/csi_manila?ref=v1.5.0"
service_name = var.service_name
region = data.ovh_cloud_project_kube.mks_cluster.region
share_network_name = "${data.ovh_cloud_project_kube.mks_cluster.name}-share-network"
network_id = data.ovh_cloud_project_kube.mks_cluster.private_network_id
subnet_id = data.ovh_cloud_project_kube.mks_cluster.nodes_subnet_id
subnet_cidr = data.ovh_cloud_network_private_vrack_subnet.mks_cluster_subnet.cidr
}
output "manila-user" {
value = module.csi_manila.manila-user
}💡W tym pliku Terraform korzystamy z istniejącego modułu csi_manila, dostępnego w repozytorium OVHcloud Public Cloud Examples na GitHubie.
Konfiguracja Terraform jest gotowa. Teraz uruchom polecenie inicjalizacji:
terraform initPowinien pojawić się wynik podobny do poniższego:
$ terraform init
Initializing the backend...
Initializing modules...
Downloading git::https://github.com/ovh/public-cloud-examples.git?ref=v1.5.0 for csi_manila...
- csi_manila in .terraform/modules/csi_manila/containers-orchestration/managed-kubernetes/install-csi-manila/modules/ovhcloud/csi_manila
Initializing provider plugins...
- Reusing previous version of hashicorp/helm from the dependency lock file
- Reusing previous version of alekc/kubectl from the dependency lock file
- Reusing previous version of ovh/ovh from the dependency lock file
- Installing hashicorp/helm v3.2.0...
- Installed hashicorp/helm v3.2.0 (signed by HashiCorp)
- Installing alekc/kubectl v2.1.6...
- Installed alekc/kubectl v2.1.6 (self-signed, key ID 772FB27A86DAFCE7)
- Installing ovh/ovh v2.16.1...
- Installed ovh/ovh v2.16.1 (signed by a HashiCorp partner, key ID F56D1A6CBDAAADA5)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://developer.hashicorp.com/terraform/cli/plugins/signing
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.Uruchom polecenie:
terraform applyPowinien pojawić się wynik podobny do poniższego:
$ terraform apply
data.ovh_cloud_project_kube.mks_cluster: Reading...
data.ovh_cloud_project_kube.mks_cluster: Read complete after 1s [id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx]
data.ovh_cloud_network_private_vrack_subnet.mks_cluster_subnet: Reading...
data.ovh_cloud_network_private_vrack_subnet.mks_cluster_subnet: Read complete after 1s [id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.csi_manila.helm_release.csi-driver-nfs will be created
+ resource "helm_release" "csi-driver-nfs" {
+ atomic = false
+ chart = "csi-driver-nfs"
+ cleanup_on_fail = false
+ create_namespace = false
+ dependency_update = false
+ disable_crd_hooks = false
+ disable_openapi_validation = false
+ disable_webhooks = false
+ force_update = false
+ id = (known after apply)
+ lint = false
+ max_history = 0
+ metadata = (known after apply)
+ name = "csi-driver-nfs"
+ namespace = "kube-system"
+ pass_credentials = false
+ recreate_pods = false
+ render_subchart_notes = true
+ replace = false
+ repository = "https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts"
+ reset_values = false
+ reuse_values = false
+ set_wo = (write-only attribute)
+ skip_crds = false
+ status = "deployed"
+ take_ownership = false
+ timeout = 300
+ upgrade_install = false
+ verify = false
+ version = "4.13.4"
+ wait = true
+ wait_for_jobs = false
}
# module.csi_manila.helm_release.openstack-manila-csi will be created
+ resource "helm_release" "openstack-manila-csi" {
+ atomic = false
+ chart = "openstack-manila-csi"
+ cleanup_on_fail = false
+ create_namespace = false
+ dependency_update = false
+ disable_crd_hooks = false
+ disable_openapi_validation = false
+ disable_webhooks = false
+ force_update = false
+ id = (known after apply)
+ lint = false
+ max_history = 0
+ metadata = (known after apply)
+ name = "openstack-manila-csi"
+ namespace = "kube-system"
+ pass_credentials = false
+ recreate_pods = false
+ render_subchart_notes = true
+ replace = false
+ repository = "https://kubernetes.github.io/cloud-provider-openstack"
+ reset_values = false
+ reuse_values = false
+ set_wo = (write-only attribute)
+ skip_crds = false
+ status = "deployed"
+ take_ownership = false
+ timeout = 300
+ upgrade_install = false
+ verify = false
+ version = "2.36.0"
+ wait = true
+ wait_for_jobs = false
}
# module.csi_manila.kubectl_manifest.csi-manila-secrets will be created
+ resource "kubectl_manifest" "csi-manila-secrets" {
+ api_version = (known after apply)
+ apply_only = false
+ field_manager = "kubectl"
+ force_conflicts = false
+ force_new = false
+ id = (known after apply)
+ kind = (known after apply)
+ live_manifest_incluster = (sensitive value)
+ live_uid = (known after apply)
+ name = (known after apply)
+ namespace = (known after apply)
+ server_side_apply = false
+ uid = (known after apply)
+ validate_schema = true
+ wait_for_rollout = true
+ yaml_body = (sensitive value)
+ yaml_body_parsed = (known after apply)
+ yaml_incluster = (sensitive value)
}
# module.csi_manila.kubectl_manifest.manila-runtime-configmap will be created
+ resource "kubectl_manifest" "manila-runtime-configmap" {
+ api_version = "v1"
+ apply_only = false
+ field_manager = "kubectl"
+ force_conflicts = false
+ force_new = false
+ id = (known after apply)
+ kind = "ConfigMap"
+ live_manifest_incluster = (sensitive value)
+ live_uid = (known after apply)
+ name = "manila-csi-runtimeconf-cm"
+ namespace = "default"
+ server_side_apply = false
+ uid = (known after apply)
+ validate_schema = true
+ wait_for_rollout = true
+ yaml_body = (sensitive value)
+ yaml_body_parsed = <<-EOT
apiVersion: v1
data:
runtimeconfig.json: |
{
"nfs": {
"matchExportLocationAddress": "10.1.0.0/16"
}
}
kind: ConfigMap
metadata:
annotations:
meta.helm.sh/release-name: manila-csi
meta.helm.sh/release-namespace: default
labels:
app.kubernetes.io/managed-by: Helm
name: manila-csi-runtimeconf-cm
namespace: default
EOT
+ yaml_incluster = (sensitive value)
}
# module.csi_manila.kubectl_manifest.storage-class will be created
+ resource "kubectl_manifest" "storage-class" {
+ api_version = (known after apply)
+ apply_only = false
+ field_manager = "kubectl"
+ force_conflicts = false
+ force_new = false
+ id = (known after apply)
+ kind = (known after apply)
+ live_manifest_incluster = (sensitive value)
+ live_uid = (known after apply)
+ name = (known after apply)
+ namespace = (known after apply)
+ server_side_apply = false
+ uid = (known after apply)
+ validate_schema = true
+ wait_for_rollout = true
+ yaml_body = (sensitive value)
+ yaml_body_parsed = (known after apply)
+ yaml_incluster = (sensitive value)
}
# module.csi_manila.ovh_cloud_project_user.manila-user will be created
+ resource "ovh_cloud_project_user" "manila-user" {
+ creation_date = (known after apply)
+ description = "User for the Manila CSI driver"
+ id = (known after apply)
+ openstack_rc = (known after apply)
+ password = (sensitive value)
+ role_name = "share_operator"
+ roles = (known after apply)
+ service_name = "xxxxxxxxxxxxxxxxxxxxx"
+ status = (known after apply)
+ username = (known after apply)
}
# module.csi_manila.ovh_cloud_storage_file_share_network.sharenetwork will be created
+ resource "ovh_cloud_storage_file_share_network" "sharenetwork" {
+ checksum = (known after apply)
+ created_at = (known after apply)
+ current_state = (known after apply)
+ description = (known after apply)
+ id = (known after apply)
+ name = "mks_standard_3az-share-network"
+ network_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
+ region = "EU-WEST-PAR"
+ resource_status = (known after apply)
+ service_name = "xxxxxxxxxxxxxxxxxxxxx"
+ subnet_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
+ updated_at = (known after apply)
}
Plan: 7 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ manila-user = (known after apply)
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
module.csi_manila.ovh_cloud_storage_file_share_network.sharenetwork: Creating...
module.csi_manila.ovh_cloud_project_user.manila-user: Creating...
module.csi_manila.kubectl_manifest.manila-runtime-configmap: Creating...
module.csi_manila.kubectl_manifest.manila-runtime-configmap: Creation complete after 0s [id=/api/v1/namespaces/default/configmaps/manila-csi-runtimeconf-cm]
module.csi_manila.helm_release.csi-driver-nfs: Creating...
module.csi_manila.ovh_cloud_storage_file_share_network.sharenetwork: Still creating... [00m10s elapsed]
module.csi_manila.ovh_cloud_project_user.manila-user: Still creating... [00m10s elapsed]
module.csi_manila.ovh_cloud_storage_file_share_network.sharenetwork: Creation complete after 12s [id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx]
module.csi_manila.kubectl_manifest.storage-class: Creating...
module.csi_manila.ovh_cloud_project_user.manila-user: Creation complete after 13s [id=718526]
module.csi_manila.kubectl_manifest.csi-manila-secrets: Creating...
module.csi_manila.kubectl_manifest.csi-manila-secrets: Creation complete after 1s [id=/api/v1/namespaces/default/secrets/csi-manila-secrets]
...Dynamiczne tworzenie przestrzeni File Storage w Kubernetes
Teraz utwórz w klastrze Kubernetes plik pvc.yaml i wprowadź poniższe dane:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-share-fs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 150Gi
storageClassName: csi-manila-nfsZastosuj konfigurację PersistentVolumeClaim (PVC), dzięki której użytkownicy Kubernetes mogą przydzielać współdzieloną przestrzeń dyskową:
kubectl apply -f pvc.yamlSprawdź status PVC:
kubectl get pvc nfs-share-fs-pvcPoczekaj, aż status PVC zmieni się na Bound.
Wynik powinien wyglądać następująco:
$ kubectl get pvc nfs-share-fs-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
nfs-share-fs-pvc Bound pvc-af1349b7-eb51-43ac-b0f0-94d0e8139c57 150Gi RWX csi-manila-nfs <unset> 3h48mUtwórz plik deploy.yaml i wprowadź poniższe dane:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
volumes:
- name: nfs-share-fs-pvc
persistentVolumeClaim:
claimName: nfs-share-fs-pvc
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: nfs-share-fs-pvcZastosuj konfigurację, która tworzy jeden pod z wolumenem podłączonym za pomocą nfs-share-fs-pvc:
kubectl apply -f deploy.yamlSprawdź, czy pod działa:
kubectl get podWynik powinien wyglądać następująco:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-6cbf9b898c-svpzf 1/1 Running 0 6mSprawdź, czy można skalować wdrożenie (podłączenie tego samego wolumenu do wielu podów):
kubectl scale deploy/nginx-deployment --replicas=2Sprawdź, czy drugi pod działa:
kubectl get podWynik powinien wyglądać następująco:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-6cbf9b898c-867bq 1/1 Running 0 3m
nginx-deployment-6cbf9b898c-svpzf 1/1 Running 0 9mAby sprawdzić działanie trybu RWX, połącz się z jednym z podów i utwórz plik w zamontowanym katalogu (np. /usr/share/nginx/html).
MY_POD=$(kubectl get po -o name | sed -n '1p')
echo $MY_POD
#Create a file in the pod number 1
kubectl exec $MY_POD -it -- touch /usr/share/nginx/html/index.htmlNastępnie połącz się z drugim podem i sprawdź, czy plik jest w nim widoczny:
MY_POD_2=$(kubectl get po -o name | sed -n '2p')
echo $MY_POD_2
#Display it in the pod number two
kubectl exec $MY_POD_2 -it -- ls -alrt /usr/share/nginx/html/Wynik powinien wyglądać następująco:
$ kubectl exec $MY_POD_2 -it -- ls -alrt /usr/share/nginx/html/
total 24
drwxr-xr-x 3 root root 4096 Jul 14 01:22 ..
drwx------ 2 root root 16384 Jul 15 09:18 lost+found
drwxrwxrwx 3 root root 4096 Jul 15 09:32 .
-rw-r--r-- 1 root root 0 Jul 15 13:09 index.htmlGotowe! Udział sieciowy Manila jest już udostępniony przez NFS i działa zgodnie z Twoimi oczekiwaniami! 🎉
Podsumowanie
W tym artykule pokazaliśmy, jak za pomocą sterownika Manila CSI i usługi OVHcloud File Storage można dynamicznie przydzielać aplikacjom Kubernetes współdzieloną przestrzeń dyskową.
Zachęcamy również do zapoznania się z Cloud Roadmap & Changelog, gdzie znajdziesz informacje o wszystkich funkcjach planowanych w usługach OVHcloud Public Cloud.