diff --git a/harbor/readme.md b/harbor/readme.md new file mode 100644 index 0000000..10899e5 --- /dev/null +++ b/harbor/readme.md @@ -0,0 +1,27 @@ +## Instalacion de Harbor + + + +### Fase 1: Despliegue con Ingress + +```bash +helm repo add harbor https://helm.goharbor.io +helm repo update +helm install harbor harbor/harbor \ + --namespace harbor --create-namespace \ + -f values.yaml +``` + +> Una vez listo, podrás acceder a: +> +> **[https://harbor.c2et.net](https://harbor.c2et.net)** +> +> Usuario: `admin` +> Contraseña: la definida en `harborAdminPassword` (p.ej. `Harbor12345`) + +```bash +docker login harbor.c2et.net +``` + + + diff --git a/harbor/values.yaml b/harbor/values.yaml index cd35e2e..2f09884 100644 --- a/harbor/values.yaml +++ b/harbor/values.yaml @@ -4,7 +4,7 @@ expose: enabled: true certSource: auto ingress: - ingressClassName: nginx + className: nginx annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" hosts: diff --git a/readme.md b/readme.md index 568b5ca..a031053 100644 --- a/readme.md +++ b/readme.md @@ -131,6 +131,7 @@ Este repositorio contiene los **manifiestos, scripts y documentación** para des | `comprobaciones.md` | Checklist tras cada paso crítico | [Ver](./comprobaciones.md) | | `script_limpieza.md` | Script para limpiar un nodo | [Ver](script_limpieza.md) | | `coredns-demo\readme.md` | Ejemplo de Multus con CoreDNS | [Ver](./coredns-demo/readme.md) | +| `harbor\readme.md` | Manual de instalacion de Harbor | [Ver](./harbor/readme.md) | | `storage\readme.md` | Ejemplo de StorageClass | [Ver](./storage/readme.md) | | `dashboard\readme.md` | Ejemplo con ingress dashboard | [Ver](./dashboard/readme.md) | | `wireguard\readme.md` | Manual de WireGuard | [Ver](./wireguard/readme.md) | diff --git a/seagate/readme.md b/seagate/readme.md index d3d675e..94619d2 100644 --- a/seagate/readme.md +++ b/seagate/readme.md @@ -1,6 +1,6 @@ -# Seagate Exos X CSI (ME5 dual‑site) — Guía de instalación y operación +# 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*. +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** > @@ -11,11 +11,100 @@ Este README documenta cómo he dejado **reproducible** la instalación del *Seag --- -## 1) Prerrequisitos en los nodos +## 1) Configuración iSCSI en los nodos -1. **Multipath** y **iSCSI** instalados/activos. +En **todos los nodos** del clúster: -2. **/etc/multipath.conf** — opciones relevantes usadas: +1. Instalar dependencias: + +```bash +sudo zypper install open-iscsi yast2-iscsi-client multipath-tools +``` + +2. Habilitar y arrancar el servicio iSCSI: + +```bash +sudo systemctl enable --now iscsid.service +systemctl status iscsid.service +``` + +3. Descubrir los targets en las cabinas: + +```bash +sudo iscsiadm -m discovery -t sendtargets -p 192.168.3.11 +sudo iscsiadm -m discovery -t sendtargets -p 192.168.3.21 +``` + +En este punto hay que **añadir en las cabinas el grupo de host con cada host**. + +4. Iniciar sesión contra todos los portales de ambas cabinas: + +```bash +# Cabina site-a +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.11:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.12:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.13:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.14:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.15:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.16:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.17:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e92b6 -p 192.168.3.18:3260 --login & + +# Cabina site-b +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.21:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.22:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.23:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.24:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.25:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.26:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.27:3260 --login & +sudo iscsiadm -m node -T iqn.1988-11.com.dell:01.array.bc305b5e8e43 -p 192.168.3.28:3260 --login +``` + +5. Verificar la sesión activa: + +```bash +sudo iscsiadm -m session +``` + +6. Editar configuración de iSCSI en `/etc/iscsi/iscsid.conf`: + +```conf +iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket +iscsid.safe_logout = Yes +node.startup = automatic +node.leading_login = No +node.session.timeo.replacement_timeout = 120 +node.conn[0].timeo.login_timeout = 15 +node.conn[0].timeo.logout_timeout = 15 +node.conn[0].timeo.noop_out_interval = 5 +node.conn[0].timeo.noop_out_timeout = 5 +node.session.err_timeo.abort_timeout = 15 +node.session.err_timeo.lu_reset_timeout = 30 +node.session.err_timeo.tgt_reset_timeout = 30 +node.session.err_timeo.host_reset_timeout = 60 +node.session.initial_login_retry_max = 8 +node.session.cmds_max = 128 +node.session.queue_depth = 32 +node.session.xmit_thread_priority = -20 +node.session.iscsi.InitialR2T = No +node.session.iscsi.ImmediateData = Yes +node.session.iscsi.FirstBurstLength = 262144 +node.session.iscsi.MaxBurstLength = 16776192 +node.conn[0].iscsi.MaxRecvDataSegmentLength = 262144 +node.conn[0].iscsi.MaxXmitDataSegmentLength = 0 +discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768 +node.session.nr_sessions = 1 +node.session.reopen_max = 0 +node.session.iscsi.FastAbort = Yes +node.session.scan = auto +``` + +--- + +## 2) Prerrequisitos en los nodos + +### 2.1. Configuración `/etc/multipath.conf` ```conf defaults { @@ -37,23 +126,24 @@ devices { > **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*. +> * `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*. -Reiniciar servicios y refrescar paths tras cambiar multipath: + +### 2.2. Multipath e iSCSI activos + +Asegurarse de tener `multipathd` en ejecución: ```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 *node‑server* aparezcan en el host: +### 2.3. Propagación de montajes (rshared) ```bash sudo mount --make-rshared / -# systemd drop‑in para kubelet +# 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] @@ -67,16 +157,14 @@ sudo systemctl daemon-reload sudo systemctl restart kubelet ``` -Comprobar: +Verificar: ```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: +### 2.4. Etiquetas de topología en nodos ```bash kubectl label nodes topology.kubernetes.io/zone=site-a --overwrite @@ -85,9 +173,9 @@ kubectl label nodes topology.kubernetes.io/zone=site-b --overw --- -## 2) Despliegue del Driver con Helm +## 3) Despliegue del Driver con Helm -### 2.1. Namespace y valores +### 3.1. Namespace y valores ```bash kubectl apply -f namespace.yaml # namespace: seagate @@ -96,19 +184,11 @@ 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` +* Sidecars: provisioner, attacher, resizer, snapshotter, registrar * `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 +### 3.2. Instalación ```bash helm upgrade --install exos-x-csi \ @@ -117,56 +197,30 @@ helm upgrade --install 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= -``` - -Reintentar `helm upgrade --install`. +*(Si hay residuos RBAC, eliminarlos antes de reintentar)* --- -## 3) Secret por cabina (A y B) +## 4) Secret por cabina (A y B) -Un `Secret` por sitio en el *namespace* `seagate` con `apiAddress`, `username`, `password` en Base64. +Crear un `Secret` por sitio 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) +## 5) StorageClass por zona -Se definen **dos** `StorageClass` idénticos salvo: +Definir **dos** `StorageClass` con: * Secret (A o B) -* `pool` (p. ej., `dg01` para site‑a, `dg02` para site‑b) -* `volPrefix` (ej. `sza` / `szb` para identificar site en el nombre de LUN) -* `allowedTopologies` con la zona correspondiente +* `pool` y `volPrefix` +* `allowedTopologies` por zona * `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 @@ -174,12 +228,9 @@ kubectl apply -f sc-me5-site-b.yaml --- -## 5) Prueba de extremo a extremo +## 6) Prueba de extremo a extremo -### 5.1. PVC + Pod en site‑a - -* PVC: `pvc-a` con `storageClassName: sc-me5-site-a` -* Pod: `pod-a` con `nodeSelector: topology.kubernetes.io/zone=site-a` +PVC + Pod en site-a: ```bash kubectl apply -f pvc-pod-a.yaml @@ -187,115 +238,57 @@ 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:** - -```bash -sudo iscsiadm -m node | sort -``` - -* **Multipath:** - -```bash -sudo multipath -ll -``` - -* **Eventos del PVC:** - -```bash -kubectl describe pvc -``` - -* **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' -``` +Verificar `iscsiadm`, `multipath`, eventos del PVC y logs del controller. --- -## 6) Medir el tiempo de *NodePublish* (montaje) - -Para medir cuánto tarda el montaje (fase *NodePublishVolume*) desde el *node‑server*: +## 7) Medición de tiempos de *NodePublish* ```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/' +| grep "NodePublishVolume" | grep "ROUTINE END" ``` -* 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-b` y repite el grep anterior en los logs. +## 8) Solución de problemas + +* `missing API credentials` → revisar claves CSI en el StorageClass. +* `DeadlineExceeded` → revisar multipath, etiquetas de zona y topología. +* Helm RBAC conflict → borrar roles residuales. --- -## 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): +## 9) Limpieza ```bash kubectl delete -f pod-a.yaml kubectl delete -f pvc-pod-a.yaml ``` -Si quisieras limpiar *todo el despliegue* del driver: +Para desinstalar completamente: ```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/`) +## 10) Resumen en repo (`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. +* `namespace.yaml` +* `secret-me5-site-a.yaml`, `secret-me5-site-b.yaml` +* `values.yaml` +* `sc-me5-site-a.yaml`, `sc-me5-site-b.yaml` +* `pvc-pod-a.yaml`, `pod-a.yaml` --- -## 10) Anexos — Comandos útiles ejecutados +## 11) Anexos — Comandos útiles -* Reinicio multipath/kubelet y propagación de montajes. -* Limpieza iSCSI/multipath (cuando se rehizo la prueba): +* Reinicio multipath/kubelet +* Limpieza iSCSI/multipath: ```bash sudo iscsiadm -m node -u || true @@ -303,14 +296,3 @@ 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.