Guía de instalación K8s + KubeVirt en Ubuntu 24.04
0. Ejemplo de configuración de red (Netplan)
Aquí defines cómo se conectará tu servidor físicamente a la red: enlaces redundantes (bonding), VLANs para separar tráfico y bridges para que las máquinas virtuales y pods se conecten a varias redes internas. Es la base para un clúster flexible y segmentado.
Archivo: /etc/netplan/50-cloud-init.yaml
network:
version: 2
ethernets:
enp2s0f0np0: {}
enp2s0f1np1: {}
bonds:
bond0:
interfaces:
- enp2s0f0np0
- enp2s0f1np1
parameters:
mode: "802.3ad"
lacp-rate: "fast"
transmit-hash-policy: "layer3+4"
vlans:
bond0.20:
id: 20
link: bond0
dhcp4: no
bond0.30:
id: 30
link: bond0
addresses:
- "192.168.3.4/24"
bond0.40:
id: 40
link: bond0
addresses:
- "192.168.4.4/24"
bridges:
br0:
interfaces:
- bond0
addresses:
- "192.168.1.14/24"
nameservers:
addresses:
- 192.168.1.1
- 1.1.1.1
- 8.8.8.8
routes:
- to: "default"
via: "192.168.1.1"
parameters:
stp: false
forward-delay: 0
br-servicios:
interfaces:
- bond0.20
addresses:
- 192.168.200.4/22
parameters:
stp: false
forward-delay: 0
No olvides aplicar cambios con:
sudo netplan apply
1. Prerrequisitos del sistema
Hay que partir de un Ubuntu 24.04 actualizado y con permisos de administrador. En este paso instalamos utilidades básicas y configuramos el repositorio oficial de Kubernetes, necesario para instalar sus componentes más adelante.
a) Actualiza el sistema y paquetes básicos
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
b) Añade el repositorio oficial de Kubernetes
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
sudo chmod 644 /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
c) Ponerle el nombre correcto al nodo
sudo hostnamectl set-hostname srvfkvmX
2. Desactiva SWAP (requisito Kubernetes)
Kubernetes requiere que el intercambio de memoria (swap) esté desactivado para gestionar los recursos de forma predecible y evitar problemas de rendimiento y estabilidad.
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
3. Instala containerd (runtime recomendado)
containerd es el motor que gestiona los contenedores en el clúster. Kubernetes necesita un “runtime” para crear y controlar los pods, y containerd es la opción oficial y más estable.
sudo apt-get install -y containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd
4. Prepara el kernel y sysctl
En este paso se habilitan módulos y parámetros de red necesarios para que Kubernetes gestione correctamente el tráfico entre pods y nodos.
sudo modprobe overlay
sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sudo sysctl --system
5. Instala kubeadm, kubelet, kubectl
Aquí se instalan los tres componentes esenciales de Kubernetes:
- kubelet: agente que corre en cada nodo y gestiona los pods
- kubeadm: herramienta para iniciar y gestionar el clúster
- kubectl: cliente de línea de comandos para operar el clúster
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
6. Inicializa el clúster (mononodo/laboratorio)
Este paso crea el clúster de Kubernetes en el nodo principal (control-plane). Aquí defines la red interna para los pods.
Si usas Flannel, usa este parámetro:
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
a) Configura kubectl para tu usuario
Permite usar el comando kubectl
como usuario normal copiando la configuración de administración del clúster a tu carpeta personal.
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
7. Instala la red de pods (Flannel)
Kubernetes solo define la infraestructura; necesitas un complemento de red (CNI) para que los pods puedan comunicarse entre sí. Flannel es la opción más sencilla y compatible.
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
8. Instala Multus (opcional, para múltiples redes)
Multus permite que un pod tenga más de una interfaz de red, útil para aplicaciones avanzadas (firewalls, balanceadores, appliances virtuales). Instálalo solo si necesitas múltiples redes.
kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/master/deployments/multus-daemonset.yml
-
Verifica:
kubectl get pods -n kube-system | grep multus
9. (Opcional) Quita el taint del nodo master para poder programar pods en él
Por defecto, Kubernetes no programa pods de usuario en el nodo principal (control-plane). Si tienes solo un nodo (laboratorio), elimina este bloqueo para poder desplegar aplicaciones ahí.
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
kubectl taint nodes --all node-role.kubernetes.io/master-
10. Test rápido de Multus
Aquí puedes comprobar que Multus funciona: se crea una red secundaria y un pod de prueba que recibe dos interfaces (una para la red de pods y otra para la red adicional configurada).
La carpeta multus/
del repositorio contiene el NAD y el pod de prueba:
multus/nad-br-servicios.yaml
(NetworkAttachmentDefinition)multus/test-multus-pod.yaml
(pod alpine)
Despliega la NAD:
kubectl apply -f multus/nad-br-servicios.yaml
Despliega el pod de test:
kubectl apply -f multus/test-multus-pod.yaml
Comprueba las interfaces:
kubectl exec -it multus-test -- sh
ip a
El pod debería tener una interfaz extra de la red br-servicios
además de la de Flannel.
Para limpiar:
kubectl delete pod multus-test
11. Instalación y configuración de MetalLB (LoadBalancer local)
MetalLB permite a tu clúster on-premise asignar IPs flotantes de tu red LAN a servicios tipo LoadBalancer
, igual que hacen los clústeres en la nube. Es necesario si quieres exponer servicios (ingress, dashboards, etc.) con una IP accesible desde tu red.
a) Instala MetalLB
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml
Esto crea el namespace metallb-system
y despliega los pods necesarios.
b) Crea la configuración del pool de IPs
Aquí defines qué rango de IPs puede repartir MetalLB dentro de tu red local. Estos archivos suelen estar versionados en la carpeta metallb/
del repositorio.
metallb/
├── ipaddresspool.yaml
├── l2advertisement.yaml
└── kustomization.yaml
Para aplicar:
kubectl apply -k metallb/
c) Uso de MetalLB
A partir de aquí, cualquier Service tipo LoadBalancer obtiene una IP flotante LAN automáticamente.
Ejemplo mínimo de Service:
apiVersion: v1
kind: Service
metadata:
name: ejemplo
spec:
selector:
app: ejemplo
ports:
- port: 80
targetPort: 80
type: LoadBalancer
Verás la IP asignada en la columna EXTERNAL-IP
al ejecutar:
kubectl get svc
Puedes acceder desde tu red local a esa IP.
12. Instalación de Traefik y cert-manager (Ingress + TLS)
Traefik actúa como el "router" de aplicaciones dentro de tu clúster, permitiendo exponer servicios a Internet o la red local de forma sencilla. cert-manager se encarga de gestionar certificados TLS automáticamente para que tus aplicaciones estén siempre seguras.
a) Instala Traefik como Ingress Controller
- Aplica todos los recursos con Kustomize:
kubectl apply -k traefik/
- Comprueba que MetalLB asigna una IP al Service principal:
kubectl get pods -n traefik
kubectl get svc -n traefik
b) Instala cert-manager
- Crea el namespace:
kubectl apply -f cert-manager/namespace.yaml
- Aplica el manifiesto oficial de cert-manager:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
- Crea los
ClusterIssuer
para staging y producción:
kubectl apply -f cert-manager/clusterissuer-staging.yaml
kubectl apply -f cert-manager/clusterissuer-prod.yaml
- Comprueba los pods:
kubectl get pods -n cert-manager
13. Instala KubeVirt y CDI
KubeVirt permite crear y gestionar máquinas virtuales dentro de Kubernetes, integrando cargas virtualizadas junto a contenedores. CDI (Containerized Data Importer) facilita la gestión y carga de discos e ISOs para esas VMs.
Nota: Puedes usar manifiestos oficiales, o crear tu carpeta kubevirt/ si deseas versionar los YAML personalizados.
# Instala KubeVirt (recomendado hacerlo tras tener la red y almacenamiento)
export KUBEVIRT_VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases/latest | grep tag_name | cut -d '"' -f 4)
kubectl create namespace kubevirt
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
# Instala CDI (para gestión de discos/ISOs)
export CDI_VERSION=$(curl -s https://api.github.com/repos/kubevirt/containerized-data-importer/releases/latest | grep tag_name | cut -d '"' -f 4)
kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/${CDI_VERSION}/cdi-operator.yaml
kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/${CDI_VERSION}/cdi-cr.yaml
14. Instala virtctl (CLI de KubeVirt)
virtctl es una herramienta de línea de comandos para interactuar fácilmente con las máquinas virtuales de KubeVirt: arranque, apagado, consola, etc.
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/
15. Habilita KVM para tu usuario
Para poder crear y gestionar máquinas virtuales, tu usuario debe pertenecer al grupo kvm
(acceso al hardware de virtualización).
sudo usermod -aG kvm $(whoami)
# Reinicia sesión o ejecuta 'newgrp kvm' para aplicar
16. Despliega kubevirt-manager
kubevirt-manager es una interfaz web sencilla para gestionar tus máquinas virtuales desde el navegador. Esta sección aplica sus manifiestos en Kubernetes.
La carpeta kubevirt-manager/
contiene todos los manifiestos organizados por tipo:
kubectl apply -k kubevirt-manager/
Puedes comprobar el estado:
kubectl get pods -n kubevirt-manager
17. Despliega el stack de almacenamiento NFS
Esta sección despliega tanto el servidor NFS (almacenamiento en red) como el "provisioner" para que Kubernetes pueda crear volúmenes dinámicos de manera automática. Es la forma más sencilla de tener almacenamiento persistente en el clúster.
La carpeta storage/
tiene todos los manifiestos del servidor y provisioner NFS, organizados en subcarpetas:
kubectl apply -k storage/
Puedes comprobar el estado:
kubectl get pods -n nfs-provisioner
-
Instala el cliente NFS en el nodo:
sudo apt install nfs-common
12. Instalación de Traefik y cert-manager (Ingress + TLS)
Traefik actúa como router de aplicaciones dentro de tu clúster, exponiendo servicios HTTP/HTTPS en LAN o Internet. Cert-manager se encarga de gestionar automáticamente los certificados TLS (Let's Encrypt, CA propia, etc.), pero también puedes usar un certificado comprado (wildcard) y aplicarlo a múltiples dominios.
a) Instala Traefik como Ingress Controller
-
Prepara tu carpeta de manifiestos (
traefik/
) con recursos desglosados:- Namespace, ServiceAccount, RBAC
- Deployment o DaemonSet (según tu preferencia)
- Service tipo
LoadBalancer
(usará MetalLB) - IngressClass (si lo quieres explícito)
- ConfigMap con parámetros de Traefik
-
Aplica los manifiestos con Kustomize:
kubectl apply -k traefik/
- Comprueba el estado y la IP asignada:
kubectl get pods -n traefik
kubectl get svc -n traefik
- El Service principal (
traefik
otraefik-lb
) debería tener una IP del pool de MetalLB (EXTERNAL-IP
).
b) Instala cert-manager (opcional si solo usas certificados propios)
- Crea el namespace:
kubectl apply -f cert-manager/namespace.yaml
- Aplica el manifiesto oficial de cert-manager:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
- (Opcional) Crea los ClusterIssuer para Let's Encrypt (staging y producción):
kubectl apply -f cert-manager/clusterissuer-staging.yaml
kubectl apply -f cert-manager/clusterissuer-prod.yaml
- Comprueba los pods:
kubectl get pods -n cert-manager
- Espera a que estén todos en estado
Running
.
c) ¿Cómo usar un certificado SSL wildcard comprado?
Si has adquirido un certificado wildcard (ej: *.miempresa.com
) y tienes el .crt
(certificado), .key
(clave privada) y, opcionalmente, el CA bundle:
- Crea un Secret TLS en el namespace donde están tus Ingress:
kubectl -n traefik create secret tls wildcard-cert \
--cert=certificado_wildcard.crt \
--key=clave_wildcard.key
-
Si necesitas añadir la cadena de CA, concaténala al
.crt
:cat wildcard.crt ca-bundle.crt > fullchain.crt kubectl -n traefik create secret tls wildcard-cert --cert=fullchain.crt --key=clave.key
- Referéncialo en tus Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ejemplo-wildcard
namespace: traefik
spec:
ingressClassName: traefik
tls:
- hosts:
- app1.miempresa.com
- app2.miempresa.com
secretName: wildcard-cert
rules:
- host: app1.miempresa.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: servicio1
port:
number: 80
- host: app2.miempresa.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: servicio2
port:
number: 80
- Todos los Ingress que referencien
secretName: wildcard-cert
usarán ese mismo certificado SSL, y funcionarán para todos los subdominios cubiertos por el wildcard.
d) ¿Dónde se guardan los certificados en Kubernetes?
Los certificados (wildcard, Let's Encrypt, CA propia…) se almacenan como objetos Secret
de tipo kubernetes.io/tls
en el namespace correspondiente. No están en disco ni en ninguna ruta específica del pod o nodo. Traefik accede al Secret por nombre, a través de la API de Kubernetes.
Puedes ver los secrets así:
kubectl get secrets -n traefik
El contenido real está en la base de datos interna de Kubernetes (etcd).
e) Cómo crear un Secret TLS a partir de tus archivos de certificado
Para cualquier certificado SSL (wildcard, multiSAN, CA interna, etc.), el comando general es:
kubectl -n <namespace> create secret tls <nombre-del-secret> \
--cert=certificado.crt \
--key=clave.key
<namespace>
: donde esté el Ingress (ejemplo:traefik
)<nombre-del-secret>
: el que quieras (ejemplo:wildcard-cert
)--cert
: debe incluir el certificado y, opcionalmente, la cadena completa de CA (fullchain)--key
: la clave privada
¿Qué hace este comando?
- Sube el contenido de los archivos al clúster y crea un objeto
Secret
de tipokubernetes.io/tls
. - Kubernetes lo guarda cifrado en etcd y lo inyecta a los pods/controllers cuando un Ingress lo solicita.