Kubernetes es un sistema de código abierto desarrollado por Google para ejecutar y administrar aplicações basadas en microservicios en contenedores en un clúster. Las personas que usan Kubernetes a menudo necesitan hacer que los servicios que crean en Kubernetes sean accesibles desde fuera de su clúster de Kubernetes.
Si bien Kubernetes proporciona soluciones integradas para exponer servicios, que se describen en Exposición de servicios de Kubernetes con soluciones integradas a continuación, esas soluciones lo limitan al equilibrio de carga de capa 4 o al equilibrio de carga HTTP por turnos.
Esta publicación muestra cómo usar NGINX Plus como una solución avanzada de equilibrio de carga de capa 7 para exponer servicios de Kubernetes a Internet, ya sea que esté ejecutando Kubernetes en la nube o en su propia infraestructura.
Supondremos que tiene un conocimiento básico de Kubernetes (pods, servicios, controladores de replicación y etiquetas) y un clúster de Kubernetes en ejecución. Para obtener más información sobre Kubernetes, consulte la guía oficial del usuario de Kubernetes .
Kubernetes ofrece varias opciones para exponer servicios . Dos de ellos, NodePort y LoadBalancer, corresponden a un tipo específico de servicio. Una tercera opción, Ingress API, estuvo disponible como versión beta en la versión 1.1 de Kubernetes.
Al especificar el tipo de servicio como NodePort , el servicio está disponible en el mismo puerto en cada nodo de Kubernetes. Para exponer el servicio a Internet, expone uno o más nodos en ese puerto. Para lograr una alta disponibilidad, puede exponer múltiples nodos y usar el equilibrio de carga basado en DNS para distribuir el tráfico entre ellos, o puede colocar los nodos detrás de un equilibrador de carga de su elección.
Cuando el tráfico entrante llega a un nodo en el puerto, se equilibra la carga entre los pods del servicio. El equilibrio de carga que realiza el proxy de red Kubernetes ( kube-proxy
) que se ejecuta en cada nodo está limitado al equilibrio de carga TCP/UDP.
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 ciertos proveedores de nube y Google Container Engine , y no está disponible si ejecuta Kubernetes en su propia infraestructura. Además, Kubernetes solo permite configurar el equilibrio de carga TCP por turnos, incluso si el equilibrador de carga en la nube tiene funciones avanzadas como persistencia de sesión o mapeo de solicitudes.
La creación de un recurso de Ingress le permite exponer servicios a Internet en URL personalizadas (por ejemplo, el servicio A en la URL /foo y el servicio B en la URL /bar ) y múltiples 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 consume un recurso de Ingress y configura un balanceador de carga externo.
Un controlador de Ingress no es 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 agregarlo a su clúster de Kubernetes. Se espera que pronto aparezcan muchas implementaciones de controladores, pero por ahora la única implementación disponible es el controlador para Google Compute Engine HTTP Load Balancer , que solo funciona si está ejecutando Kubernetes en Google Compute Engine o Google Container Engine . La API de Ingress solo admite el equilibrio de carga HTTP round-robin, incluso si el equilibrador de carga real admite funciones avanzadas.
Al momento de escribir este artículo, tanto la API de Ingress como el controlador del balanceador de carga HTTP de Google Compute Engine están en versión beta.
Actualización : el controlador de ingreso NGINX para NGINX y NGINX Plus ahora está disponible en nuestro repositorio de GitHub . Para obtener detalles del producto, consulte Controlador de ingreso NGINX .
Si bien las soluciones mencionadas anteriormente son fáciles de configurar y funcionan de inmediato, no brindan ninguna función avanzada, especialmente funciones relacionadas con el equilibrio de carga de capa 7.
[Editor: esta sección se ha actualizado para hacer referencia a la API NGINX Plus , que reemplaza y deja obsoleto el módulo de configuración dinámica independiente que se analizó originalmente aquí].
Para integrar NGINX Plus con Kubernetes, debemos asegurarnos de que la configuración de NGINX Plus permanezca sincronizada con Kubernetes, reflejando los cambios en los servicios de Kubernetes, como la adición o eliminación de pods. Con NGINX Open Source, modifica manualmente el archivo de configuración de NGINX y realiza una recarga de la configuración. Con NGINX Plus, hay dos formas de actualizar la configuración dinámicamente:
Suponemos que ya tiene un clúster de Kubernetes en ejecución y 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 es necesario haber creado una imagen Docker de NGINX Plus, y las instrucciones están disponibles en Implementación de NGINX y NGINX Plus con Docker en nuestro blog.
Aquí hay un resumen de lo que haremos:
Notas: Probamos la solución descrita en este blog con Kubernetes 1.0.6 ejecutándose en Google Compute Engine y una configuración local de Vagrant , que es lo que estamos usando a continuación.
En los comandos, los valores que pueden ser diferentes para su configuración de Kubernetes aparecen en cursiva.
Estamos colocando NGINX Plus en un pod de Kubernetes en un nodo que exponemos a Internet. Nuestro pod se crea mediante un controlador de replicación, que también estamos configurando. Nuestro archivo de configuración NGINX Plus específico de Kubernetes reside en una carpeta compartida entre el pod NGINX Plus y el nodo, lo que hace que sea más sencillo de mantener.
Para designar el nodo donde se ejecuta el pod NGINX Plus, agregamos una etiqueta a ese nodo. Obtenemos la lista de todos los nodos ejecutando:
$ kubectl get nodes NOMBRE ETIQUETAS ESTADO 10.245.1.3 Kubernetes.io/hostname=10.245.1.3 Listo 10.245.1.4 Kubernetes.io/hostname=10.245.1.4 Listo 10.245.1.5 Kubernetes.io/hostname=10.245.1.5 Listo
Elegimos el primer nodo y le agregamos una etiqueta ejecutando:
$ kubectl etiqueta nodo10.245.1.3 rol=nginxplus
No estamos creando un pod NGINX Plus directamente, sino a través de un controlador de replicación. Configuramos el controlador de replicación para el pod NGINX Plus en un archivo de declaración de Kubernetes llamado nginxplus-rc.yaml .
réplicas
en uno, lo que significa que Kubernetes se asegura de que siempre haya un pod NGINX Plus en ejecución: si el pod falla, se reemplaza por uno nuevo.nodeSelector
especificamos que el pod NGINX Plus se crea en un nodo etiquetado con el rol:
nginxplus
.apiVersion: v1
tipo: Controlador de Replicación
Metadatos:
Nombre: nginxplus-rc
Especificaciones:
Réplicas: 1
Selector:
aplicación: nginxplus
Plantilla:
Metadatos:
Etiquetas:
aplicación: nginxplus
Especificación:
Selector de nodos:
Rol: nginxplus
Contenedores:
- Nombre: nginxplus
Política de extracción de imágenes: IfNotPresent
imagen: nginxplus
puertos:
- nombre: http
puertoContainer: 80
Puerto del host: 80
- nombre: http-alt
puertoContenedor: 8080
Puerto del host: 8080
volumenMontajes:
- Ruta de montaje: "/etc/nginx/conf.d"
nombre: etc-nginx-confd
volumenes:
- Ruta de host:
ruta: "/etc/nginx/conf.d"
nombre: etc-nginx-confd
Como dijimos anteriormente, ya hemos creado una imagen Docker de NGINX Plus. Ahora lo ponemos disponible en el nodo. Para simplificar, no utilizamos un repositorio Docker privado y simplemente 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:
$ ventana acoplable guardar -o nginxplus.tar nginxplus
Transferimos nginxplus.tar al nodo y ejecutamos el siguiente comando en el nodo para cargar la imagen desde el archivo:
$ docker load -i nginxplus.tar
En la carpeta /etc/nginx del contenedor NGINX Plus, conservamos el archivo de configuración principal predeterminado nginx.conf que viene con los paquetes NGINX Plus. La directiva de inclusión
en el archivo predeterminado lee otros archivos de configuración de la carpeta /etc/nginx/conf.d . Como se especifica en el archivo de declaración del controlador de replicación NGINX Plus ( nginxplus-rc.yaml ), compartimos la carpeta /etc/nginx/conf.d en el nodo NGINX Plus con el contenedor. Compartir significa que podemos realizar cambios en los archivos de configuración almacenados en la carpeta (en el nodo) sin tener que reconstruir la imagen Docker de NGINX Plus, lo 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, creemos la carpeta /etc/nginx/conf.d en el nodo.
$ sudo mkdir -p /etc/nginx/conf.d
Luego 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 directiva de servidor
dentro del bloque ascendente
, que se analiza en el siguiente punto). Identificamos este servidor DNS por su nombre de dominio, kube-dns.kube-system.svc.cluster.local . El parámetro válido
le dice a NGINX Plus que envíe la solicitud de nueva resolución cada cinco segundos.
(Tenga en cuenta que el proceso de resolución para esta directiva difiere del de los servidores ascendentes: este nombre de dominio se resuelve solo 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 ascendente llamado backend para contener los servidores que proporcionan el servicio Kubernetes que estamos exponiendo. En lugar de enumerar los servidores individualmente, los identificamos con un nombre de host completo en una única directiva de servidor
. El parámetro de resolución
le indica a NGINX Plus que vuelva a resolver el nombre de host en tiempo de ejecución, de acuerdo con las configuraciones especificadas con la directiva de resolución
.
Dado que tanto Kubernetes DNS como NGINX Plus (R10 y posteriores) admiten registros del Servicio DNS ( SRV
), NGINX Plus puede obtener los números de puerto de los servidores ascendentes a través de DNS. Incluimos el parámetro de servicio
para que NGINX Plus solicite registros SRV
, especificando el nombre ( _http
) y el protocolo ( _tcp
) para los puertos expuestos por nuestro servicio. Declaramos esos valores en el archivo webapp-svc.yaml que se analiza en Creación del controlador de replicación para el servicio a continuación.
Para obtener más información sobre el descubrimiento de servicios con DNS, consulte Uso de DNS para el descubrimiento de servicios con NGINX y NGINX Plus en nuestro blog.
servidor
(dos veces) – Define dos servidores virtuales:
El primer servidor escucha en el puerto 80 y equilibra la carga de las solicitudes entrantes para /webapp (nuestro servicio) entre los pods que ejecutan instancias de servicio. También establecemos controles de salud activos .
El segundo servidor escucha en el puerto 8080. Aquí configuramos el monitoreo de actividad en vivo de NGINX Plus. Más tarde lo usaremos para comprobar que NGINX Plus se ha reconfigurado correctamente.
[Editor: La configuración de este segundo servidor se ha actualizado para utilizar la API NGINX Plus , que reemplaza y deja obsoleto el módulo de estado separado utilizado originalmente.]
Resolver kube-dns.kube-system.svc.cluster.local válido=5s;
backend ascendente {
zona backend ascendente 64k;
servidor webapp-svc.default.svc.cluster.local servicio=_http._tcp resolver;
}
servidor {
escuchar 80;
zona_estado servidores_backend;
ubicación /webapp {
contraseña_proxy http://backend;
comprobación_de_estado;
}
}
servidor {
escuchar 8080;
raíz /usr/share/nginx/html;
ubicación = /dashboard.html { }
ubicación = / {
devolver 302 /dashboard.html;
}
ubicación /api {
api escribir=on;
}
}
Ahora estamos listos para crear el controlador de replicación ejecutando este comando:
$ kubectl create -f nginxplus-rc.yaml
Para verificar que se creó el pod NGINX Plus, ejecutamos:
$ kubectl get pods NOMBRE LISTO ESTADO REINICIO EDAD nginxplus-rc-0ts5t 1/1 En ejecución 0 17 s
Estamos ejecutando Kubernetes en una configuración local de Vagrant, por lo que sabemos que la dirección IP externa de nuestro nodo es 10.245.1.3 y usaremos esa dirección para el resto de este ejemplo. Si está ejecutando Kubernetes en un proveedor de nube, puede obtener la dirección IP externa de su nodo ejecutando:
$ kubectl get nodes nombre-de-nodo -o json | grep -i IP-externa -A 1 "tipo": "IP externa", "dirección": XXX.XXX.XXX.XXX
Si está ejecutando en una nube, no olvide configurar una regla de firewall para permitir que el nodo NGINX Plus acepte tráfico entrante. Consulte la documentación de su proveedor de nube.
Podemos comprobar que nuestro pod NGINX Plus está en funcionamiento mirando el panel de monitoreo de actividad en vivo de NGINX Plus, que está disponible en el puerto 8080 en la dirección IP externa del nodo (en nuestro caso, http://10.245.1.3:8080/dashboard.html ). Sin embargo, si miramos este punto, no vemos ningún servidor para nuestro servicio, porque aún no hemos creado el servicio.
Ahora es el momento de crear un servicio Kubernetes. Nuestro servicio consta de dos servidores web, cada uno de los cuales sirve una página web con información sobre el contenedor en el que se ejecutan.
Primero creamos un controlador de replicación para que Kubernetes se asegure de que la cantidad especificada de réplicas de servidor web (pods) siempre estén ejecutándose en el clúster. Aquí está el archivo de declaración ( webapp-rc.yaml ):
apiVersion: v1tipo: Controlador de Replicación
Metadatos:
Nombre: webapp-rc
Especificaciones:
Réplicas: 2
Selector:
aplicación: webapp
Plantilla:
Metadatos:
Etiquetas:
aplicación: webapp
Especificaciones:
Contenedores:
- Nombre: Hola
Imagen: nginxdemos/hello
Puertos:
- PuertoContenedor: 80
Nuestro controlador consta de dos servidores web. Declaramos un controlador que consta de pods con un solo contenedor, exponiendo el puerto 80. La imagen nginxdemos/hello se extraerá de Docker Hub.
Para crear el controlador de replicación ejecutamos el siguiente comando:
$ kubectl create -f webapp-rc.yaml
Para comprobar que nuestros pods se han creado podemos ejecutar el siguiente comando. Usamos el selector de etiquetas app=webapp
para obtener solo los pods creados por el controlador de replicación en el paso anterior:
$ kubectl get pods -l app=webapp NOMBRE LISTO ESTADO REINICIO EDAD webapp-rc-544f1 1/1 En ejecución 0 2m webapp-rc-uk6pm 1/1 En ejecución 0 2m
A continuación, creamos un servicio para los pods creados por nuestro controlador de replicación. Declaramos el servicio con el siguiente archivo ( webapp-service.yaml ):
apiVersion: v1tipo: Servicio
Metadatos:
Nombre: webapp-svc
Especificación:
IP del clúster: Ninguno
Puertos:
- Puerto: 80
Puerto de destino: 80
protocolo: TCP
nombre: http
selector:
aplicación: webapp
Aquí declaramos un servicio headless especial configurando el campo ClusterIP
en None
. Con este tipo de servicio, no se asigna una dirección IP del clúster y el servicio no está disponible a través del proxy de kube. 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 conectar los pods. Además de especificar el puerto y los números de puerto de destino, especificamos el nombre ( http
) y el protocolo ( TCP
). Usamos esos valores en el archivo de configuración de NGINX Plus, en el que le indicamos a NGINX Plus que obtenga los números de puerto de los pods a través de DNS usando registros SRV
.
Al configurar el campo selector
en app:
webapp
, declaramos qué pods pertenecen al servicio, es decir, los pods creados por nuestro controlador de replicación NGINX (definido en webapp-rc.yaml ).
Ejecutamos el siguiente comando, que crea el servicio:
$ kubectl create -f webapp-service.yaml
Ahora, si actualizamos la página del panel y hacemos clic en la pestaña Upstreams en la esquina superior derecha, veremos los dos servidores que agregamos.
También podemos comprobar que NGINX Plus está equilibrando la carga del tráfico entre los pods del servicio. Si es así, cuando accedemos a http://10.245.1.3/webapp/ en un navegador, la página nos muestra la 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 observamos el panel de estado, veremos cómo se distribuyen las solicitudes entre los dos servidores ascendentes.
[Editor: esta sección se ha actualizado para utilizar la API NGINX Plus , que reemplaza y deja obsoleto el módulo de estado separado utilizado originalmente.]
Ahora agreguemos dos pods más a nuestro servicio y asegurémonos de que la configuración de NGINX Plus se actualice nuevamente de manera automática. Ejecutamos este comando para cambiar la cantidad de pods a cuatro escalando el controlador de replicación:
$ kubectl scale rc webapp-rc --replicas=4 escalado
Para comprobar que NGINX Plus se ha reconfigurado, podemos volver a mirar el panel de control, pero esta vez utilizaremos la API de NGINX Plus . Ejecutamos el siguiente comando, con10.245.1.3
siendo la dirección IP externa de nuestro nodo NGINX Plus y3
La versión de la API de NGINX Plus . Para formatear correctamente la salida JSON, la enviamos a jq
.
$ curl -s10.245.1.3 :8080/api/3 /http/upstreams/backend/servers | jq { "pares": [ { "id": 1, "servidor": "10.0.0.1:80", "copia de seguridad": falso, "peso": 1, "estado": "insalubre", "activo": 0, "solicitudes": 1, "respuestas": { "1xx": 0, "2xx": 0, "3xx": 0, "4xx": 0, "5xx": 0, "total": 0 }, "enviado": 0, "recibido": 0, "falla": 0, "no disponible": 0, "controles_de_salud": { "controles": 1, "falla": 1, "insalubre": 1, "last_passed": falso }, "tiempo de inactividad": 33965, "arranque descendente": 1445378182275, "seleccionado": 1445378131000 }, { "id": 2, "servidor": "10.246.1.6:80", ... }, { "id": 3, "servidor": "10.246.3.2:80", ... { "id": 4, "servidor": "10.0.0.2:80", ... } ], "mantener vivo": 0 }
La matriz de pares
en la salida JSON tiene exactamente cuatro elementos, uno para cada servidor web.
Ahora reduzcamos la cantidad de pods de cuatro a uno y verifiquemos nuevamente el estado de NGINX Plus:
$ kubectl scale rc webapp-rc --replicas=1 escalado $ curl -s10.245.1.3 :8080/api/3 /http/upstreams/backend/servers | jq
Ahora la matriz de pares
en la salida JSON contiene solo un elemento (la salida es la misma que para el par con ID 1 en el comando de muestra anterior).
Ahora que tenemos NGINX Plus en funcionamiento, podemos comenzar a aprovechar sus funciones avanzadas, como persistencia de sesión , terminación SSL/TLS , enrutamiento de solicitudes , monitoreo avanzado y más .
Las opciones de reconfiguración sobre la marcha disponibles en NGINX Plus le permiten integrarlo con Kubernetes con facilidad: ya sea de manera programada a través de una API o completamente por medio de DNS. El uso de NGINX Plus para exponer servicios de Kubernetes a Internet proporciona muchas características de las que carecen las soluciones de equilibrio de carga de Kubernetes integradas actuales.
Para explorar cómo NGINX Plus funciona junto con Kubernetes, comience hoy su prueba gratuita de 30 días o contáctenos para analizar su caso de uso.
"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.