Saltar a contenido

K8s

K8s es simplemente una abreviatura de Kubernetes, donde la "K" es la primera letra, la "s" es la última letra, y el "8" representa las 8 letras intermedias (u, b, e, r, n, e, t, e). Es una forma muy común y rápida de referirse a Kubernetes en la industria.

Kubernetes es una plataforma de orquestación de contenedores open-source desarrollada originalmente por Google y ahora mantenida por la Cloud Native Computing Foundation (CNCF).

Su función principal es automatizar el despliegue, la gestión, el escalado y la operación de aplicaciones en contenedores, normalmente basados en Docker u otros runtimes compatibles.

Características

  • Despliegue automático de contenedores (por ejemplo, imágenes de Docker).
  • Escalado automático de aplicaciones (más o menos réplicas de pods según carga).
  • Balanceo de carga entre pods.
  • Gestión de la configuración y secretos (ConfigMaps, Secrets).
  • Recuperación automática: reinicia pods que fallan, reemplaza nodos, etc.
  • Actualizaciones sin downtime mediante rolling updates.
  • Orquestación multi-nodo: distribuye contenedores en varios servidores (nodos) de forma eficiente.

Usos

  • Microservicios distribuidos.
  • Necesidad de alta disponibilidad.
  • Aplicaciones que deben escalar horizontalmente.
  • Infraestructura híbrida (on-premise + cloud).

Helm

https://helm.sh/

Helm es una herramienta de gestión de paquetes para Kubernetes, que permite facilitar la instalación, actualización y gestión de aplicaciones dentro de un clúster de Kubernetes. Utiliza lo que se conoce como "Charts", que son colecciones de archivos que describen un conjunto de recursos de Kubernetes necesarios para ejecutar una aplicación o servicio.

Helm simplifica la forma en que implementamos y administramos aplicaciones en Kubernetes, proporcionando una forma estandarizada de empaquetar, distribuir y actualizar aplicaciones. Con Helm, puedes gestionar dependencias, versiones y configuraciones de tus aplicaciones de manera más sencilla.

Ventajas de Usar Helm ✅

✔️ Automatización: Despliegues más rápidos y sencillos.
✔️ Gestión de versiones: Puedes hacer rollback a una versión anterior fácilmente.
✔️ Reutilización: Usa charts existentes o comparte los tuyos.
✔️ Configuración flexible: Puedes personalizar valores sin modificar los archivos originales.
✔️ Compatibilidad con CI/CD: Ideal para pipelines de integración continua.


Conclusión

Helm es una herramienta poderosa para administrar aplicaciones en Kubernetes de manera más eficiente. Facilita la instalación, configuración y actualización de aplicaciones, permitiéndote manejar entornos de producción con menos esfuerzo.

Helm | Installing Helm

Helm tiene un script de instalación que automáticamente descargará la última versión de Helm y la instalará localmente.

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh

Comprobar

helm version

Manifiesto

image.png

Un manifiesto en Kubernetes es simplemente otra forma de llamar a un archivo declarativo YAML que describe la configuración de un recurso en el clúster.

En otras palabras:
👉 "manifiesto" = archivo YAML que define un recurso de Kubernetes

Se le dice manifiesto porque "declara" de manera formal el estado deseado de un recurso dentro de Kubernetes. Es como una "declaración oficial" de cómo debe ser un Deployment, un Pod, un Service, etc.

Elementos

Un manifiesto en Kubernetes siempre tendrá al menos estas secciones:

  1. apiVersion: La versión de la API de Kubernetes que se usará.

  2. kind: El tipo de recurso que quieres crear (Pod, Deployment, Service, etc.).

  3. metadata: Información como el nombre del recurso y etiquetas.

  4. spec: La especificación detallada de cómo debe comportarse ese recurso.


📝 Ejemplo de un manifiesto

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

Este sería un manifiesto de Pod que puedes aplicar en Kubernetes.

Contenido

Un YAML de Kubernetes describe recursos como:

  • Pods
  • Deployments
  • Services
  • ConfigMaps
  • Secrets
  • Ingress, etc.

Puedes tener múltiples manifiestos en un solo archivo YAML, separados con ---, alternativamente puedes tener un manifiesto por archivo si prefieres mantener todo modular.

Aplicación de un manifiesto

kubectl apply -f mi-fichero.yaml

Kubernetes toma este manifiesto y se asegura de crear el recurso exactamente como lo describes. si el recurso ya está creado, Kubernetes lee el archivo, compara el estado deseado con el estado actual y concilia la diferencia para que tu aplicación quede como tú la definiste en el YAML.

POD

image.png

Un Pod en Kubernetes es la unidad más pequeña de despliegue y ejecución dentro del clúster. Un pod encapsula uno o más contenedores que comparten el mismo entorno de red, almacenamiento y configuración.

Características principales de un pod:

  1. Uno o varios contenedores: Aunque lo más común es que un pod contenga un solo contenedor, puede tener varios (por ejemplo, un contenedor principal y un "sidecar" para tareas auxiliares).
  2. Red compartida: Todos los contenedores dentro del pod comparten la misma dirección IP, el mismo puerto de red y las mismas interfaces de red.
  3. Volúmenes compartidos: Los contenedores dentro del pod pueden compartir volúmenes para intercambiar datos entre ellos.
  4. Ciclo de vida conjunto: Los contenedores dentro de un pod siempre se ejecutan juntos en el mismo nodo y se gestionan como una unidad. Si el pod muere, todos los contenedores dentro de él también se detienen.

📝 Manifiesto de Pod:

vi myapp.yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: httpd:latest
    ports:
    - containerPort: 80

🔧 Comandos para PODs

# despliegue del Pod
kubectl apply -f myapp.yaml

# Eliminar el Pod
kubectl delete -f myapp.yaml

# Devuelve el listado de pods
kubectl get pods

# Describe un pod
kubectl describe pod <name>

# Devuelve el consumo de recursos de un nodo
kubectl top pod <name> 

# Ejecutar un comando sobre un contenedor
kubectl exec <pod> -c <contenedor> <comando>

# Copia un fichero en un contenedor
kubectl cp /tmp/foo <pod-name>:/tmp/bar -c <container-name>

# Consulta de los de un contenedor
kubectl logs <pod-name> -c <container-name>

# Port forwarding
kubectl port-forward --address 0.0.0.0 pod/<pod-name> <host-port>:<pod-port>

Namespace

image.png

Los namespaces en Kubernetes son una forma de aislar y organizar recursos dentro de un mismo clúster.

Piensa en ellos como "espacios de trabajo" o "compartimentos" virtuales donde puedes tener recursos que no interfieren entre sí, aunque tengan el mismo nombre.

Utilidad

  1. Separar entornos: Puedes tener un namespace para desarrollo, otro para testing y otro para producción dentro del mismo clúster.
  2. Evitar conflictos de nombres: Puedes tener un Deployment llamado web-app en dos namespaces diferentes sin que choquen entre ellos.
  3. Aplicar políticas y límites:

    • Puedes aplicar quotas de recursos por namespace (CPU, memoria).
    • Puedes definir reglas de seguridad o control de acceso (RBAC) por namespace.
    • Facilitar la administración: En clústeres grandes, los namespaces ayudan a que los equipos trabajen de manera aislada y organizada.

Namespaces por defecto

  • default: Namespace por defecto donde se crean los recursos si no especificas otro.
  • kube-system: Recursos internos del sistema de Kubernetes (DNS, kube-proxy, etc.).
  • kube-public: Datos accesibles de forma pública dentro del clúster (rara vez se usa directamente).
  • kube-node-lease: Namespace para gestionar heartbeats de los nodos (para detectar si un nodo está vivo).

🔧 Comandos para trabajar con Namespaces:

# Devuelve el listado de namespaces
kubectl get namespaces

# Crea un namespace
kubectl create namespace <nombre>

# Especifical el namespace en el cliente kubectl
kubectl apply -f pod.yaml --namespace=<nombre>

# Establecer un determinado namespace como predeterminado
kubectl config set-context --current -–namespace=<nombre>

Definir un namespace dentro de un YAML

metadata:
  name: myapp
  namespace: desarrollo

Service

image.png

Un Service en Kubernetes es un recurso que proporciona una abstracción para exponer y acceder a un conjunto de pods de manera estable y confiable. Los pods son efímeros y sus IPs pueden cambiar, por lo que un Service actúa como un punto fijo de entrada que redirige el tráfico a los pods correctos, incluso si estos son recreados o se mueven a otro nodo.

Funciones principales de un servicio:

  1. Descubrimiento y balanceo de carga:

    • Distribuye automáticamente el tráfico entre los pods que coincidan con el selector definido.
    • Dirección IP estable:

    • Mientras que los pods tienen IPs dinámicas, el Service proporciona una IP virtual estable (ClusterIP) o un nombre DNS interno.

    • Exposición de la aplicación:

    • Puede exponer una aplicación internamente dentro del clúster o externamente hacia internet.

Tipos de servicios en Kubernetes:

  1. ClusterIP (por defecto):

    • Expone el servicio internamente dentro del clúster. No es accesible desde fuera.
    • NodePort:

    • Abre un puerto en cada nodo del clúster y redirige el tráfico a los pods.

    • LoadBalancer:

    • Crea un balanceador de carga externo (si el clúster está en una nube como AWS, GCP, Azure) y lo conecta al servicio.

    • ExternalName:

    • No redirige tráfico, pero mapea un nombre DNS interno a un nombre DNS externo.

📝 Manifiesto de "Service" tipo NodePort

---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  type: NodePort
  selector:
    app: myapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

Funcionamiento

  • El selector app: myapp hace que este Service envíe tráfico a todos los pods que tengan la etiqueta app=myapp.
  • El puerto 80 del Service se mapea al puerto 80 del pod (targetPort).

🔧 Comandos

# Aplica el manifiesto o los cambios
kubectl apply -f myapp.yaml

# Elimina el manifiesto 
kubectl delete -f myapp.yaml

# Comprueba
kubectl get all

NAME        READY   STATUS    RESTARTS   AGE
pod/myapp   1/1     Running   0          15m

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        44h
service/service1     NodePort    10.96.146.193   <none>        80:31926/TCP   15m

Deploymentimage.png

Un deployment en Kubernetes es un recurso que gestiona y mantiene el ciclo de vida de un conjunto de réplicas de un pod de manera declarativa. Es uno de los objetos más utilizados en Kubernetes, ya que te permite:

  1. Desplegar una aplicación: Define qué imagen de contenedor se debe usar, cuántas réplicas deben ejecutarse y cómo deben exponerse.
  2. Actualizar la aplicación sin tiempo de inactividad: Permite hacer rolling updates (actualizaciones progresivas) de los pods, minimizando la posibilidad de interrupciones.
  3. Gestionar el estado deseado: Kubernetes se asegura de que siempre haya el número de réplicas especificadas corriendo; si un pod falla, automáticamente se crea uno nuevo.
  4. Rollback: Puedes revertir a una versión anterior si una actualización falla.

📝 Manifiesto de "Deployment"

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp-container
          image: httpd:latest
          ports:
            - containerPort: 80

✅ Conceptos clave:

  • replicas: número de instancias de un pod.
  • selector: cómo Kubernetes identifica los pods que pertenecen a este deployment.
  • template: especifica la plantilla de los pods (contenedores, puertos, variables de entorno, etc.).
  • strategy: (opcional) puedes definir estrategias de despliegue como RollingUpdate o Recreate.

🔧 Comandos para deployments

# Aplica el manifiesto o los cambios
kubectl apply -f myapp.yaml

# Elimina el manifiesto 
kubectl delete -f myapp.yaml

# Comprueba deployments
kubectl get deployments

# Escala el despliegue
kubectl scale --replicas 2 deployment/myapp

Volúmenes

En Kubernetes, un volumen es una forma de proporcionar almacenamiento persistente a los pods y sus contenedores. Los volúmenes permiten que los datos persistan más allá de la vida de un pod individual (ya que los pods son efímeros y sus datos locales se pierden cuando son eliminados).

📦 Tipos de volúmenes en Kubernetes

Kubernetes soporta distintos tipos de volúmenes dependiendo del caso de uso y del proveedor de infraestructura.

  1. emptyDir: Crea un volumen vacío cuando el pod se inicializa. Se borra cuando el pod muere. Útil para almacenamiento temporal (caches, etc.).
  2. hostPath: Monta una carpeta del nodo físico (host) dentro del contenedor. No es recomendable para producción, pero útil para pruebas locales.
  3. nfs: Monta un volumen compartido a través de un servidor NFS externo.
  4. persistentVolumeClaim (PVC): Solicita almacenamiento persistente a través de un PersistentVolume. Es la forma estándar de montar almacenamiento duradero en Kubernetes.
  5. configMap / secret: Permiten montar configuraciones o secretos como archivos dentro de los pods.
  6. cloud-specific (AWS EBS, GCE Persistent Disk, Azure Disk): Volúmenes gestionados por proveedores cloud que pueden ser montados como almacenamiento persistente.

✅ Ejemplos

📝 Pod con volumen emptyDir
apiVersion: v1
kind: Pod
metadata:
  name: mypod-emptydir
spec:
  containers:
  - name: app
    image: httpd
    volumeMounts:
    - mountPath: /usr/local/apache2/htdocs  # Aquí se montará el volumen
      name: web-content
  volumes:
  - name: web-content
    emptyDir: {}   # Volumen tipo "directorio vacío"
  • Cuando el pod se crea, Kubernetes genera un directorio temporal en el nodo donde corre el pod.
  • Ese directorio está disponible en /usr/local/apache2/htdocs/ dentro del contenedor de httpd.
  • Los datos se mantienen mientras el pod esté vivo, pero se eliminan cuando el pod muere o se borra.

ℹ️ Casos de uso para emptyDir: - Para almacenamiento temporal de archivos o cachés. - Para compartir datos entre múltiples contenedores dentro del mismo pod. - Como espacio de trabajo para procesos batch o temporales.

📝 Pod con hostPath

apiVersion: v1
kind: Pod
metadata:
  name: mypod-hostpath
spec:
  containers:
  - name: app
    image: httpd
    volumeMounts:
    - mountPath: /usr/local/apache2/htdocs   # Dentro del contenedor
      name: web-content
  volumes:
  - name: web-content
    hostPath:
      path: /data/httpd                  # Ruta en el nodo físico
      type: DirectoryOrCreate            # Crea el directorio si no existe
  • El contenedor de httpd montará el directorio /data/nginx del host físico en /usr/local/apache2/htdocs/ dentro del contenedor.
  • Todo lo que escribas o leas dentro de /usr/local/apache2/htdocs/ se reflejará en /data/httpd del nodo.
  • Si el directorio /data/httpd no existe, Kubernetes lo creará automáticamente porque usamos type: DirectoryOrCreate.

ℹ️ Casos de uso para hostPath: - Es útil para entornos de desarrollo o pruebas locales. - En producción, no es recomendable, ya que acopla los pods a un nodo específico. - Puede ser peligroso si no se controla bien, ya que accede directamente al sistema de archivos del host.

📝 Pod con volumen nfs

apiVersion: v1
kind: Pod
metadata:
  name: mypod-nfs
spec:
  containers:
  - name: app
    image: httpd
    volumeMounts:
    - mountPath: /usr/local/apache2/htdocs  # Ruta dentro del contenedor
      name: nfs-volumen
  volumes:
  - name: nfs-volumen
    nfs:
      server: 192.168.1.100       # IP del servidor NFS
      path: /exports/web-content  # Ruta compartida en el NFS
  • El pod monta el directorio remoto /exports/web-content de un servidor NFS con IP 192.168.1.100.
  • Todo lo que el contenedor httpd lea o escriba en /usr/local/apache2/htdocs/ se guardará en el servidor NFS.
  • Este volumen puede ser compartido por varios pods al mismo tiempo, lo que lo hace útil para entornos donde múltiples aplicaciones necesitan acceder al mismo almacenamiento.

ℹ️ Casos de uso para NFS: - Servir archivos estáticos desde un punto común. - Compartir configuraciones, datos o resultados entre diferentes pods. - Montar un almacenamiento distribuido simple para apps legacy.

🗂️ Relación entre PersistentVolume (PV) y PersistentVolumeClaim (PVC)

  • PersistentVolume (PV): Es el recurso que representa un bloque de almacenamiento real en el clúster, como un disco EBS, un disco local o un volumen NFS.
  • PersistentVolumeClaim (PVC): Es una petición de almacenamiento por parte de un pod o aplicación. El PVC "reclama" un PV disponible según el tamaño y las características que necesita.

📝 1️⃣ PersistentVolume (PV)

Manifiesto PV NFS -> nfs-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /mnt/nfs_share
    server: <IP_DEL_SERVIDOR_NFS>

📝 2️⃣ PersistentVolumeClaim (PVC)

Manifiesto PVC que usa el PV anterior -> nfs-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

📝 3️⃣ Pod que usa el PVC

apiVersion: v1
kind: Pod
metadata:
  name: mypod-pvc
spec:
  containers:
  - name: app
    image: httpd
    volumeMounts:
    - mountPath: /usr/local/apache2/htdocs
      name: volumen-persistente
  volumes:
  - name: volumen-persistente
    persistentVolumeClaim:
      claimName: mypvc
  • El PV define el volumen físico.
  • El PVC es la solicitud que hace el Pod para "reclamar" ese volumen.
  • El Pod monta ese PVC en /usr/local/apache2/htdocs/ y todo lo que escriba allí será persistente, incluso si el pod es eliminado y recreado.

⚠️ Advertencia: En producción lo ideal es que el PV sea de un tipo distribuido o gestionado como: nfs, awsElasticBlockStore, gcePersistentDisk, cephfs, etc.

StorageClass

✅ StorageClasses permiten almacenamiento dinámico en Kubernetes.
✅ Diferentes provisioners ofrecen distintas opciones de almacenamiento.
✅ Facilitan la gestión automática de volúmenes sin intervención manual.

NFS

⚙ Opciones para usar NFS

Kubernetes no tiene un provisioner de NFS incorporado, pero puedes usar varias opciones de aprovisionamiento:

  1. Manualmente: Creas un PersistentVolume (PV) con una ruta NFS y luego un PersistentVolumeClaim (PVC) lo usa.
  2. Dynamic Provisioning con NFS Subdir External Provisioner: Usa un controlador que aprovisione dinámicamente volúmenes en un servidor NFS.

📌 Opción 1: StorageClass con aprovisionamiento manual (Static Provisioning)

En este caso, el StorageClass no es obligatorio, pero puede ayudar a organizar el almacenamiento.

📝 Paso 1: Crear un PersistentVolume (PV) manualmente
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual-nfs
  nfs:
    path: /exported/path/mi-directorio # directorio dentro de NFS
    server: 192.168.1.100  # IP de tu servidor NFS
📝 Paso 2: Crear un PersistentVolumeClaim (PVC)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: manual-nfs
  resources:
    requests:
      storage: 5Gi

🔹 Aquí, el PVC buscará un PV con storageClassName: manual-nfs.


📌 Opción 2: Aprovisionamiento dinámico con NFS Subdir External Provisioner

Para evitar crear manualmente PVs, puedes usar el NFS Subdir External Provisioner, que crea automáticamente directorios en un servidor NFS.

🛠 Paso 1: Instalar el NFS Provisioner

Si usas Helm, instala el provisioner:

# añade el repositorio helm
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm repo update
# instalar "nfs-provisioner"
helm install nfs-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner   --set storageClass.reclaimPolicy=Retain   --set storageClass.archiveOnDelete=false   --set storageClass.onDelete=delete   --set nfs.server=192.168.1.100   --set nfs.path=/exported/path
  • 📦 Instala nfs-provisioner en el namespace "default"
  • 🔗 Configura el servidor NFS y la ruta compartida (--set nfs.server=192.168.1.1 y --set nfs.path=/exported/path).
  • 📂 Crea una StorageClass llamada nfs-client

Para comprobar recursos NFS exportados:

sudo showmount -e 192.168.1.100

Export list for 192.168.1.100:
/exported/paths        0.0.0.0/0
📝 Paso 2: Crear un PersistentVolumeClaim (PVC)

Después de instalarlo, el provisioner crea una StorageClass como esta:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-dynamic-nfs
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs-client
  resources:
    requests:
      storage: 5Gi

🔹 Aquí, el PVC creará automáticamente un subdirectorio en el servidor NFS.


🚀 Comparativa

Método Ventajas Desventajas
Manual (Static Provisioning) Control total, útil si ya tienes PVs definidos Hay que crear cada PV manualmente
Dinámico (NFS Provisioner) Crea volúmenes automáticamente, menos gestión manual Requiere instalar el provisioner

Si tu infraestructura soporta un servidor NFS y necesitas escalabilidad, usar aprovisionamiento dinámico es la mejor opción.


🎯 Conclusión

  • NFS es una excelente opción para almacenamiento compartido en Kubernetes porque permite ReadWriteMany (RWX).
  • Puedes usar PVs estáticos o un provisioner dinámico para manejar el almacenamiento más eficientemente.
  • El NFS Subdir External Provisioner es una herramienta útil para facilitar la gestión.

Ingress

Ingress en Kubernetes es un recurso que te permite gestionar el acceso externo a servicios del clúster a través de HTTP/HTTPS.

  • Define reglas de enrutamiento basadas en rutas (paths) y dominios (hosts).
  • Expone múltiples services de Kubernetes detrás de una misma IP pública.
  • Facilita la gestión de TLS (SSL) para HTTPS.
  • Es compatible con autenticación, reescritura de URL, balanceo de carga y más.

Componentes principales:

  1. Ingress Resource: Es un manifiesto YAML donde defines las reglas de acceso (host, path, backend service).
  2. Ingress Controller: Es el componente que escucha los recursos de Ingress y configura un proxy (como NGINX, HAProxy, Traefik) para aplicarlas. No es parte nativa de Kubernetes; debes desplegarlo en el clúster.

Ingress Controller

Ingress Controller en Kubernetes es el componente que implementa las reglas definidas en un recurso Ingress y gestiona el tráfico HTTP/HTTPS desde fuera del clúster hacia los servicios internos.

  • El Ingress es solo una especificación, un manifiesto con reglas (por ejemplo: "el tráfico que llegue a /app1 va al Service A").
  • Pero el que realmente escucha esas reglas y configura un proxy HTTP es el Ingress Controller.

ℹ️ Nota: Sin Ingress Controller, el Ingress YAML no tendría efecto real.


Características

  • Crea un proxy HTTP(S) que expone tus aplicaciones al exterior.
  • Gestiona:
  • Balanceo de carga de capa 7 (HTTP).
  • Redirecciones y reescrituras.
  • TLS/SSL (certificados).
  • Autenticaciones (Basic Auth, JWT, etc.).
  • Reglas por dominio y rutas.

Ingress Controllers populares

  • NGINX Ingress Controller (el más común).
  • Traefik.
  • HAProxy Ingress.
  • Kong Ingress Controller (API Gateway).
  • Istio Gateway (cuando usas Istio como service mesh).

Funcionamiento

  1. Despliegas un Ingress Controller (por ejemplo, NGINX) como un Pod dentro de tu clúster.
  2. Ese Pod escucha los recursos Ingress que creas.
  3. Automáticamente configura un proxy inverso y expone los servicios según las reglas de tus manifiestos.

💡 Ejemplo:
  1. Usuario accede a https://myapp.dominio.com.
  2. Llega al Ingress Controller (que tiene la IP pública o está expuesto).
  3. El Controller lee la regla del Ingress y redirige la petición al Service correspondiente.

Despliegue NGINX Ingress Controller

1️⃣ Instalar NGINX Ingress Controller

Mediante helm
# Añadir el repositorio de ingress-nginx a Helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
# Instalar 
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx   --namespace ingress-nginx --create-namespace   --set controller.service.type=NodePort   --set controller.service.nodePorts.http=30080   --set controller.service.nodePorts.https=30443   --set controller.rbac.create=true  
  • controller.service.type=NodePort: Define que el Service será de tipo NodePort, necesario en Cluster local.
  • controller.service.nodePorts.http=30080: Configura el puerto HTTP en el 30080.
  • controller.service.nodePorts.https=30443: Configura el puerto HTTPS en el 30443.

👉 Esto instalará: - Deployment del NGINX Ingress Controller. - Service tipo LoadBalancer (o NodePort según el entorno). - RBAC y otros recursos necesarios.


2️⃣ Verificar que esté en ejecución

kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

Verás un servicio llamado ingress-nginx-controller que será el punto de entrada de tu tráfico HTTP/HTTPS.


3️⃣ Exponerlo en entornos sin LoadBalancer

Si estás en un clúster sin proveedor de nube (bare-metal, Proxmox, etc.), cambia el tipo de Service a NodePort:

kubectl edit svc ingress-nginx-controller -n ingress-nginx

Cambia type: LoadBalancer por type: NodePort y guarda.

ℹ️ Nota: Si instalaste con la opción "--set controller.service.type=NodePort" no será necesario este paso.


4️⃣ Manifiesto Ingress

Un ejemplo de Ingress que hace uso del controlador:

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: miapp.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-service
            port:
              number: 80

🚩 No olvides crear tu Service myapp-service previamente.


5️⃣ Configura tu DNS o /etc/hosts

Si es un entorno local puedes añadir en tu PC:

<IP_DEL_INGRESS_CONTROLLER> myapp.dominio.com

Desinstalar Ingress-NGINX con Helm

# Eliminar el release con Helm
helm uninstall ingress-nginx -n ingress-nginx

#(Opcional) Borrar el namespace si no lo necesitas más
kubectl delete namespace ingress-nginx

default-backend

Kubernetes no proporciona automáticamente una página por defecto para ingress-nginx. Sin embargo, podemos usar un simple Deployment y Service de Nginx para servir contenido estático de una página web para manejar las peticiones no encontradas. Se utiliza un default-backend, que es un servicio que responde con una página de error personalizada cuando no se encuentra una ruta coincidente en el controlador Ingress.

1. Crear un ConfigMap para la página web

El ConfigMap contendrá el contenido HTML de la página por defecto.

apiVersion: v1
kind: ConfigMap
metadata:
  name: default-404-page
  namespace: ingress-nginx
data:
  index.html: |
    <!DOCTYPE html>
    <html lang="es">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Página no encontrada</title>
      <style>
        body { font-family: Arial, sans-serif; text-align: center; margin: 50px; }
        h1 { color: red; }
      </style>
    </head>
    <body>
      <h1>404 - Página no encontrada</h1>
      <p>Lo sentimos, pero la página que buscas no existe.</p>
    </body>
    </html>

2. Crear el Deployment

Este Deployment utiliza la imagen de NGINX, monta el ConfigMap en el directorio de contenido web, crea el servicio y configura Ingress para mostrar "default-backend".

apiVersion: apps/v1
kind: Deployment
metadata:
  name: default-backend
  namespace: ingress-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: default-backend
  template:
    metadata:
      labels:
        app: default-backend
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        configMap:
          name: default-404-page
---
apiVersion: v1
kind: Service
metadata:
  name: default-backend
  namespace: ingress-nginx
spec:
  selector:
    app: default-backend
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

3. Aplica el deployment

Crea los manifiestos anteriores (se pueden unificar en uno solo) y aplica el deployment:

kubectl apply -f default-backend.yaml

4. Configurar ingress-nginx-controller para usar el Default Backend

El controlador Ingress-Nginx puede configurarse para usar un backend por defecto modificando su Deployment.

Ejecuta el Gifts el siguiente comando para editarlo en vivo:

kubectl edit deployment ingress-nginx-controller -n ingress-nginx

Añade la línea correspondiente en la sección de argumentos:

spec:
  containers:
  - name: controller
    args:
      - /nginx-ingress-controller
      - --default-backend-service=ingress-nginx/default-backend # añade la siguiente linea

Cert-Manager

https://cert-manager.io/

Cert-Manager es una herramienta nativa de Kubernetes que automatiza la gestión de certificados TLS dentro de un clúster.

Cert-Manager es un controlador de Kubernetes que: - Solicita certificados de diferentes proveedores (por ejemplo: Let's Encrypt, Venafi, CA interna, etc.). - Renueva automáticamente los certificados antes de que expiren. - Crea y genera los Secrets de Kubernetes que contienen los certificados TLS.

🛠️ Funcionamiento

  1. Automatiza la emisión y renovación de certificados TLS.
  2. Funciona con Ingress, Services, Pods, y cualquier recurso que necesite TLS.
  3. Soporta ACME (Let's Encrypt), certificados auto-firmados, Vault, entre otros.
  4. Utiliza recursos personalizados de Kubernetes como:
    • Issuer (local a un namespace)
    • ClusterIssuer (disponible para todo el clúster)
    • Certificate (define el dominio y cómo obtener el TLS)
    • Order, Challenge (para procesos ACME)

Instalación

Usando "Helm"

# Añadir repositorio
helm repo add jetstack https://charts.jetstack.io --force-update
helm repo update
# Instalar
helm install   cert-manager jetstack/cert-manager   --namespace cert-manager   --create-namespace   --set crds.enabled=true

ClusterIssuer

Global -> para todo el clúster

  • Se aplica una sola vez y puedes usarlo en cualquier namespace.
  • Ideal para producción cuando quieres certificados automáticos a nivel de clúster.

Manifiesto "letsencrypt-staging.yaml":

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    # The ACME server URL
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: user@example.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-staging
    # Enable the HTTP-01 challenge provider
    solvers:
      - http01:
          ingress:
            class: nginx

Manifiesto "letsencrypt-prod.yaml":

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: user@example.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod
    # Enable the HTTP-01 challenge provider
    solvers:
      - http01:
          ingress:
            class: nginx
# ClusterIssuer test
kubectl apply -f letsencrypt-staging.yaml

# ClusterIssuer Producción
kubectl apply -f letsencrypt-prod.yaml

Comprobación

# Lista ClusterIssuers
kubectl get clusterissuer

# Obtener detalles del ClusterIssuer
kubectl describe clusterissuer letsencrypt-staging
kubectl describe clusterissuer letsencrypt-prod

Manifiesto

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: httpd-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    cert-manager.io/cluster-issuer: letsencrypt-prod # issuer
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true" # redirige http -> https
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.dominio.com # FQDN app
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: httpd-service 
            port:
              number: 80
  tls:
  - hosts:
    - myapp.dominio.com # FQDN app
    secretName: myapp-tls

Desinstalación

helm delete cert-manager --namespace cert-manager
kubectl delete crd   issuers.cert-manager.io   clusterissuers.cert-manager.io   certificates.cert-manager.io   certificaterequests.cert-manager.io   orders.acme.cert-manager.io   challenges.acme.cert-manager.io