--- title: "Cómo instalar K3s en Ubuntu 24.04 y crear un clúster" description: "Instala K3s en Ubuntu 24.04, une nodos worker al clúster, configura kubectl y publica una aplicación de prueba con Ingress de Traefik y un volumen local-path." category: "Kubernetes Avanzado" language: es source: https://cubepath.com/es/docs/kubernetes-avanzado/instalacion-de-kubernetes-ligero-k3s updated: 2026-09-25 --- # Cómo instalar K3s en Ubuntu 24.04 y crear un clúster K3s es una distribución de Kubernetes certificada por la CNCF que se distribuye como un único binario y consume mucha menos memoria que una instalación con kubeadm. Incluye de serie containerd, Flannel, CoreDNS, el Ingress Controller Traefik, metrics-server y un provisionador de almacenamiento local. En este tutorial instalarás un servidor K3s en Ubuntu 24.04, le unirás un nodo worker, configurarás `kubectl` para tu usuario y publicarás una aplicación de prueba con Ingress y almacenamiento persistente. ## Requisitos previos - Dos servidores con Ubuntu 24.04 LTS, por ejemplo dos VPS de CubePath: uno hará de servidor (plano de control) y otro de agente (worker). Si solo quieres un clúster de un nodo, basta con uno y puedes saltarte el paso 4. - Un usuario no root con privilegios `sudo` en ambos. - Al menos 2 GB de RAM y 2 vCPU en el servidor, y 1 GB de RAM en el agente. K3s arranca con menos, pero deja poco margen para tus cargas. - Conectividad entre los nodos, idealmente por una red privada. En esta guía `your_server_ip` es la IP del servidor que usará el agente para conectarse. - Nombres de host distintos en cada nodo: K3s rechaza dos nodos con el mismo nombre. ## Paso 1: Preparar el firewall K3s necesita varios puertos entre nodos. En el servidor, permite SSH, la API de Kubernetes, la red overlay de Flannel (VXLAN) y el kubelet. Sustituye `10.0.0.0/24` por la subred privada de tus nodos: ```bash sudo ufw allow OpenSSH sudo ufw allow 6443/tcp sudo ufw allow from 10.0.0.0/24 to any port 8472 proto udp sudo ufw allow from 10.0.0.0/24 to any port 10250 proto tcp ``` La documentación de K3s indica además que, con UFW activo, hay que permitir el tráfico de las redes de pods (`10.42.0.0/16`) y de servicios (`10.43.0.0/16`), que son los rangos por defecto: ```bash sudo ufw allow from 10.42.0.0/16 to any sudo ufw allow from 10.43.0.0/16 to any ``` Si vas a publicar aplicaciones por HTTP y HTTPS con Traefik, abre también esos puertos: ```bash sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable ``` Repite en el agente las reglas de SSH, 8472/udp, 10250/tcp y las de las redes de pods y servicios. El agente no necesita el puerto 6443 abierto. > Nota: si solo usas `kubectl` desde el propio servidor, puedes restringir el 6443 a tu IP con `sudo ufw allow from your_admin_ip to any port 6443 proto tcp` en lugar de abrirlo a todo Internet. ## Paso 2: Instalar el servidor K3s K3s se instala con un script oficial que descarga el binario, crea el servicio systemd `k3s` y añade los enlaces `kubectl`, `crictl` y `ctr`. Antes de ejecutarlo, crea el archivo de configuración para que el servidor arranque ya con los ajustes deseados: ```bash sudo mkdir -p /etc/rancher/k3s sudo nano /etc/rancher/k3s/config.yaml ``` Añade este contenido. `write-kubeconfig-mode` controla los permisos del kubeconfig que genera K3s, `tls-san` añade la IP o el nombre por el que accederás a la API al certificado, y `node-label` etiqueta el nodo: ```yaml write-kubeconfig-mode: "0600" tls-san: - "your_server_ip" node-label: - "environment=production" ``` Cada clave del archivo equivale a una opción de línea de comandos de `k3s server` sin los guiones iniciales. Descarga ahora el script de instalación y revísalo antes de ejecutarlo: ```bash curl -sfL https://get.k3s.io -o k3s-install.sh less k3s-install.sh ``` Ejecuta el script. Instala la última versión del canal `stable` y lee automáticamente `/etc/rancher/k3s/config.yaml`: ```bash sh k3s-install.sh ``` El script usa `sudo` internamente cuando lo lanzas con un usuario normal. Comprueba que el servicio está activo: ```bash sudo systemctl status k3s --no-pager ``` ```output ● k3s.service - Lightweight Kubernetes Loaded: loaded (/etc/systemd/system/k3s.service; enabled; preset: enabled) Active: active (running) since ... ``` Y que el nodo aparece como `Ready` (puede tardar unos 30 segundos): ```bash sudo k3s kubectl get nodes ``` ```output NAME STATUS ROLES AGE VERSION k3s-server Ready control-plane,master 45s v1.3x.x+k3s1 ``` ## Paso 3: Configurar kubectl para tu usuario K3s escribe el kubeconfig en `/etc/rancher/k3s/k3s.yaml`, que solo puede leer root. Cópialo a tu directorio personal para usar `kubectl` sin `sudo`: ```bash mkdir -p ~/.kube sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config sudo chown "$USER":"$USER" ~/.kube/config chmod 600 ~/.kube/config ``` Comprueba que funciona y revisa los componentes del sistema: ```bash kubectl get pods -A ``` ```output NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-... 1/1 Running 0 2m kube-system helm-install-traefik-... 0/1 Completed 1 2m kube-system helm-install-traefik-crd-... 0/1 Completed 0 2m kube-system local-path-provisioner-... 1/1 Running 0 2m kube-system metrics-server-... 1/1 Running 0 2m kube-system svclb-traefik-... 2/2 Running 0 90s kube-system traefik-... 1/1 Running 0 90s ``` Los pods `helm-install-*` en estado `Completed` son normales: son los trabajos que instalan Traefik a partir de los manifiestos incluidos. Si quieres administrar el clúster desde tu equipo, copia ese mismo archivo y cambia `server: https://127.0.0.1:6443` por `https://your_server_ip:6443`. Funciona porque añadiste esa IP a `tls-san`. ## Paso 4: Unir un nodo agente Los agentes se autentican con el token del servidor. Muéstralo en el servidor: ```bash sudo cat /var/lib/rancher/k3s/server/node-token ``` ```output K10abc123...::server:0123456789abcdef ``` En el nodo agente, descarga el mismo script, revísalo y ejecútalo con las variables `K3S_URL` y `K3S_TOKEN`. Cuando `K3S_URL` está definida, el script instala K3s en modo agente con el servicio `k3s-agent`: ```bash curl -sfL https://get.k3s.io -o k3s-install.sh less k3s-install.sh K3S_URL=https://your_server_ip:6443 K3S_TOKEN=your_node_token sh k3s-install.sh ``` Sustituye `your_node_token` por el valor completo obtenido antes. Comprueba el servicio en el agente: ```bash sudo systemctl status k3s-agent --no-pager ``` Y desde el servidor verifica que el nuevo nodo se ha unido: ```bash kubectl get nodes -o wide ``` ```output NAME STATUS ROLES AGE VERSION INTERNAL-IP k3s-server Ready control-plane,master 10m v1.3x.x+k3s1 10.0.0.10 k3s-agent1 Ready 40s v1.3x.x+k3s1 10.0.0.11 ``` Si los nodos se comunican por una red privada y K3s ha elegido la IP pública como `INTERNAL-IP`, añade `node-ip: "ip_privada_del_nodo"` a `/etc/rancher/k3s/config.yaml` en cada nodo y reinicia el servicio (`k3s` o `k3s-agent`). ## Paso 5: Desplegar una aplicación de prueba con Ingress Traefik ya escucha en los puertos 80 y 443 de los nodos gracias al balanceador integrado ServiceLB. Crea un manifiesto con un Deployment de Nginx, su Service y un Ingress: ```bash nano demo.yaml ``` ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: demo spec: replicas: 2 selector: matchLabels: app: demo template: metadata: labels: app: demo spec: containers: - name: nginx image: nginx:stable ports: - containerPort: 80 resources: requests: cpu: 50m memory: 64Mi limits: memory: 128Mi --- apiVersion: v1 kind: Service metadata: name: demo spec: selector: app: demo ports: - port: 80 targetPort: 80 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo spec: ingressClassName: traefik rules: - host: demo.your_domain http: paths: - path: / pathType: Prefix backend: service: name: demo port: number: 80 ``` Aplica el manifiesto y espera a que el Deployment esté disponible: ```bash kubectl apply -f demo.yaml kubectl rollout status deployment/demo ``` ```output deployment "demo" successfully rolled out ``` Prueba el Ingress sin necesidad de DNS enviando la cabecera `Host` al servidor: ```bash curl -H "Host: demo.your_domain" http://your_server_ip ``` La respuesta debe ser el HTML de la página de bienvenida de Nginx. Cuando apuntes un registro A de `demo.your_domain` a la IP del servidor, podrás abrirla en el navegador. ## Paso 6: Usar almacenamiento persistente con local-path K3s crea la StorageClass `local-path`, marcada como predeterminada, que guarda los datos en `/var/lib/rancher/k3s/storage` del nodo donde se ejecuta el pod. Crea un PVC y un pod que escriba en él: ```bash nano pvc-demo.yaml ``` ```yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: data-demo spec: accessModes: - ReadWriteOnce storageClassName: local-path resources: requests: storage: 1Gi --- apiVersion: v1 kind: Pod metadata: name: pvc-demo spec: containers: - name: busybox image: busybox:stable command: ["sh", "-c", "date >> /data/log.txt && sleep 3600"] volumeMounts: - name: data mountPath: /data volumes: - name: data persistentVolumeClaim: claimName: data-demo ``` ```bash kubectl apply -f pvc-demo.yaml kubectl get pvc data-demo ``` ```output NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE data-demo Bound pvc-3f1c... 1Gi RWO local-path 20s ``` El PVC queda en `Pending` hasta que un pod lo usa, porque la StorageClass tiene el modo `WaitForFirstConsumer`. Comprueba que el archivo se ha escrito: ```bash kubectl exec pvc-demo -- cat /data/log.txt ``` > Importante: los volúmenes `local-path` viven en el disco de un único nodo. Si ese nodo cae, el pod no puede moverse a otro con sus datos. Para datos críticos usa una solución replicada como Longhorn o copias de seguridad externas. Cuando termines, elimina los recursos de prueba: ```bash kubectl delete -f pvc-demo.yaml -f demo.yaml ``` ## Mantenimiento: actualizar y desinstalar Para actualizar K3s, vuelve a ejecutar el script de instalación con la misma configuración. Actualiza primero el servidor y después los agentes: ```bash curl -sfL https://get.k3s.io -o k3s-install.sh sh k3s-install.sh ``` En los agentes repite el comando con `K3S_URL` y `K3S_TOKEN`. El script instala también desinstaladores: `/usr/local/bin/k3s-uninstall.sh` en el servidor y `/usr/local/bin/k3s-agent-uninstall.sh` en los agentes. Ambos borran el servicio, los contenedores y los datos del clúster. ## Solución de problemas **El servicio `k3s` no arranca.** Revisa el registro del servicio; un error de sintaxis en `config.yaml` o el puerto 6443 ocupado aparecen aquí: ```bash sudo journalctl -u k3s -n 100 --no-pager sudo ss -tlnp | grep 6443 ``` **El agente no se une al clúster.** Mira el registro del agente y comprueba que llega a la API. La respuesta `pong` confirma la conectividad: ```bash sudo journalctl -u k3s-agent -n 100 --no-pager curl -ks https://your_server_ip:6443/ping ``` Si aparece un error de token, vuelve a copiarlo completo desde `/var/lib/rancher/k3s/server/node-token`. Si el nodo aparece pero los pods de nodos distintos no se ven entre sí, el puerto 8472/udp está bloqueado entre ellos. **El PVC se queda en `Pending` con un pod ya creado.** Revisa el provisionador y el espacio en disco del nodo: ```bash kubectl -n kube-system logs deploy/local-path-provisioner df -h /var/lib/rancher/k3s ``` ## Conclusión Tienes un clúster K3s con un servidor y un agente, `kubectl` configurado para tu usuario, una aplicación publicada con Traefik y un volumen persistente local. Como siguientes pasos puedes instalar cert-manager para obtener certificados TLS de Let's Encrypt en tus Ingress, pasar a un plano de control de alta disponibilidad con tres servidores y etcd embebido (`cluster-init: true` en el primero), o definir requests y límites de recursos para tus cargas.