Если вам требуется общее постоянное хранилище для приложений, работающих в OVHcloud Managed Kubernetes Service (MKS), то OVHcloud Enterprise File Storage (EFS) с Trident CSI предоставляет удобный способ его предоставления и управления.
В этой статье блога объясняется, как создать и подключить OVHcloud EFS к вашему кластеру MKS с помощью Trident CSI, чтобы вы могли динамически предоставлять постоянное хранилище для рабочих нагрузок Kubernetes.
OVHcloud Enterprise File System (EFS)
EFS — это высокопроизводительное полностью управляемое файловое хранилище на базе NetApp ONTAP в архитектуре active-active. Оно предназначено для корпоративных рабочих нагрузок, требующих высокой доступности, предсказуемой производительности и бесшовной интеграции с облачными средами.
Услуга доступна в нескольких регионах, включая Roubaix, Gravelines, Strasbourg, Limbourg и Beauharnois, с сильным SLA 99,99% времени безотказной работы. Емкость хранилища составляет от 50 ГБ до 29 ТБ.
EFS обеспечивает гарантированную производительность: 4 000 IOPS и 64 МБ/с пропускной способности на 1 ТБ, с линейным масштабированием в зависимости от размера тома благодаря инфраструктуре NVMe SSD.
Созданный для современных инфраструктур, EFS нативно интегрируется с Kubernetes через Trident CSI (совместим с MKS) и поддерживает доступ ReadWriteMany (RWX). Он работает в пределах одной зоны доступности (1AZ) и предоставляет низколатентное NFS-хранилище по защищенной сети vRack OVHcloud, обеспечивая высокую безопасность и соответствие требованиям.
NetApp Trident CSI
Trident — это проект с открытым исходным кодом для оркестрации хранилищ, полностью поддерживаемый NetApp. Он предназначен для того, чтобы помочь приложениям Kubernetes использовать постоянное хранилище через стандартные интерфейсы, такие как Container Storage Interface (CSI).
Trident работает непосредственно внутри кластеров Kubernetes как набор Pod и обеспечивает динамическое предоставление и управление хранилищем для контейнеризированных рабочих нагрузок. Он позволяет приложениям легко получать доступ к постоянному хранилищу из экосистемы NetApp, включая системы ONTAP (например, OVHcloud EFS).
Давайте сделаем это!
Создание EFS
У нас уже есть кластер MKS в регионе GRA11, работающий внутри частной сети и подсети с шлюзом.
У нас также есть vRack, и наш проект Public Cloud привязан к этому vRack.
Поэтому в этой статье мы создадим только новый EFS в регионе eu-west-rbx, привязанный к vRackServices, в той же подсети, что и наш существующий кластер MKS.
Вот архитектура всех сервисов:
⚠️ Регионы EFS и MKS могут различаться; имейте в виду, что задержка между разными регионами может повлиять на производительность ваших рабочих нагрузок хранилища. Настоятельно рекомендуется размещать хранилище и вычисления как можно ближе.
Мы развернем EFS в регионе eu-west-rbx, а не в eu-west-gra, чтобы показать вам, что это возможно.
Для развертывания EFS мы будем использовать Terraform-модуль OVHcloud EFS.
Используемый модуль может развернуть все компоненты, необходимые для использования EFS с кластером MKS (как показано на схеме).
Но в этой статье мы предполагаем, что уже развернуты:
- vRack
- Частная сеть
- Частная подсеть
- Шлюз
- Кластер MKS
Таким образом, используя Terraform-модуль, мы заполним информацию о существующих ресурсах и попросим Terraform создать:
- учётные данные OAuth2
- политику IAM
- EFS
- vRack Services
Давайте развернём наши компоненты с помощью Terraform!
Создайте файл provider.tf и заполните его информацией:
terraform {
required_providers {
ovh = {
source = "ovh/ovh"
version = ">= 2.12.0"
}
null = {
source = "hashicorp/null"
version = ">= 3.0.0"
}
}
required_version = ">= 1.7.0"
}
provider "ovh" {
}
Если вы не указываете информацию о провайдере в этом файле, как показано в примере, вы можете вместо этого задать переменные окружения со своими учётными данными:
# 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"
Создайте файл variable.tf.template и заполните его этой информацией:
# Existing services
variable "service_name" {
default = "$OVH_CLOUD_PROJECT_SERVICE"
}
variable "vrack_id" {
default = "pn-1234567" #ID of your existing vRack
}
variable "vlan_id" {
default = "666" #ID of your VLAN
}
variable "private_network_id" {
default = "d111cb65-1234-5678-9012-dac2e93b8944" #ID of your private network
}
variable "private_subnet_id" {
default = "d8dc2469-1234-5678-9012-1f86551d3466" #ID of your subnet
}
variable "vrackservices_subnet_service_range_cidr" {
default = "192.168.168.248/29" #CIDR of your private network
}
variable "private_subnet_cidr" {
default = "192.168.168.0/24" #CIDR of your subnet
}
variable "mks_region" {
default = "GRA11" #Region of your existing MKS cluster
}
variable "mks_cluster_id" {
default = "7c3e1e6e-1234-5678-9012-4fb5a5b145e7" #ID of your existing MKS cluster
}
# Services to create
variable "oauth2_client_name" {
default = "efs-trident-client-example"
}
variable "oauth2_client_description" {
default = "OAuth2 client for EFS Trident integration"
}
variable "iam_policy_name" {
default = "efs-trident-policy-example"
}
variable "iam_policy_description" {
default = "IAM policy for EFS Trident access"
}
variable "vrackservices_attach_to_efs" {
description = "Whether to attach the EFS service endpoint to vRack Services. Set to false before destroying."
type = bool
default = true
}
variable "efs_region" {
default = "eu-west-rbx"
}
variable "efs_name" {
default = "my-efs-storage"
}
variable "efs_plan" {
default = "enterprise-file-storage-premium-1tb"
}
⚠️ В файле замените ID, CIDR и регион MKS на информацию о ваших существующих ресурсах.
Замените значение переменной окружения OVH_CLOUD_PROJECT_SERVICE в файле variables.tf:
envsubst < variables.tf.template > variables.tf
Создайте файл efs.tf и заполните его информацией:
module "ovh_efs_trident" {
source = "ovh/efs/ovh//modules/efs-trident"
# Регион OVH для EFS и vRack Services
region = var.efs_region
# Регион Public Cloud для MKS и частной сети
public_cloud_region = var.mks_region
# ID VLAN должен быть одинаковым для vRack Services и частной сети Public Cloud
vlan_id = var.vlan_id
# Установите значение false перед уничтожением, чтобы сначала отсоединить конечную точку
vrackservices_attach_to_efs = var.vrackservices_attach_to_efs
# Создание EFS
storage_efs_name = var.efs_name
storage_efs_plan_code = var.efs_plan
# --- vRack ---
create_vrack = false
vrack_service_name = var.vrack_id
# --- Cloud Project ---
create_cloud_project = false
cloud_project_id = var.service_name
bind_vrack_to_cloud_project = false # Установите false, если уже привязано
# --- Частная сеть ---
create_private_network = false
private_network_id = var.private_network_id
# --- Частная подсеть ---
create_private_subnet = false
private_subnet_id = var.private_subnet_id
# --- Шлюз ---
create_gateway = false # Установите false, только если существующая сеть имеет шлюз
# --- Кластер MKS ---
create_mks_cluster = false
mks_cluster_id = var.mks_cluster_id # mks-priv-gra11
create_node_pool = false # Установите false, если используете существующий пул узлов
# OAuth2 и IAM
oauth2_client_name = var.oauth2_client_name
oauth2_client_description = var.oauth2_client_description
iam_policy_name = var.iam_policy_name
iam_policy_description = var.iam_policy_description
# Сеть (общая для vRack Services и Public Cloud)
private_network_subnet_cidr = var.private_subnet_cidr
vrackservices_subnet_service_range_cidr = var.vrackservices_subnet_service_range_cidr # EFS получает IP-адреса отсюда
}
Создайте файл output.tf со следующим содержимым:
output "client_id" {
value = module.ovh_efs_trident.client_id
}
output "client_secret" {
value = module.ovh_efs_trident.client_secret
sensitive = true
}
output "efs_id" {
value = module.ovh_efs_trident.efs_id
}
Конфигурация Terraform готова. Давайте инициализируем её:
terraform init
Вывод должен выглядеть так:
$ terraform init
Инициализация бэкенда...
Инициализация модулей...
Инициализация плагинов провайдеров...
- Повторное использование предыдущей версии hashicorp/null из файла блокировки зависимостей
- Повторное использование предыдущей версии ovh/ovh из файла блокировки зависимостей
- Использование ранее установленного hashicorp/null v3.2.4
- Использование ранее установленного ovh/ovh v2.13.1
Terraform успешно инициализирован!
Теперь вы можете начать работу с Terraform. Попробуйте выполнить "terraform plan", чтобы увидеть
возможные изменения, необходимые для вашей инфраструктуры. Все команды Terraform
теперь должны работать.
Если вы когда-либо изменяли модули или конфигурацию бэкенда для Terraform,
выполните эту команду повторно, чтобы переинициализировать рабочую директорию. Если вы забудете,
другие команды обнаружат это и напомнят вам сделать это при необходимости.
Примените конфигурацию:
terraform apply
Вывод должен быть следующим:
$ terraform apply
module.ovh_efs_trident.data.ovh_me.my_account: Reading...
module.ovh_efs_trident.data.ovh_cloud_project_kube.existing[0]: Reading...
module.ovh_efs_trident.data.ovh_cloud_project.existing[0]: Reading...
module.ovh_efs_trident.data.ovh_me.my_account: Read complete after 1s [id=xx12345-ovh]
module.ovh_efs_trident.data.ovh_cloud_project.existing[0]: Read complete after 0s
module.ovh_efs_trident.data.ovh_order_cart.cart: Reading...
module.ovh_efs_trident.data.ovh_order_cart.cart: Read complete after 0s [id=d582ab7c-1234-5678-9012-4a6e702ea4c5]
module.ovh_efs_trident.data.ovh_cloud_project_kube.existing[0]: Read complete after 5s [id=7c3e1e6e-1234-5678-9012-4fb5a5b145e7]
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.ovh_efs_trident.null_resource.config_validation will be created
+ resource "null_resource" "config_validation" {
+ id = (known after apply)
}
# module.ovh_efs_trident.ovh_iam_policy.iam_policy will be created
+ resource "ovh_iam_policy" "iam_policy" {
+ allow = [
+ "storageNetApp:apiovh:get",
+ "storageNetApp:apiovh:serviceInfos/get",
+ "storageNetApp:apiovh:share/accessPath/get",
+ "storageNetApp:apiovh:share/acl/create",
+ "storageNetApp:apiovh:share/acl/delete",
+ "storageNetApp:apiovh:share/acl/get",
+ "storageNetApp:apiovh:share/create",
+ "storageNetApp:apiovh:share/delete",
+ "storageNetApp:apiovh:share/edit",
+ "storageNetApp:apiovh:share/extend",
+ "storageNetApp:apiovh:share/get",
+ "storageNetApp:apiovh:share/revertToSnapshot",
+ "storageNetApp:apiovh:share/snapshot/create",
+ "storageNetApp:apiovh:share/snapshot/delete",
+ "storageNetApp:apiovh:share/snapshot/edit",
+ "storageNetApp:apiovh:share/snapshot/get",
]
+ created_at = (known after apply)
+ description = "IAM policy for EFS Trident access"
+ id = (known after apply)
+ identities = (known after apply)
+ name = "efs-trident-policy-example"
+ owner = (known after apply)
+ read_only = (known after apply)
+ resources = (known after apply)
+ updated_at = (known after apply)
}
# module.ovh_efs_trident.ovh_me_api_oauth2_client.api_oauth2_client will be created
+ resource "ovh_me_api_oauth2_client" "api_oauth2_client" {
+ client_id = (known after apply)
+ client_secret = (sensitive value)
+ description = "OAuth2 client for EFS Trident integration"
+ flow = "CLIENT_CREDENTIALS"
+ id = (known after apply)
+ identity = (known after apply)
+ name = "efs-trident-client-example"
}
# module.ovh_efs_trident.ovh_storage_efs.efs[0] will be created
+ resource "ovh_storage_efs" "efs" {
+ created_at = (known after apply)
+ iam = (known after apply)
+ id = (known after apply)
+ name = "my-efs-storage"
+ order = (known after apply)
+ ovh_subsidiary = "FR"
+ performance_level = (known after apply)
+ plan = [
+ {
+ configuration = [
+ {
+ label = "region"
+ value = "eu-west-rbx"
},
+ {
+ label = "network"
+ value = "vrack"
},
]
+ duration = "P1M"
+ plan_code = "enterprise-file-storage-premium-1tb"
+ pricing_mode = "default"
},
]
+ product = (known after apply)
+ quota = (known after apply)
+ region = (known after apply)
+ service_name = (known after apply)
+ status = (known after apply)
}
# module.ovh_efs_trident.ovh_vrack_vrackservices.vrack-vrackservices-binding[0] will be created
+ resource "ovh_vrack_vrackservices" "vrack-vrackservices-binding" {
+ id = (known after apply)
+ service_name = "pn-1234567"
+ vrack_services = (known after apply)
}
# module.ovh_efs_trident.ovh_vrackservices.vrackservices[0] will be created
+ resource "ovh_vrackservices" "vrackservices" {
+ checksum = (known after apply)
+ created_at = (known after apply)
+ current_state = (known after apply)
+ current_tasks = (known after apply)
+ iam = (known after apply)
+ id = (known after apply)
+ order = (known after apply)
+ ovh_subsidiary = "FR"
+ plan = [
+ {
+ configuration = [
+ {
+ label = "region_name"
+ value = "eu-west-rbx"
},
]
+ duration = "P1M"
+ plan_code = "vrack-services"
+ pricing_mode = "default"
},
]
+ resource_status = (known after apply)
+ target_spec = {
+ subnets = [
+ {
+ cidr = "192.168.168.0/24"
+ service_endpoints = [
+ {
+ managed_service_urn = (known after apply)
},
]
+ service_range = {
+ cidr = "192.168.168.248/29"
}
+ vlan = 666
# (1 unchanged attribute hidden)
},
]
}
+ updated_at = (known after apply)
}
Plan: 6 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ client_id = (known after apply)
+ client_secret = (sensitive value)
+ efs_id = (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.ovh_efs_trident.null_resource.config_validation: Creating...
module.ovh_efs_trident.null_resource.config_validation: Creation complete after 0s [id=8553589333890826101]
module.ovh_efs_trident.ovh_me_api_oauth2_client.api_oauth2_client: Creating...
module.ovh_efs_trident.ovh_storage_efs.efs[0]: Creating...
module.ovh_efs_trident.ovh_me_api_oauth2_client.api_oauth2_client: Creation complete after 0s [id=EU.xxxxxxxxxxxxx]
module.ovh_efs_trident.ovh_storage_efs.efs[0]: Still creating... [00m10s elapsed]
module.ovh_efs_trident.ovh_storage_efs.efs[0]: Still creating... [00m20s elapsed]
module.ovh_efs_trident.ovh_storage_efs.efs[0]: Still creating... [00m30s elapsed]
...
module.ovh_efs_trident.ovh_storage_efs.efs[0]: Still creating... [03m40s elapsed]
module.ovh_efs_trident.ovh_storage_efs.efs[0]: Still creating... [03m50s elapsed]
module.ovh_efs_trident.ovh_storage_efs.efs[0]: Creation complete after 3m52s [id=c2d759de-cd63-4e28-aaab-a7599aad2ca8]
module.ovh_efs_trident.ovh_vrackservices.vrackservices[0]: Creating...
module.ovh_efs_trident.ovh_iam_policy.iam_policy: Creating...
module.ovh_efs_trident.ovh_iam_policy.iam_policy: Creation complete after 0s [id=a434d1a4-1234-5678-9012-cf54251eee52]
module.ovh_efs_trident.ovh_vrackservices.vrackservices[0]: Still creating... [00m10s elapsed]
module.ovh_efs_trident.ovh_vrackservices.vrackservices[0]: Still creating... [00m20s elapsed]
...
module.ovh_efs_trident.ovh_vrackservices.vrackservices[0]: Still creating... [01m20s elapsed]
module.ovh_efs_trident.ovh_vrackservices.vrackservices[0]: Creation complete after 1m30s [id=vrs-a00-b11-c22-d33]
module.ovh_efs_trident.ovh_vrack_vrackservices.vrack-vrackservices-binding[0]: Creating...
module.ovh_efs_trident.ovh_vrack_vrackservices.vrack-vrackservices-binding[0]: Still creating... [00m10s elapsed]
module.ovh_efs_trident.ovh_vrack_vrackservices.vrack-vrackservices-binding[0]: Still creating... [00m20s elapsed]
...
module.ovh_efs_trident.ovh_vrack_vrackservices.vrack-vrackservices-binding[0]: Still creating... [01m40s elapsed]
module.ovh_efs_trident.ovh_vrack_vrackservices.vrack-vrackservices-binding[0]: Creation complete after 1m43s [id=vrack_pn-1234567-vrackServices_vrs-a00-b11-c22-d33]
Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
Outputs:
client_id = "EU.xxxxxxxxxxxxx"
client_secret = <sensitive>
efs_id = "c2d759de-cd63-4e28-aaab-a7599aad2ca8"
Сохраните учетные данные OAuth2 в переменных окружения:
export EFS_CLIENT_ID=$(terraform output -raw client_id)
export EFS_CLIENT_SECRET=$(terraform output -raw client_secret)
Установка Trident CSI
Установите оператор Trident в ваш кластер MKS:
helm repo add netapp-trident https://netapp.github.io/trident-helm-chart
helm install trident-operator netapp-trident/trident-operator
--version 100.2502.1
--create-namespace
--namespace trident
--set tridentSilenceAutosupport=true
--set operatorImage="ovhcom/trident-operator:25.02.1-linux-amd64"
--set tridentImage="ovhcom/trident:25.02.1-linux-amd64"
Результат должен выглядеть так:
$ helm install trident-operator netapp-trident/trident-operator
--version 100.2502.1
--create-namespace
--namespace trident
--set tridentSilenceAutosupport=true
--set operatorImage="ovhcom/trident-operator:25.02.1-linux-amd64"
--set tridentImage="ovhcom/trident:25.02.1-linux-amd64"
NAME: trident-operator
LAST DEPLOYED: Tue Apr 28 14:01:19 2026
NAMESPACE: trident
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Благодарим вас за установку trident-operator, который развернёт и будет управлять CSI-провайдером
хранилища NetApp Trident для Kubernetes.
Ваш релиз называется 'trident-operator' и установлен в пространство имён 'trident'.
Обратите внимание: в кластере Kubernetes должен быть только один экземпляр Trident (и trident-operator).
Для настройки Trident на управление ресурсами хранилища вам понадобится копия tridentctl, которая
доступна в предварительно упакованных релизах Trident. Все релизы Trident и исходный код можно найти
онлайн на https://github.com/NetApp/trident.
Чтобы узнать больше о релизе, попробуйте:
$ helm status trident-operator
$ helm get all trident-operator
После завершения установки убедитесь, что все поды Trident находятся в состоянии Running в пространстве имён trident, прежде чем продолжить:
$ kubectl get pods -n trident
NAME READY STATUS RESTARTS AGE
trident-controller-5bf6c8d6f6-g95jq 6/6 Running 0 119s
trident-node-linux-4xtjr 2/2 Running 1 (82s ago) 119s
trident-node-linux-6w5ff 2/2 Running 1 (82s ago) 119s
trident-node-linux-r7hxp 2/2 Running 0 119s
trident-operator-859f59c58b-2z2ts 1/1 Running 0 2m31s
Создание бэкенда Trident
Бэкенд Trident подключает NetApp Trident к сервису OVHcloud EFS, используя ранее созданные учётные данные IAM.
1. Создание секрета
Создайте Secret Kubernetes, содержащий информацию для подключения, которая позволит Trident обращаться к API OVHcloud. Создайте файл trident-secret.yaml.template со следующим содержимым:
apiVersion: v1
kind: Secret
metadata:
name: ovh-efs-secret
type: Opaque
stringData:
clientID: "$EFS_CLIENT_ID" # ваш clientId
clientSecret: "$EFS_CLIENT_SECRET" # ваш clientSecret
Замените значения clientID и clientSecret на данные OAuth2-клиента, который мы создали с помощью Terraform:
envsubst < trident-secret.yaml.template > trident-secret.yaml
Примените секрет в вашем кластере:
kubectl apply -f trident-secret.yaml -n trident
Проверьте, что секрет создан корректно:
$ kubectl get secret ovh-efs-secret -n trident
NAME TYPE DATA AGE
ovh-efs-secret Opaque 2 3s
2. Создание бэкенда Trident
Создайте ваш бэкенд с помощью команды ниже:
cat <<EOF | kubectl create -n trident -f -
apiVersion: trident.netapp.io/v1
kind: TridentBackendConfig
metadata:
name: ovh-efs-rbx
spec:
version: 1
backendName: backend-ovh-efs
defaults:
exportRule: "192.168.168.0/24" # CIDR вашей сети для NFS ACL
storageDriverName: ovh-efs
clientLocation: ovh-eu
location: eu-west-rbx # Расположение вашего сервиса EFS
serviceLevel: premium
nfsMountOptions: rw,hard,rsize=65536,wsize=65536,nfsvers=3,tcp
credentials:
name: ovh-efs-secret
volumeCreateTimeout: "60"
EOF
⚠️ Необходимо использовать драйвер хранилища ovh-efs. Замените exportRule, location и другие параметры значениями, соответствующими вашему окружению.
Проверьте, что бэкенд создан корректно, с помощью команды ниже:
$ kubectl get TridentBackendConfig -n trident
NAME BACKEND NAME BACKEND UUID PHASE STATUS
ovh-efs-rbx backend-ovh-efs ace12d67-70ea-44e1-abd8-20d016f7f030 Bound Success
Использование EFS в вашем кластере MKS
В этом разделе описывается, как предоставить Enterprise File Storage рабочим нагрузкам Kubernetes с помощью Trident.
1. StorageClass
В файле sc_efs.yaml определите StorageClass для включения динамического выделения ресурсов через драйвер CSI Trident:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ovh-efs-premium
provisioner: csi.trident.netapp.io
parameters:
backendType: "ovh-efs"
fsType: "nfs"
allowVolumeExpansion: true
Примените StorageClass:
kubectl apply -f sc_efs.yaml
Проверьте, что StorageClass создан:
$ kubectl get sc ovh-efs-premium
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
ovh-efs-premium csi.trident.netapp.io Delete Immediate true 3h13m
Этот StorageClass позволяет выделять тома по требованию и динамически расширять их.
2. Создание тома (PVC)
Создайте PersistentVolumeClaim с режимом доступа ReadWriteMany (RWX). Создайте файл pvc_efs.yaml со следующим содержимым:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: premium-pvc-efs
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Gi
storageClassName: ovh-efs-premium
Примените его:
kubectl apply -f pvc_efs.yaml
Проверьте, что PVC создан, с помощью команды ниже:
kubectl get pvc premium-pvc-efs
На этом этапе EFS создаёт том, назначает правильный ACL и монтирует его в PVC
Через некоторое время вывод должен показать PVC в состоянии Bound:
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
premium-pvc-efs Bound pvc-faca364d-ad76-44ec-9bc9-959c0d33c515 100Gi RWX ovh-efs-premium <unset> 3m43s
Том создан через PVC, и теперь вы можете смонтировать его в Pod 🎉.
Заключение
В этом блоге мы объяснили, как создать EFS и использовать его в кластере MKS через Trident CSI. Это даст вам гибкий, готовый к эксплуатации подход к постоянному общему хранилищу в Kubernetes.

Комментарии
Категории
Случайное

Простое руководство по передаче файлов

Как сделать отступ в WordPress:

Освобождаем место на хостинге:

Полный контроль над AI-агентами Hermes
