Kubernetes es un sistema de código abierto desarrollado por Google para ejecutar y gestionar en un clúster aplicaciones basadas en microservicios en contenedores. Quienes utilizan Kubernetes suelen necesitar que los servicios que crean en Kubernetes sean accesibles desde fuera de su clúster de Kubernetes.
Aunque Kubernetes ofrece soluciones integradas para exponer servicios, descritas más adelante en Exposición de servicios de Kubernetes mediante soluciones integradas, dichas soluciones se limitan al balanceo de carga de capa 4 o al balanceo de carga HTTP mediante round-robin.
Este artículo muestra cómo utilizar NGINX Plus como una solución avanzada de equilibrio de carga de capa 7 para exponer servicios de Kubernetes a Internet, tanto si ejecuta Kubernetes en la nube como en su propia infraestructura.
Suponemos que tiene conocimientos básicos de Kubernetes (pods, servicios, controladores de replicación y etiquetas), así como un clúster de Kubernetes en funcionamiento. Para obtener más información sobre Kubernetes, consulte la guía oficial del usuario de Kubernetes.
Exposición de servicios de Kubernetes con soluciones integradas
Kubernetes ofrece varias opciones para exponer servicios. Dos de ellas, NodePort y LoadBalancer, corresponden a un tipo específico de servicio. Una tercera opción, la API Ingress, pasó a estar disponible en fase beta en la versión 1.1 de Kubernetes.
NodePort
Al especificar el tipo de servicio como NodePort el servicio queda disponible en el mismo puerto de cada nodo de Kubernetes. Para exponer el servicio a Internet, debe exponer uno o varios nodos en ese puerto. Para garantizar una alta disponibilidad, puede exponer varios nodos y utilizar el equilibrio de carga basado en DNS para distribuir el tráfico entre ellos, o bien colocar los nodos detrás del equilibrador de carga que prefiera.
Cuando el tráfico entrante llega a un nodo a través del puerto, se distribuye entre los pods del servicio. El balanceo de carga que realiza el proxy de red de Kubernetes (kube-proxy) que se ejecuta en cada nodo se limita al balanceo de carga TCP/UDP.
Balanceador de carga
Al especificar el tipo de servicio como LoadBalancer, se asigna un balanceador de carga en la nube que distribuye el tráfico entrante entre los pods del servicio.
La solución LoadBalancer solo es compatible con determinados proveedores de servicios en la nube y con Google Container Engine, y no está disponible si ejecuta Kubernetes en su propia infraestructura. Además, Kubernetes solo permite configurar el balanceo de carga TCP mediante round-robin, aunque el balanceador de carga en la nube disponga de funciones avanzadas, como la persistencia de sesión o el enrutamiento de solicitudes.
API de Ingress
Crear un recurso Ingress permite exponer servicios en Internet mediante URL personalizadas (por ejemplo, el servicio A en la URL /foo y el servicio B en la URL /bar) y varios nombres de host virtuales (por ejemplo, foo.example.com para un grupo de servicios y bar.example.com para otro grupo). Un controlador de Ingress procesa un recurso Ingress y configura un balanceador de carga externo.
Un controlador de Ingress no forma parte de una implementación estándar de Kubernetes: debe elegir el controlador que mejor se adapte a sus necesidades o implementar uno usted mismo y añadirlo a su clúster de Kubernetes. Se espera que pronto aparezcan muchas implementaciones de controladores, pero, por ahora, la única disponible es el controlador para el balanceador de carga HTTP de Google Compute Engine, que solo funciona si ejecuta Kubernetes en Google Compute Engine o Google Container Engine. La API de Ingress solo admite el balanceo de carga HTTP mediante round-robin, aunque el balanceador de carga real admita funciones avanzadas.
En el momento de redactar este documento, tanto la API de Ingress como el controlador del balanceador de carga HTTP de Google Compute Engine se encuentran en fase beta.
Actualización – NGINX Ingress Controller para NGINX y NGINX Plus ya está disponible en nuestro repositorio de GitHub. Para obtener más información sobre el producto, consulte NGINX Ingress Controller.
Aunque las soluciones mencionadas anteriormente son fáciles de configurar y funcionan sin necesidad de ajustes adicionales, no ofrecen ninguna funcionalidad avanzada, especialmente en lo que respecta al equilibrio de carga de capa 7.
Exposición de servicios de Kubernetes con NGINX Plus
[Editor – Esta sección se ha actualizado para hacer referencia a la API de NGINX Plus, que sustituye y deja obsoleto el módulo independiente de configuración dinámica mencionado originalmente aquí.]
Para integrar NGINX Plus con Kubernetes, debemos asegurarnos de que la configuración de NGINX Plus se mantenga sincronizada con Kubernetes y refleje los cambios en los servicios de Kubernetes, como la adición o eliminación de pods. Con NGINX Open Source, se modifica manualmente el archivo de configuración de NGINX y se vuelve a cargar la configuración. Con NGINX Plus, hay dos formas de actualizar la configuración de forma dinámica:
- Con las API – Este método utiliza la API de NGINX Plus para añadir y eliminar entradas de los pods de Kubernetes en la configuración de NGINX Plus, y la API de Kubernetes para obtener las direcciones IP de los pods. Este método requiere que escribamos algo de código, por lo que no lo trataremos en profundidad aquí. Para obtener más información, vea el seminario web de Kelsey Hightower, «Llevando Kubernetes al perímetro con NGINX Plus», en el que explora las API y crea una aplicación que las utiliza.
- Mediante la resolución periódica de nombres DNS – Este método solo requiere configurar correctamente NGINX Plus una vez, tal como se describe en la siguiente sección.
Uso de la reconfiguración basada en DNS
Suponemos que ya dispone de un clúster de Kubernetes en funcionamiento y de un host con la utilidad kubectl disponible para administrar el clúster. Para obtener instrucciones, consulte la guía de introducción a Kubernetes correspondiente a su tipo de clúster. También debe haber creado una imagen de Docker de NGINX Plus. Encontrará las instrucciones en Implementación de NGINX y NGINX Plus con Docker en nuestro blog.
A continuación, se resume lo que haremos:
- Configure un pod de NGINX Plus para exponer y equilibrar la carga del servicio que vamos a crear en el paso 2.
- Cree una aplicación web sencilla que actúe como nuestro servicio.
- Aumente y reduzca la escala del servicio y observe cómo NGINX Plus se reconfigura automáticamente.
Notas: Probamos la solución descrita en este blog con Kubernetes 1.0.6 ejecutándose en Google Compute Engine y en un entorno local de Vagrant, que es el que utilizamos a continuación.
En los comandos, los valores que pueden variar según la configuración de Kubernetes aparecen en cursiva.
Configuración del pod de NGINX Plus
Vamos a instalar NGINX Plus en un pod de Kubernetes, en un nodo que expondremos a Internet. Nuestro pod lo crea un controlador de replicación, que también estamos configurando. El archivo de configuración de NGINX Plus específico para Kubernetes se encuentra en una carpeta compartida entre el pod de NGINX Plus y el nodo, lo que facilita su mantenimiento.
Elegir un nodo para alojar el pod de NGINX Plus
Para designar el nodo en el que se ejecuta el pod de NGINX Plus, añadimos una etiqueta a dicho nodo. Para obtener la lista de todos los nodos, ejecutamos:
$ kubectl get nodesNAME LABELS STATUS
10.245.1.3 Kubernetes.io/hostname=10.245.1.3 Ready
10.245.1.4 Kubernetes.io/hostname=10.245.1.4 Ready
10.245.1.5 Kubernetes.io/hostname=10.245.1.5 ReadyElegimos el primer nodo y le añadimos una etiqueta ejecutando:
$ kubectl label node 10.245.1.3 role=nginxplusConfiguración del controlador de replicación para el pod de NGINX Plus
No creamos un pod de NGINX Plus directamente, sino a través de un controlador de replicación. Configuramos el controlador de replicación para el pod de NGINX Plus en un archivo de declaración de Kubernetes llamado «nginxplus-rc.yaml».
- Establecemos el número de
réplicasen uno, lo que significa que Kubernetes garantiza que siempre haya un pod de NGINX Plus en ejecución: si el pod falla, se sustituye por uno nuevo. - En el campo
nodeSelectorespecificamos que el pod de NGINX Plus se cree en un nodo con la etiquetarole:nginxplus. - Nuestro contenedor NGINX Plus expone dos puertos, el 80 y el 8080, y configuramos una asignación entre estos y los puertos 80 y 8080 del nodo.
- Nuestro contenedor de NGINX Plus también comparte la carpeta /etc/nginx/conf.d que se encuentra en el nodo. Como se explica más adelante en Configuración de NGINX Plus, compartir la carpeta nos permite reconfigurar NGINX Plus sin tener que volver a crear la imagen del contenedor.
apiVersion: v1
kind: ReplicationController
metadata:
name: nginxplus-rc
spec:
replicas: 1
selector:
app: nginxplus
template:
metadata:
labels:
app: nginxplus
spec:
nodeSelector:
role: nginxplus
containers:
- name: nginxplus
imagePullPolicy: IfNotPresent
image: nginxplus
ports:
- name: http
containerPort: 80
hostPort: 80
- name: http-alt
containerPort: 8080
hostPort: 8080
volumeMounts:
- mountPath: "/etc/nginx/conf.d"
name: etc-nginx-confd
volumes:
- hostPath:
path: "/etc/nginx/conf.d"
name: etc-nginx-confdHacer que la imagen de Docker de NGINX Plus esté disponible en el nodo
Como hemos indicado anteriormente, ya hemos creado una imagen de Docker de NGINX Plus. Ahora vamos a hacer que esté disponible en el nodo. Para simplificar, no utilizamos un repositorio privado de Docker, sino que cargamos manualmente la imagen en el nodo.
En el host donde creamos la imagen de Docker, ejecutamos el siguiente comando para guardar la imagen en un archivo:
$ docker save -o nginxplus.tar nginxplusTransferimos nginxplus.tar al nodo y ejecutamos el siguiente comando en él para cargar la imagen desde el archivo:
$ docker load -i nginxplus.tarConfiguración de NGINX Plus
En la carpeta /etc/nginx del contenedor de NGINX Plus, conservamos el archivo de configuración principal predeterminado nginx.conf que se incluye con los paquetes de NGINX Plus. La directiva include del archivo predeterminado carga otros archivos de configuración de la carpeta /etc/nginx/conf.d. Tal como se especifica en el archivo de declaración del controlador de replicación de NGINX Plus (nginxplus-rc.yaml), compartimos la carpeta /etc/nginx/conf.d del nodo de NGINX Plus con el contenedor. Esto nos permite modificar los archivos de configuración almacenados en la carpeta (en el nodo) sin tener que volver a compilar la imagen de Docker de NGINX Plus, algo que tendríamos que hacer si creáramos la carpeta directamente en el contenedor. Colocamos nuestro archivo de configuración específico de Kubernetes (backend.conf) en la carpeta compartida.
Primero, vamos a crear la carpeta /etc/nginx/conf.d en el nodo.
$ sudo mkdir -p /etc/nginx/conf.dA continuación, creamos allí el archivo backend.conf e incluimos estas directivas:
resolver– Define el servidor DNS que NGINX Plus utiliza para volver a resolver periódicamente el nombre de dominio que usamos para identificar nuestros servidores ascendentes (en la directivaserverdentro del bloqueupstream, que se explica en el siguiente punto). Identificamos este servidor DNS mediante su nombre de dominio, kube-dns.kube-system.svc.cluster.local. El parámetrovalidindica a NGINX Plus que envíe la solicitud de nueva resolución cada cinco segundos. (Tenga en cuenta que el proceso de resolución de esta directiva difiere del de los servidores ascendentes: este nombre de dominio solo se resuelve cuando NGINX se inicia o se recarga, y NGINX Plus utiliza el servidor o los servidores DNS del sistema definidos en el archivo /etc/resolv.conf para resolverlo).upstream– Crea un grupo de servidores upstream denominado backend que contiene los servidores que proporcionan el servicio de Kubernetes que estamos exponiendo. En lugar de enumerar los servidores individualmente, los identificamos mediante un nombre de host completo en una única directivaserver. El parámetroresolveindica a NGINX Plus que vuelva a resolver el nombre de host en tiempo de ejecución, de acuerdo con la configuración especificada mediante la directivaresolver. Dado que tanto el DNS de Kubernetes como NGINX Plus (R10 y versiones posteriores) admiten registros de servicio DNS (SRV), NGINX Plus puede obtener mediante DNS los números de puerto de los servidores upstream. Incluimos el parámetroservicepara que NGINX Plus solicite registrosSRV, especificando el nombre (_http) y el protocolo (_tcp) de los puertos expuestos por nuestro servicio. Declaramos esos valores en el archivo webapp-svc.yaml, que se explica más adelante en Creación del controlador de replicación para el servicio. Para obtener más información sobre la detección de servicios mediante DNS, consulte Uso de DNS para la detección de servicios con NGINX y NGINX Plus en nuestro blog.server(dos veces): define dos servidores virtuales:- El primer servidor escucha en el puerto 80 y distribuye las solicitudes entrantes de /webapp (nuestro servicio) entre los pods que ejecutan instancias del servicio. También configuramos comprobaciones de estado activas.
- El segundo servidor escucha en el puerto 8080. Aquí configuramos la supervisión de la actividad en tiempo real de NGINX Plus. Más adelante, la utilizaremos para comprobar que NGINX Plus se haya reconfigurado correctamente. [Editor: La configuración de este segundo servidor se ha actualizado para utilizar la API de NGINX Plus, que sustituye al módulo de estado independiente utilizado originalmente y hace que quede obsoleto.]
resolver kube-dns.kube-system.svc.cluster.local valid=5s;
upstream backend {
zone upstream-backend 64k;
server webapp-svc.default.svc.cluster.local service=_http._tcp resolve;
}
server {
listen 80;
status_zone backend-servers;
location /webapp {
proxy_pass http://backend;
health_check;
}
}
server {
listen 8080;
root /usr/share/nginx/html;
location = /dashboard.html { }
location = / {
return 302 /dashboard.html;
}
location /api {
api write=on;
}
}Creación del controlador de replicación
Ahora ya podemos crear el controlador de replicación ejecutando este comando:
$ kubectl create -f nginxplus-rc.yamlPara comprobar que se ha creado el pod de NGINX Plus, ejecutamos:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginxplus-rc-0ts5t 1/1 Running 0 17sEstamos ejecutando Kubernetes en un entorno local de Vagrant, por lo que sabemos que la dirección IP externa de nuestro nodo es 10.245.1.3 y utilizaremos esa dirección durante el resto de este ejemplo. Si está ejecutando Kubernetes en un proveedor de servicios en la nube, puede obtener la dirección IP externa de su nodo ejecutando:
$ kubectl get nodes node-name -o json | grep -i externalIP -A 1 "type": "ExternalIP",
"address": XXX.XXX.XXX.XXXSi utiliza un entorno en la nube, no olvide configurar una regla de firewall para permitir que el nodo de NGINX Plus acepte el tráfico entrante. Consulte la documentación de su proveedor de servicios en la nube.
Podemos comprobar que nuestro pod de NGINX Plus está en funcionamiento consultando el panel de monitorización de actividad en tiempo real de NGINX Plus, disponible en el puerto 8080 de la dirección IP externa del nodo (en nuestro caso, http://10.245.1.3:8080/dashboard.html). Sin embargo, si lo consultamos en este momento, no veremos ningún servidor para nuestro servicio, ya que todavía no lo hemos creado.

Creación de un servicio sencillo de Kubernetes
Ahora es el momento de crear un servicio de Kubernetes. Nuestro servicio consta de dos servidores web, cada uno de los cuales ofrece una página web con información sobre el contenedor en el que se ejecuta.
Creación del controlador de replicación para el servicio
Primero creamos un controlador de replicación para que Kubernetes garantice que el número especificado de réplicas del servidor web (pods) esté siempre en ejecución en el clúster. Este es el archivo de declaración (webapp-rc.yaml):
apiVersion: v1kind: ReplicationController
metadata:
name: webapp-rc
spec:
replicas: 2
selector:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: hello
image: nginxdemos/hello
ports:
- containerPort: 80Nuestro controlador consta de dos servidores web. Declaramos un controlador formado por pods con un único contenedor que expone el puerto 80. La imagen nginxdemos/hello se descargará de Docker Hub.
Para crear el controlador de replicación, ejecutamos el siguiente comando:
$ kubectl create -f webapp-rc.yamlPara comprobar que nuestros pods se han creado, podemos ejecutar el siguiente comando. Usamos el selector de etiquetas app=webapp para obtener únicamente los pods creados por el controlador de replicación en el paso anterior:
$ kubectl get pods -l app=webapp
NAME READY STATUS RESTARTS AGE
webapp-rc-544f1 1/1 Running 0 2m
webapp-rc-uk6pm 1/1 Running 0 2mCreación del servicio
A continuación, creamos un servicio para los pods creados por nuestro controlador de replicación. Declaramos el servicio mediante el siguiente archivo (webapp-service.yaml):
apiVersion: v1kind: Service
metadata:
name: webapp-svc
spec:
clusterIP: None
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: webappAquí declaramos un servicio sin encabezado especial estableciendo el campo ClusterIP en None. Con este tipo de servicio, no se asigna ninguna dirección IP del clúster y el servicio no está disponible a través de kube-proxy. Una consulta DNS al DNS de Kubernetes devuelve varios registros A (las direcciones IP de nuestros pods).
También declaramos el puerto que NGINX Plus utilizará para conectarse a los pods. Además de especificar los números de puerto y puerto de destino, indicamos el nombre (http) y el protocolo (TCP). Utilizamos esos valores en el archivo de configuración de NGINX Plus, donde indicamos a NGINX Plus que obtenga los números de puerto de los pods mediante DNS utilizando registros SRV.
Al establecer el campo selector en app: webapp, declaramos qué pods pertenecen al servicio, concretamente los pods creados por nuestro controlador de replicación de NGINX (definido en webapp-rc.yaml).
Ejecutamos el siguiente comando, que crea el servicio:
$ kubectl create -f webapp-service.yamlAhora, si actualizamos la página del panel de control y hacemos clic en la pestaña «Upstreams» de la esquina superior derecha, veremos los dos servidores que hemos añadido.

También podemos comprobar que NGINX Plus distribuye el tráfico entre los pods del servicio. Si es así, cuando accedemos a http://10.245.1.3/webapp/ desde un navegador, la página nos muestra información sobre el contenedor en el que se ejecuta el servidor web, como el nombre de host y la dirección IP.
Si actualizamos esta página varias veces y consultamos el panel de estado, veremos cómo se distribuyen las solicitudes entre los dos servidores upstream.
Escalar el servicio de Kubernetes
[Editor: Esta sección se ha actualizado para utilizar la API de NGINX Plus, que sustituye al módulo de estado independiente utilizado originalmente y lo marca como obsoleto.]
Ahora añadamos dos pods más a nuestro servicio y asegurémonos de que la configuración de NGINX Plus vuelva a actualizarse automáticamente. Ejecutamos este comando para cambiar el número de pods a cuatro escalando el controlador de replicación:
$ kubectl scale rc webapp-rc --replicas=4
scaledPara comprobar que NGINX Plus se ha reconfigurado, podríamos volver a consultar el panel, pero esta vez utilizaremos la API de NGINX Plus. Ejecutamos el siguiente comando, donde 10.245.1.3 es la dirección IP externa de nuestro nodo NGINX Plus y 3 es la versión de la API de NGINX Plus. Para dar un formato legible a la salida JSON, la canalizamos a jq.
$ curl -s 10.245.1.3:8080/api/3/http/upstreams/backend/servers | jq{
"peers": [
{
"id": 1,
"server": "10.0.0.1:80",
"backup": false,
"weight": 1,
"state": "unhealthy",
"active": 0,
"requests": 1,
"responses": {
"1xx": 0,
"2xx": 0,
"3xx": 0,
"4xx": 0,
"5xx": 0,
"total": 0
},
"sent": 0,
"received": 0,
"fails": 0,
"unavail": 0,
"health_checks": {
"checks": 1,
"fails": 1,
"unhealthy": 1,
"last_passed": false
},
"downtime": 33965,
"downstart": 1445378182275,
"selected": 1445378131000
},
{
"id": 2,
"server": "10.246.1.6:80",
...
},
{
"id": 3,
"server": "10.246.3.2:80",
...
{
"id": 4,
"server": "10.0.0.2:80",
...
}
],
"keepalive": 0
}La matriz peers de la salida JSON tiene exactamente cuatro elementos, uno por cada servidor web.
Ahora reduzcamos el número de pods de cuatro a uno y volvamos a comprobar el estado de NGINX Plus:
$ kubectl scale rc webapp-rc --replicas=1scaled
$ curl -s 10.245.1.3:8080/api/3/http/upstreams/backend/servers | jqAhora la matriz peers de la salida JSON contiene un solo elemento (la salida es la misma que la del par con el ID 1 en el comando de ejemplo anterior).
Ahora que tenemos NGINX Plus en funcionamiento, podemos empezar a aprovechar sus funciones avanzadas, como la persistencia de sesión, la terminación SSL/TLS, el enrutamiento de solicitudes, la monitorización avanzada y muchas más.
Resumen
Las opciones de reconfiguración dinámica disponibles en NGINX Plus permiten integrarlo fácilmente con Kubernetes, ya sea mediante programación a través de una API o íntegramente mediante DNS. El uso de NGINX Plus para exponer servicios de Kubernetes a Internet ofrece muchas funciones de las que carecen las soluciones de balanceo de carga integradas actualmente en Kubernetes.
Para descubrir cómo funciona NGINX Plus con Kubernetes, comience hoy mismo su prueba gratuita de 30 días o póngase en contacto con nosotros para hablar sobre su caso de uso.
Sobre el autor
Artículos relacionados del blog
Únete a F5 NGINX en AppWorld 2024
Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.
Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.
Exposición de APIs en Kubernetes
La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».
NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.
Presentamos NGINX Plus R22
NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.
Presentamos NGINX Plus R17
NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.