Files
kubernetes/seagate/readme.md
2025-08-26 22:00:11 +02:00

317 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Seagate Exos X CSI (ME5 dualsite) — 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** (sitea y siteb) usando iSCSI + multipath y *topología por zona*.
> **Objetivo**
>
> * Un único despliegue del driver (Helm).
> * **Dos StorageClass** (uno por sitio) con `allowedTopologies` y 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
1. **Multipath** y **iSCSI** instalados/activos.
2. **/etc/multipath.conf** — opciones relevantes usadas:
```conf
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:
```bash
sudo systemctl restart multipathd
sudo multipath -r
```
3. **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 *nodeserver* aparezcan en el host:
```bash
sudo mount --make-rshared /
# systemd dropin 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:
```bash
sudo findmnt -o TARGET,PROPAGATION /
sudo findmnt -o TARGET,PROPAGATION /var/lib/kubelet
```
4. **Etiquetas de topología en nodos**
Etiquetar cada nodo con su zona:
```bash
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
```bash
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.1`
* `csi-resizer v1.11.1`
* `csi-snapshotter v8.0.1`
* `csi-node-driver-registrar v2.9.0`
* `controller.extraArgs: ["-v=2"]`
* `node.extraArgs: ["-v=2"]`
> **Nota:** no es necesario tocar `CSIDriver` para topología; la topología se maneja desde los `StorageClass` + etiquetas de nodo.
### 2.2. Instalación
```bash
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:
```bash
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.
```bash
kubectl apply -f secret-me5-site-a.yaml
kubectl apply -f secret-me5-site-b.yaml
```
> **Importante:** Los `StorageClass` deben usar las **claves estándar CSI** para que el provisioner pase el Secret al driver:
>
> * `csi.storage.k8s.io/provisioner-secret-name|namespace`
> * `csi.storage.k8s.io/controller-publish-secret-name|namespace`
> * `csi.storage.k8s.io/controller-expand-secret-name|namespace`
> * `csi.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., `dg01` para sitea, `dg02` para siteb)
* `volPrefix` (ej. `sza` / `szb` para identificar site en el nombre de LUN)
* `allowedTopologies` con la zona correspondiente
* `volumeBindingMode: 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`:
```bash
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 sitea
* PVC: `pvc-a` con `storageClassName: sc-me5-site-a`
* Pod: `pod-a` con `nodeSelector: topology.kubernetes.io/zone=site-a`
```bash
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 sitea.
### 5.2. Verificaciones útiles
* **iSCSI nodes vistos:**
```bash
sudo iscsiadm -m node | sort
```
* **Multipath:**
```bash
sudo multipath -ll
```
* **Eventos del PVC:**
```bash
kubectl describe pvc <nombre>
```
* **Logs del controller:** (búsqueda de credenciales / errores de provisión)
```bash
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 *nodeserver*:
```bash
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 *dmname* de portales inaccesibles. Revisa topologías, conectividad y que solo se prueben portales de la zona activa.
> Para validar zonaB, lanza un Pod/PVC análogo en `site-b` y repite el grep anterior en los logs.
---
## 7) Solución de problemas
* **`missing API credentials` al provisionar**
* Asegúrate de usar las **claves CSI** en `parameters:` del `StorageClass` (ver §3).
* **Errores Helm de *invalid ownership metadata***
* Borra los `ClusterRole/ClusterRoleBinding` residuales del release antiguo (ver §2.2).
* **`DeadlineExceeded` durante 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 `StorageClass` correcto tenga `allowedTopologies` de esa zona.
* **Ver puertos/portales iSCSI efectivos**
* `sudo iscsiadm -m node | sort` para 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):
```bash
kubectl delete -f pod-a.yaml
kubectl delete -f pvc-pod-a.yaml
```
Si quisieras limpiar *todo el despliegue* del driver:
```bash
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` — Namespace `seagate`.
* `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 con `allowedTopologies`, `pool`, `volPrefix`, claves CSI de Secret y `WaitForFirstConsumer`.
* `pvc-pod-a.yaml` + `pod-a.yaml` — Manifests de prueba en `site-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):
```bash
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`, `PVC` y `Pod`.
---
### 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.