diff --git a/kubevirt-manager/deployments/deployment.yaml b/kubevirt-manager/deployments/deployment.yaml deleted file mode 100644 index e3bd805..0000000 --- a/kubevirt-manager/deployments/deployment.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kubevirt-manager - namespace: kubevirt-manager -spec: - replicas: 1 - selector: - matchLabels: - app: kubevirt-manager - template: - metadata: - labels: - app: kubevirt-manager - spec: - serviceAccountName: kubevirt-manager - containers: - - name: kubevirt-manager - image: kubevirtmanager/kubevirt-manager:1.4.0 - ports: - - containerPort: 8001 - env: - - name: BACKEND_URL - value: "http://localhost:8080" diff --git a/kubevirt-manager/ingress/ingress.yaml b/kubevirt-manager/ingress/ingress.yaml deleted file mode 100644 index 01204f9..0000000 --- a/kubevirt-manager/ingress/ingress.yaml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: kubevirt-manager - namespace: kubevirt-manager - annotations: - cert-manager.io/cluster-issuer: "letsencrypt-prod" - nginx.ingress.kubernetes.io/force-ssl-redirect: "true" - nginx.ingress.kubernetes.io/backend-protocol: "HTTP" -spec: - ingressClassName: nginx - tls: - - hosts: - - kubevirt.manabo.org - secretName: kubevirt-manager-tls - rules: - - host: kubevirt.manabo.org - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: kubevirt-manager - port: - number: 80 diff --git a/kubevirt-manager/kustomization.yaml b/kubevirt-manager/kustomization.yaml deleted file mode 100644 index 3923093..0000000 --- a/kubevirt-manager/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -resources: - - namespace.yaml - - deployments/deployment.yaml - - services/service.yaml -# - ingress/ingress.yaml - - rbac/serviceaccount.yaml - - rbac/clusterrolebinding.yaml diff --git a/kubevirt-manager/rbac/clusterrolebinding.yaml b/kubevirt-manager/rbac/clusterrolebinding.yaml deleted file mode 100644 index 00934e5..0000000 --- a/kubevirt-manager/rbac/clusterrolebinding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kubevirt-manager -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: -- kind: ServiceAccount - name: kubevirt-manager - namespace: kubevirt-manager diff --git a/kubevirt-manager/rbac/serviceaccount.yaml b/kubevirt-manager/rbac/serviceaccount.yaml deleted file mode 100644 index 71bde4a..0000000 --- a/kubevirt-manager/rbac/serviceaccount.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kubevirt-manager - namespace: kubevirt-manager - diff --git a/kubevirt/deployments/dashboard.yaml b/kubevirt/deployments/dashboard.yaml new file mode 100644 index 0000000..fd51dcf --- /dev/null +++ b/kubevirt/deployments/dashboard.yaml @@ -0,0 +1,36 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kubevirt-manager + namespace: kubevirt +spec: + replicas: 1 + selector: + matchLabels: + app: kubevirt-manager + template: + metadata: + labels: + app: kubevirt-manager + spec: + serviceAccountName: kubevirt-manager + containers: + - name: kubevirt-manager + image: kubevirtmanager/kubevirt-manager:1.4.0 + ports: + - containerPort: 8001 + env: + - name: BACKEND_URL + value: "http://localhost:8080" + readinessProbe: + httpGet: + path: / + port: 8001 + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: / + port: 8001 + initialDelaySeconds: 15 + periodSeconds: 20 diff --git a/kubevirt/deployments/isoserver.yaml b/kubevirt/deployments/isoserver.yaml new file mode 100644 index 0000000..c4f5f89 --- /dev/null +++ b/kubevirt/deployments/isoserver.yaml @@ -0,0 +1,51 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: iso-server + namespace: kubevirt +spec: + replicas: 1 + selector: + matchLabels: + app: iso-server + template: + metadata: + labels: + app: iso-server + spec: + containers: + - name: httpd + image: httpd:2.4 + ports: + - containerPort: 80 + volumeMounts: + - name: iso-storage + mountPath: /usr/local/apache2/htdocs + readinessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 15 + periodSeconds: 20 + + - name: samba + image: dperson/samba + args: ["-p", "-s", "isos;/share;yes;no"] + ports: + - containerPort: 445 + securityContext: + runAsUser: 0 + volumeMounts: + - name: iso-storage + mountPath: /share + + volumes: + - name: iso-storage + persistentVolumeClaim: + claimName: iso-pvc diff --git a/kubevirt/ingress/ingress-dashboard.yaml b/kubevirt/ingress/ingress-dashboard.yaml new file mode 100644 index 0000000..07e26b6 --- /dev/null +++ b/kubevirt/ingress/ingress-dashboard.yaml @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: kubevirt-manager + namespace: kubevirt + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" +# nginx.ingress.kubernetes.io/whitelist-source-range: "192.168.0.0/24,192.168.254.0/24" +spec: + ingressClassName: nginx + tls: + - hosts: + - kubevirt.c2et.net + secretName: kubevirt-c2et-net-tls + rules: + - host: kubevirt.c2et.net + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: kubevirt-manager + port: + number: 80 diff --git a/kubevirt/ingress/ingress-isoserver.yaml b/kubevirt/ingress/ingress-isoserver.yaml new file mode 100644 index 0000000..dc55183 --- /dev/null +++ b/kubevirt/ingress/ingress-isoserver.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: iso-server + namespace: kubevirt + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" +spec: + ingressClassName: nginx + tls: + - hosts: + - isoserver.c2et.net + secretName: isoserver-c2et-net-tls + rules: + - host: isoserver.c2et.net + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: iso-server-http + port: + number: 80 diff --git a/kubevirt/kustomization.yaml b/kubevirt/kustomization.yaml new file mode 100644 index 0000000..88df1fc --- /dev/null +++ b/kubevirt/kustomization.yaml @@ -0,0 +1,14 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: kubevirt +resources: + - rbac/serviceaccount.yaml + - rbac/clusterrolebinding.yaml + - deployments/dashboard.yaml + - services/service-dashboard.yaml + - ingress/ingress-dashboard.yaml + - pvc/iso-pvc.yaml + - deployments/isoserver.yaml + - services/service-http.yaml + - services/service-samba.yaml + - ingress/ingress-isoserver.yaml diff --git a/kubevirt-manager/namespace.yaml b/kubevirt/namespace.yaml similarity index 100% rename from kubevirt-manager/namespace.yaml rename to kubevirt/namespace.yaml diff --git a/kubevirt/pvc/iso-pvc.yaml b/kubevirt/pvc/iso-pvc.yaml new file mode 100644 index 0000000..19f9776 --- /dev/null +++ b/kubevirt/pvc/iso-pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: iso-pvc + namespace: kubevirt +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 800Gi + storageClassName: ceph-rbd diff --git a/kubevirt/rbac/clusterrolebinding.yaml b/kubevirt/rbac/clusterrolebinding.yaml new file mode 100644 index 0000000..d9db688 --- /dev/null +++ b/kubevirt/rbac/clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: kubevirt-manager +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: kubevirt-manager + namespace: kubevirt diff --git a/kubevirt/rbac/serviceaccount.yaml b/kubevirt/rbac/serviceaccount.yaml new file mode 100644 index 0000000..f0d6156 --- /dev/null +++ b/kubevirt/rbac/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kubevirt-manager + namespace: kubevirt diff --git a/kubevirt/readme.md b/kubevirt/readme.md new file mode 100644 index 0000000..647d5bb --- /dev/null +++ b/kubevirt/readme.md @@ -0,0 +1,300 @@ +# KubeVirt en Kubernetes (SUSE) con Dashboard y ISO Server + +> Entorno: 4 nodos SUSE con Flannel + Multus, containerd con `SystemdCgroup=true`, kubelet con `cgroupDriver: systemd`. +> +> Dominios: `kubevirt.c2et.net` (dashboard) y `isoserver.c2et.net` (HTTP para imágenes). +> +> Storage: `ceph-rbd` (RWO) para el PVC del ISO server. + +--- + +## 0) Prerrequisitos y comprobaciones + +En **cada nodo**: + +```bash +# Virtualización (debe devolver > 0) +egrep -o 'vmx|svm' /proc/cpuinfo | wc -l + +# Cargar módulos KVM (Intel o AMD) +sudo modprobe kvm +sudo modprobe kvm_intel # o kvm_amd + +# Persistir módulos al arranque +printf "kvm\nkvm_intel\n" | sudo tee /etc/modules-load.d/kvm.conf # (o kvm_amd) + +# Verificar /dev/kvm y AppArmor +ls -l /dev/kvm +sudo aa-status | head -n 5 + +# containerd: SystemdCgroup=true +sudo grep -n "SystemdCgroup" /etc/containerd/config.toml + +# kubelet: cgroupDriver: systemd +grep -i cgroup /var/lib/kubelet/config.yaml +``` + +> **PSA (opcional)** si usas Pod Security Admission: + +```bash +kubectl create ns kubevirt --dry-run=client -o yaml | kubectl apply -f - +kubectl label ns kubevirt \ + pod-security.kubernetes.io/enforce=privileged \ + pod-security.kubernetes.io/audit=privileged \ + pod-security.kubernetes.io/warn=privileged --overwrite + +kubectl create ns cdi --dry-run=client -o yaml | kubectl apply -f - +kubectl label ns cdi \ + pod-security.kubernetes.io/enforce=baseline \ + pod-security.kubernetes.io/audit=baseline \ + pod-security.kubernetes.io/warn=baseline --overwrite +``` + +--- + +## 1) Instalar KubeVirt y CDI (versionado recomendado) + +> **Recomendación:** fija versiones (no uses `latest`) para reproducibilidad. + +```bash +# Elige versiones estables (ejemplos; ajusta según tu política) +export KUBEVIRT_VERSION=v1.6.0 +export CDI_VERSION=v1.62.0 + +# KubeVirt (operator + CR) +kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-operator.yaml +kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-cr.yaml + +# CDI (operator + CR) +kubectl apply -f https://github.com/kubevirt/containerized-data-importer/releases/download/${CDI_VERSION}/cdi-operator.yaml +kubectl apply -f https://github.com/kubevirt/containerized-data-importer/releases/download/${CDI_VERSION}/cdi-cr.yaml +``` + +**Checks mínimos:** + +```bash +kubectl -n kubevirt get kv kubevirt -o jsonpath='{.status.phase}'; echo # Debería: Deployed +kubectl -n kubevirt get pods +kubectl -n cdi get pods +``` + +--- + +## 2) Instalar `virtctl` (CLI) + +```bash +curl -L -o virtctl \ + https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/virtctl-${KUBEVIRT_VERSION}-linux-amd64 +chmod +x virtctl && sudo mv virtctl /usr/local/bin/ +virtctl version +``` + +--- + +## 3) Dashboard (kubevirt-manager) en `kubevirt.c2et.net` + +Estructura (kustomize) sugerida dentro de tu repo `kubernetes/kubevirt/`: + +``` +. +├─ deployments/ +│ └─ dashboard.yaml # Deployment (image kubevirtmanager/kubevirt-manager:1.4.0) +├─ services/ +│ └─ service-dashboard.yaml # Service ClusterIP (80 → 8001) +├─ ingress/ +│ └─ ingress-dashboard.yaml # Ingress (class nginx, LE prod) +├─ rbac/ +│ ├─ serviceaccount.yaml # SA kubevirt-manager +│ └─ clusterrolebinding.yaml # CRB a cluster-admin +└─ kustomization.yaml +``` + +**Puntos clave:** + +* Namespace: `kubevirt`. +* Service **ClusterIP** exponiendo `port: 80` → `targetPort: 8001`. +* Ingress con `ingressClassName: nginx`, `cert-manager.io/cluster-issuer: letsencrypt-prod`, host `kubevirt.c2et.net`. +* RBAC: `ClusterRoleBinding` a `cluster-admin` para la SA del dashboard. + +Aplicación y verificación: + +```bash +kubectl apply -k kubernetes/kubevirt +kubectl -n kubevirt get deploy,svc,ingress | grep kubevirt-manager +``` + +Acceso: `https://kubevirt.c2et.net/` + +--- + +## 4) ISO Server en `isoserver.c2et.net` (HTTP) + Samba (LB 192.168.0.105) + +Estructura (kustomize) en el mismo módulo `kubernetes/kubevirt/`: + +``` +. +├─ pvc/ +│ └─ iso-pvc.yaml # PVC ceph-rbd (RWO) +├─ deployments/ +│ └─ isoserver.yaml # Pod con httpd:2.4 + dperson/samba +├─ services/ +│ ├─ service-http.yaml # Service ClusterIP (para Ingress) +│ └─ service-samba.yaml # Service LoadBalancer (LB IP 192.168.0.105) +├─ ingress/ +│ └─ ingress-isoserver.yaml # Ingress (host isoserver.c2et.net) +└─ kustomization.yaml +``` + +**PVC (`ceph-rbd`)** — ¡Importante! + +```yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: iso-pvc + namespace: kubevirt +spec: + accessModes: [ReadWriteOnce] # RBD es RWO + resources: + requests: + storage: 800Gi + storageClassName: ceph-rbd +``` + +**Deployment** + +* `httpd:2.4` monta `/usr/local/apache2/htdocs` +* `dperson/samba` exporta `/share` +* Ambos montan **el mismo PVC** (`iso-pvc`) → lo que subes por Samba se sirve por HTTP. + +**Services** + +* `iso-server-http` → **ClusterIP** `port: 80` (backend de Ingress) +* `iso-server-samba` → **LoadBalancer** `loadBalancerIP: 192.168.0.105` `port: 445` + + * Asegura que 192.168.0.105 está dentro de un **pool de MetalLB**. + +**Ingress (HTTP/HTTPS)** + +* Host: `isoserver.c2et.net` +* Cert: `letsencrypt-prod` +* **Sin** `force-ssl-redirect` para poder usar HTTP con CDI si tu CA no es de confianza. + +Aplicación y verificación: + +```bash +kubectl apply -k kubernetes/kubevirt +kubectl -n kubevirt get pods | grep iso-server +kubectl -n kubevirt get svc iso-server-http iso-server-samba -o wide +kubectl -n kubevirt get ingress iso-server +``` + +Acceso: + +* **Samba**: `\\192.168.0.105\isos` (guest por defecto; puedes parametrizar usuarios) +* **HTTP**: `http://isoserver.c2et.net/` + +> **Sugerencias de seguridad (opcionales):** +> +> * Añade credenciales a Samba: `args: ["-p","-u","iso;TuPass","-s","isos;/share;yes;no"]` +> * Limita el Ingress por rangos: `nginx.ingress.kubernetes.io/whitelist-source-range: "192.168.0.0/24"` + +--- + +## 5) Uso con CDI: importar imágenes/ISOs + +### 5.1 Subir ficheros al ISO server + +```bash +# Linux (guest) +sudo mkdir -p /mnt/isos +sudo mount -t cifs //192.168.0.105/isos /mnt/isos -o guest,vers=3.0 +cp ./ubuntu-24.04.qcow2 /mnt/isos/ + +# Ver por HTTP +curl -I http://isoserver.c2et.net/ubuntu-24.04.qcow2 +``` + +### 5.2 Crear un DataVolume desde URL (HTTP) + +```yaml +apiVersion: cdi.kubevirt.io/v1beta1 +kind: DataVolume +metadata: + name: dv-ubuntu-24 + namespace: default +spec: + source: + http: + url: "http://isoserver.c2et.net/ubuntu-24.04.qcow2" + pvc: + storageClassName: ceph-rbd + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 20Gi +``` + +```bash +kubectl apply -f dv-ubuntu-24.yaml +kubectl -n default get dv,pvc +kubectl -n cdi get pods -w # verás el importer hasta Succeeded +``` + +> **HTTPS** también funciona. Si usas CA propia, puedes inyectar la CA en el DV (campo `certConfigMap`) o usar `virtctl image-upload --insecure` en pruebas. + +### 5.3 Usar el PVC en una VM + +```yaml +# Fragmento de spec de VirtualMachine +volumes: + - name: rootdisk + dataVolume: + name: dv-ubuntu-24 + +disks: + - name: rootdisk + disk: { bus: virtio } +``` + +> Para **ISOs**, crea un DV de la ISO y móntalo como `cdrom: { readonly: true }`. + +--- + +## 6) Comprobaciones y troubleshooting + +```bash +# KubeVirt / CDI +kubectl -n kubevirt get kv kubevirt -o jsonpath='{.status.phase}'; echo +kubectl -n kubevirt get deploy,ds,pods | egrep 'virt-|kubevirt-' +kubectl -n cdi get pods + +# Dashboard +kubectl -n kubevirt get endpoints kubevirt-manager + +# ISO server +kubectl -n kubevirt get endpoints iso-server-http +smbclient -L 192.168.0.105 -N +curl -I http://isoserver.c2et.net/ +``` + +**MetalLB asigna otra IP** → asegúrate de que `192.168.0.105` está en el pool. Puedes recrear el Service o `patch`: + +```bash +kubectl -n kubevirt patch svc iso-server-samba -p '{"spec":{"loadBalancerIP":"192.168.0.105"}}' +``` + +**CDI falla con HTTPS** → usa HTTP o confía la CA (o `certConfigMap` en el DV). + +--- + +## 7) Referencias rápidas + +* Namespace: `kubevirt` +* Dashboard host: `kubevirt.c2et.net` (Ingress `nginx`, TLS LE) +* ISO server host: `isoserver.c2et.net` (HTTP para CDI; TLS opcional) +* Samba LB: `192.168.0.105` (MetalLB) +* StorageClass ISO PVC: `ceph-rbd` (RWO) + +--- + diff --git a/kubevirt-manager/services/service.yaml b/kubevirt/services/service-dashboard.yaml similarity index 57% rename from kubevirt-manager/services/service.yaml rename to kubevirt/services/service-dashboard.yaml index ded2a8d..8950307 100644 --- a/kubevirt-manager/services/service.yaml +++ b/kubevirt/services/service-dashboard.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Service metadata: name: kubevirt-manager - namespace: kubevirt-manager + namespace: kubevirt spec: selector: app: kubevirt-manager @@ -10,5 +10,4 @@ spec: - port: 80 targetPort: 8001 protocol: TCP - nodePort: 30081 # <--- puedes elegir el puerto, debe estar entre 30000-32767 - type: NodePort + type: ClusterIP diff --git a/kubevirt/services/service-http.yaml b/kubevirt/services/service-http.yaml new file mode 100644 index 0000000..750b858 --- /dev/null +++ b/kubevirt/services/service-http.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: iso-server-http + namespace: kubevirt +spec: + type: ClusterIP + selector: + app: iso-server + ports: + - name: http + port: 80 + targetPort: 80 + protocol: TCP diff --git a/kubevirt/services/service-samba.yaml b/kubevirt/services/service-samba.yaml new file mode 100644 index 0000000..591e04f --- /dev/null +++ b/kubevirt/services/service-samba.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: iso-server-samba + namespace: kubevirt +spec: + type: LoadBalancer + loadBalancerIP: 192.168.0.105 + selector: + app: iso-server + ports: + - name: samba + port: 445 + targetPort: 445 + protocol: TCP