Seagate Exos X CSI (ME5 dual‑site) — Guía de instalación y operación
Este README documenta cómo he dejado reproducible la instalación del Seagate Exos X CSI Driver (soporta ME5) en un clúster Kubernetes con dos cabinas / dos zonas (site‑a y site‑b) usando iSCSI + multipath y topología por zona.
Objetivo
- Un único despliegue del driver (Helm).
- Dos StorageClass (uno por sitio) con
allowedTopologiesy credenciales (Secret) separadas.- WaitForFirstConsumer para que el volumen se cree en la misma zona del pod.
- Montajes iSCSI rápidos gracias a multipath bien configurado (modo
greedy).
1) Prerrequisitos en los nodos
-
Multipath y iSCSI instalados/activos.
-
/etc/multipath.conf — opciones relevantes usadas:
defaults {
user_friendly_names "no"
find_multipaths "greedy"
no_path_retry "queue"
}
devices {
device {
vendor "DellEMC"
product "ME5"
path_grouping_policy "multibus"
path_checker "tur"
prio "alua"
}
}
Por qué
greedy?
find_multipaths "greedy"evita crear maps hasta que haya más de un camino o el dispositivo sea claramente multipath, reduciendo falsos positivos y estabilizando el udev settle. Mejora tiempos de descubrimiento y evita flapping.
Reiniciar servicios y refrescar paths tras cambiar multipath:
sudo systemctl restart multipathd
sudo multipath -r
- Propagación de montajes (rshared)
Asegurar que / y /var/lib/kubelet están en rshared para que los montajes hechos por el plugin dentro del pod del node‑server aparezcan en el host:
sudo mount --make-rshared /
# systemd drop‑in para kubelet
sudo install -d /etc/systemd/system/kubelet.service.d
cat <<'EOF' | sudo tee /etc/systemd/system/kubelet.service.d/10-mount-propagation.conf
[Service]
MountFlags=
ExecStartPre=/bin/mkdir -p /var/lib/kubelet
ExecStartPre=/bin/mount --bind /var/lib/kubelet /var/lib/kubelet
ExecStartPre=/bin/mount --make-rshared /var/lib/kubelet
EOF
sudo systemctl daemon-reload
sudo systemctl restart kubelet
Comprobar:
sudo findmnt -o TARGET,PROPAGATION /
sudo findmnt -o TARGET,PROPAGATION /var/lib/kubelet
- Etiquetas de topología en nodos
Etiquetar cada nodo con su zona:
kubectl label nodes <nodo-del-site-a> topology.kubernetes.io/zone=site-a --overwrite
kubectl label nodes <nodo-del-site-b> topology.kubernetes.io/zone=site-b --overwrite
2) Despliegue del Driver con Helm
2.1. Namespace y valores
kubectl apply -f namespace.yaml # namespace: seagate
values.yaml (resumen de lo usado):
-
Imagen del driver:
ghcr.io/seagate/seagate-exos-x-csi:v1.10.0 -
Sidecars:
csi-provisioner v5.0.1(timeout 60s)csi-attacher v4.6.1csi-resizer v1.11.1csi-snapshotter v8.0.1csi-node-driver-registrar v2.9.0
-
controller.extraArgs: ["-v=2"] -
node.extraArgs: ["-v=2"]
Nota: no es necesario tocar
CSIDriverpara topología; la topología se maneja desde losStorageClass+ etiquetas de nodo.
2.2. Instalación
helm upgrade --install exos-x-csi \
-n seagate --create-namespace \
./seagate-exos-x-csi \
-f ./values.yaml
Si hay residuos de una instalación anterior (RBAC)
Si aparece un error de invalid ownership metadata con recursos tipo ClusterRole/ClusterRoleBinding de un release previo (p.ej. exosx-csi), eliminarlos:
kubectl delete clusterrole external-provisioner-runner-systems
kubectl delete clusterrolebinding csi-provisioner-role-systems
# (si hubiera más, listarlos por label y borrarlos)
# kubectl get clusterrole,clusterrolebinding -A -l app.kubernetes.io/instance=<old-release>
Reintentar helm upgrade --install.
3) Secret por cabina (A y B)
Un Secret por sitio en el namespace seagate con apiAddress, username, password en Base64.
kubectl apply -f secret-me5-site-a.yaml
kubectl apply -f secret-me5-site-b.yaml
Importante: Los
StorageClassdeben usar las claves estándar CSI para que el provisioner pase el Secret al driver:
csi.storage.k8s.io/provisioner-secret-name|namespacecsi.storage.k8s.io/controller-publish-secret-name|namespacecsi.storage.k8s.io/controller-expand-secret-name|namespacecsi.storage.k8s.io/node-stage-secret-name|namespace(si aplica)csi.storage.k8s.io/node-publish-secret-name|namespace(si aplica)
El síntoma de no usar estos nombres es: missing API credentials en el evento del PVC.
4) StorageClass por zona (topología)
Se definen dos StorageClass idénticos salvo:
- Secret (A o B)
pool(p. ej.,dg01para site‑a,dg02para site‑b)volPrefix(ej.sza/szbpara identificar site en el nombre de LUN)allowedTopologiescon la zona correspondientevolumeBindingMode: WaitForFirstConsumer
Con WFFC, el PVC no se enlaza hasta que exista un Pod consumidor; el scheduler elige un nodo, y el provisioner crea el volumen en la zona del nodo.
Aplicar ambos StorageClass:
kubectl apply -f sc-me5-site-a.yaml
kubectl apply -f sc-me5-site-b.yaml
5) Prueba de extremo a extremo
5.1. PVC + Pod en site‑a
- PVC:
pvc-aconstorageClassName: sc-me5-site-a - Pod:
pod-aconnodeSelector: topology.kubernetes.io/zone=site-a
kubectl apply -f pvc-pod-a.yaml
kubectl apply -f pod-a.yaml
kubectl get pvc,pod
Deberías ver el Pod en Running y el volumen creado/montado en la ME5 del site‑a.
5.2. Verificaciones útiles
- iSCSI nodes vistos:
sudo iscsiadm -m node | sort
- Multipath:
sudo multipath -ll
- Eventos del PVC:
kubectl describe pvc <nombre>
- Logs del controller: (búsqueda de credenciales / errores de provisión)
kubectl -n seagate logs deploy/seagate-exos-x-csi-controller-server \
-c seagate-exos-x-csi-controller | grep -i -E 'cred|secret|error'
6) Medir el tiempo de NodePublish (montaje)
Para medir cuánto tarda el montaje (fase NodePublishVolume) desde el node‑server:
kubectl -n seagate logs -l name=seagate-exos-x-csi-node-server \
-c seagate-exos-x-csi-node --tail=10000 \
| grep "NodePublishVolume" \
| grep "ROUTINE END" \
| sed -E 's/.*NodePublishVolume.*<([^>]*)>.*/\1/'
- Valores ~< 2 min indican que el montaje completa dentro de la ventana de kubelet, evitando
DeadlineExceeded. - Si ves ~4m34s constantes: el driver está esperando a que aparezcan dm‑name de portales inaccesibles. Revisa topologías, conectividad y que solo se prueben portales de la zona activa.
Para validar zona‑B, lanza un Pod/PVC análogo en
site-by repite el grep anterior en los logs.
7) Solución de problemas
-
missing API credentialsal provisionar- Asegúrate de usar las claves CSI en
parameters:delStorageClass(ver §3).
- Asegúrate de usar las claves CSI en
-
Errores Helm de invalid ownership metadata
- Borra los
ClusterRole/ClusterRoleBindingresiduales del release antiguo (ver §2.2).
- Borra los
-
DeadlineExceededdurante montaje-
Comprueba:
find_multipaths "greedy"y resto de multipath según §1.2.- Etiquetas de zona en el nodo donde programa el Pod.
- Que el
StorageClasscorrecto tengaallowedTopologiesde esa zona.
-
-
Ver puertos/portales iSCSI efectivos
sudo iscsiadm -m node | sortpara ver a qué destinos quedó configurado el nodo. Con topología bien aplicada, deben ser los del sitio correspondiente.
8) Limpieza y reintentos
Para repetir la prueba desde cero (manteniendo el driver):
kubectl delete -f pod-a.yaml
kubectl delete -f pvc-pod-a.yaml
Si quisieras limpiar todo el despliegue del driver:
helm uninstall exos-x-csi -n seagate
# Si quedaron RBAC de releases previos:
kubectl delete clusterrole external-provisioner-runner-systems || true
kubectl delete clusterrolebinding csi-provisioner-role-systems || true
9) Resumen de lo que quedó en repo (carpeta seagate/)
namespace.yaml— Namespaceseagate.secret-me5-site-a.yaml/secret-me5-site-b.yaml— Credenciales por sitio.values.yaml— Valores de Helm usados para el driver v1.10.0.sc-me5-site-a.yaml/sc-me5-site-b.yaml— StorageClass conallowedTopologies,pool,volPrefix, claves CSI de Secret yWaitForFirstConsumer.pvc-pod-a.yaml+pod-a.yaml— Manifests de prueba ensite-a.- (Opcional)
csi-exos-x-csidriver.yaml— no es necesario modificarlo para topología en esta versión.
10) Anexos — Comandos útiles ejecutados
- Reinicio multipath/kubelet y propagación de montajes.
- Limpieza iSCSI/multipath (cuando se rehizo la prueba):
sudo iscsiadm -m node -u || true
sudo iscsiadm -m node -o delete || true
sudo multipath -F || true
sudo multipath -r
- Despliegue Helm + manejo de residuos RBAC (ver §2.2).
- Aplicación secuencial de
namespace,secrets,StorageClass,PVCyPod.
Resultado
- Reproducible: con esta receta, el volumen se crea en la cabina de su zona y el Pod arranca.
- Tiempos de montaje: bajan de ~4m34s a ≈1m30s (observado), dentro del presupuesto de kubelet.
- Aislamiento por zona: cada StorageClass limita portales iSCSI a su sitio gracias a
allowedTopologies+ etiquetas de nodo.