El objetivo último del desarrollo de aplicaciones es, por supuesto, publicar aplicaciones en Internet. Para los desarrolladores, Kubernetes simplifica en cierta medida este proceso al proporcionar el controlador Ingress como mecanismo para dirigir las solicitudes a la aplicación. Sin embargo, no todo funciona de forma tan autoservicio como probablemente desearía: sigue necesitando un registro en el sistema de nombres de dominio (DNS) que asocie el nombre de dominio de la aplicación con la dirección IP del controlador Ingress, así como un certificado TLS para proteger las conexiones mediante HTTPS. En la mayoría de las organizaciones, usted no gestiona directamente el DNS ni TLS, por lo que debe coordinarse con el equipo operativo (¡o los equipos!) que sí lo hace.
Las cosas tampoco son necesariamente más fáciles para los operadores. En la mayoría de las organizaciones, la necesidad de actualizar los registros DNS es tan poco frecuente que los procedimientos —tanto las normas empresariales como los pasos técnicos concretos— suelen ser escasos o inexistentes. Esto significa que, cuando necesitas añadir un registro DNS, primero tienes que buscar la documentación, preguntar a un compañero o, en el peor de los casos, averiguar cómo hacerlo por tu cuenta. También debes asegurarte de cumplir todas las normas de seguridad corporativas y de que el recurso Ingress esté correctamente etiquetado para los cortafuegos.
Afortunadamente, existe una forma de facilitarles la vida tanto a los desarrolladores como a los operadores. En este artículo, mostramos cómo los operadores pueden configurar un despliegue de Kubernetes para que los desarrolladores puedan actualizar por sí mismos los registros DNS y generar certificados TLS en un entorno de Kubernetes. Al preparar la infraestructura con antelación, puede garantizar que se cumplan todos los requisitos empresariales y técnicos necesarios.
Descripción general y requisitos previos
Una vez implementada la solución, lo único que tiene que hacer un desarrollador para exponer una aplicación a Internet es crear un controlador Ingress a partir de una plantilla proporcionada que incluya un nombre de dominio completo (FQDN) dentro de un dominio gestionado por la instalación de Kubernetes. Kubernetes utiliza la plantilla para asignar una dirección IP al controlador Ingress, crear el registro DNS A que asocia el FQDN con la dirección IP, generar certificados TLS para el FQDN y añadirlos al controlador Ingress. La limpieza es igual de sencilla: cuando se elimina el Ingress, también se eliminan los registros DNS.
La solución utiliza las siguientes tecnologías (más adelante proporcionamos instrucciones de instalación y configuración):
- Kubernetes.
- ExternalDNS.
- cert-manager.
- Let’s Encrypt.
- NGINX Ingress Controller de F5 NGINX, basado en NGINX Open Source o NGINX Plus. La solución no funciona con el NGINX Ingress Controller mantenido por la comunidad de Kubernetes. Para obtener más información sobre las diferencias entre ambos proyectos, consulte nuestro blog.
Antes de configurar la solución, necesita:
- Una instalación de Kubernetes en la nube con un objeto de salida (
LoadBalancer). La solución utiliza Linode, pero también funciona con otros proveedores de servicios en la nube. - Un nombre de dominio alojado en Cloudflare, que elegimos porque es uno de los proveedores de DNS compatibles con cert-manager y admite ExternalDNS (en fase beta en el momento de redactar este documento). Recomendamos encarecidamente no utilizar el dominio en producción ni para ningún otro fin crítico.
- Acceso a la API de Cloudflare, incluido en el plan gratuito.
- Helm para instalar y desplegar Kubernetes.
kubectlcomo interfaz de línea de comandos para Kubernetes.- Opcionalmente, K9s, una interfaz de usuario de terminal (TUI) bien diseñada que permite interactuar con Kubernetes de una forma más estructurada.
También suponemos que tiene conocimientos básicos de Kubernetes (cómo aplicar un manifiesto, usar un chart de Helm y ejecutar comandos kubectl para consultar la salida y solucionar problemas). Resulta útil conocer los conceptos básicos de Let’s Encrypt, aunque no es imprescindible; para obtener una visión general, consulte nuestro blog. Tampoco necesita saber cómo funciona cert-manager, pero, si le interesa saber cómo funciona junto con los certificados en general con NGINX Ingress Controller, consulte mi publicación reciente, Automatización de la gestión de certificados en un entorno de Kubernetes.
Hemos probado la solución tanto en macOS como en Linux. No la hemos probado en Subsistema de Windows para Linux versión 2 (WSL2), pero no prevemos ningún problema.
Nota: La solución está concebida como una prueba de concepto de ejemplo y no para su uso en producción. En particular, no incorpora todas las prácticas recomendadas de funcionamiento y seguridad. Para obtener información sobre estos temas, consulte la documentación de cert-manager y ExternalDNS.
Implementación de la solución
Siga los pasos de estas secciones para implementar la solución:
- Descargar software
- Implementar NGINX Ingress Controller
- Desplegar cert-manager
- Desplegar ExternalDNS
- Desplegar la aplicación de ejemplo
- Validar la solución
Descargar software
- Descarga tu token de API de Cloudflare.
- Clona el repositorio de NGINX Ingress Controller:
$ git clone https://github.com/nginxinc/kubernetes-ingress.gitCloning into 'kubernetes-ingress'...
remote: Enumerating objects: 45176, done.
remote: Counting objects: 100% (373/373), done.
remote: Compressing objects: 100% (274/274), done.
remote: Total 45176 (delta 173), reused 219 (delta 79), pack-reused 44803
Receiving objects: 100% (45176/45176), 60.45 MiB | 26.81 MiB/s, done.
Resolving deltas: 100% (26592/26592), done.- Comprueba que puedes conectarte al clúster de Kubernetes.
$ kubectl cluster-infoKubernetes control plane is running at https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443
KubeDNS is running at https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.Desplegar el controlador de Ingress NGINX
- Con Helm, despliega NGINX Ingress Controller. Ten en cuenta que vamos a añadir tres opciones de configuración no estándar:
$ helm install nginx-kic nginx-stable/nginx-ingress --namespace nginx-ingress --set controller.enableCustomResources=true --create-namespace --set controller.enableCertManager=true --set controller.enableExternalDNS=trueNAME: nginx-kic
LAST DEPLOYED: Day Mon DD hh:mm:ss YYYY
NAMESPACE: nginx-ingress
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The NGINX Ingress Controller has been installed.controller.enableCustomResources– Indica a Helm que instale las definiciones de recursos personalizados (CRD) utilizadas para crear los recursos personalizados VirtualServer y VirtualServerRoute de NGINX.controller.enableCertManager– Configura NGINX Ingress Controller para que se comunique con los componentes de cert-manager.controller.enableExternalDNS– Configura el controlador de Ingress para que se comunique con los componentes de ExternalDNS.
- Compruebe que NGINX Ingress Controller esté en ejecución y anote el valor del campo
EXTERNAL-IP; es la dirección IP de NGINX Ingress Controller (en este caso,www.xxx.yyy.zzz). Para facilitar la lectura, la salida se muestra en dos líneas.
$ kubectl get services --namespace nginx-ingressNAME TYPE CLUSTER-IP ...
nginx-kic-nginx-ingress LoadBalancer 10.128.152.88 ...
... EXTERNAL-IP PORT(S) AGE
... www.xxx.yyy.zzz 80:32457/TCP,443:31971/TCP 3h8mDesplegar cert-manager
En la solución, cert-manager utiliza el tipo de desafío DNS-01 al obtener un certificado TLS, lo que requiere proporcionar el token de la API de Cloudflare durante la creación del recurso ClusterIssuer. En la solución, el token de la API se proporciona como un Secret de Kubernetes.
- Con Helm, despliega cert-manager:
$ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.9.1 --set installCRDs=trueNAME: cert-manager
LAST DEPLOYED: Day Mon DD hh:mm:ss YYYY
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager v1.9.1 has been deployed successfully!- Despliega el token de la API de Cloudflare como un secreto de Kubernetes, sustituyéndolo por
<your-API-token>:
$ kubectl apply -f - <<EOFapiVersion: v1 kind: Secret metadata: name: Cloudflare-api-token-secret namespace: cert-manager type: Opaque stringData: api-token: "<your-API-token>" EOF
secret/Cloudflare-api-token-secret created- Cree un objeto ClusterIssuer y especifique
Cloudflare-api-token-secret(definido en el paso anterior) como la ubicación de la que se recuperará el token. Si lo desea, puede sustituirexample-issueren el campometadata.name(yexample-issuer-account-keyen el campospec.acme.privateKeySecretRef.name) por otro nombre.
$ kubectl apply -f - <<EOFapiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: example-issuer namespace: cert-manager spec: acme: email: example@example.com server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: example-issuer-account-key solvers: - dns01: Cloudflare: apiTokenSecretRef: name: Cloudflare-api-token-secret key: api-token EOF
clusterissuer.cert-manager.io/example-issuer created- Compruebe que ClusterIssuer esté desplegado y listo (el valor del campo
READYesTrue).
$ kubectl get clusterissuerNAME READY AGE
example-issuer True 3h9mDesplegar ExternalDNS
Al igual que cert-manager, el proyecto ExternalDNS requiere un token de API de Cloudflare para gestionar el DNS. Se puede utilizar el mismo token para ambos proyectos, aunque no es obligatorio.
- Cree los CRD de ExternalDNS para NGINX Ingress Controller a fin de habilitar la integración entre ambos proyectos.
$ kubectl create -f ./kubernetes-ingress/deployments/common/crds/externaldns.nginx.org_dnsendpoints.yamlcustomresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.nginx.org created- Crea el servicio de DNS externo (
external-dns). Como el manifiesto es bastante largo, lo dividiremos en dos partes. La primera parte configura las cuentas, los roles y los permisos:
$ kubectl apply -f - <<EOFapiVersion: v1 kind: ServiceAccount metadata: name: external-dns --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns rules: - apiGroups: [""] resources: ["services","endpoints","pods"] verbs: ["get","watch","list"] - apiGroups: ["extensions","networking.k8s.io"] resources: ["ingresses"] verbs: ["get","watch","list"] - apiGroups: ["externaldns.nginx.org"] resources: ["dnsendpoints"] verbs: ["get","watch","list"] - apiGroups: ["externaldns.nginx.org"] resources: ["dnsendpoints/status"] verbs: ["update"] - apiGroups: [""] resources: ["nodes"] verbs: ["list","watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: external-dns subjects: - kind: ServiceAccount name: external-dns namespace: default EOF
serviceaccount/external-dns created
clusterrole.rbac.authorization.k8s.io/external-dns created
clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created- La segunda parte del manifiesto crea el despliegue de ExternalDNS:
$ kubectl apply -f - <<EOF --- apiVersion: apps/v1 kind: Deployment metadata: name: external-dns spec: strategy: type: Recreate selector: matchLabels: app: external-dns template: metadata: labels: app: external-dns spec: serviceAccountName: external-dns containers: - name: external-dns image: k8s.gcr.io/external-dns/external-dns:v0.12.0 args: - --source=service - --source=ingress - --source=crd - --crd-source-apiversion=externaldns.nginx.org/v1 - --crd-source-kind=DNSEndpoint - --domain-filter=example.com - --provider=Cloudflare env: - name: CF_API_TOKEN value: "<your-API-token>" - name: FREE_TIER value: "true" EOF
serviceaccount/external-dns created
clusterrole.rbac.authorization.k8s.io/external-dns created
clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created
deployment.apps/external-dns created- Crea un objeto ServiceAccount llamado «
external-dns» para gestionar todas las operaciones de escritura y actualización relacionadas con la administración del DNS. - Crea un objeto ClusterRole (también llamado
external-dns) que define los permisos necesarios. - Vincula el ClusterRole con la ServiceAccount.
- Crea un filtro de dominios que limita el alcance de los posibles daños causados por ExternalDNS al gestionar dominios. Por ejemplo, puede especificar los nombres de dominio de los entornos de preproducción para evitar cambios en los entornos de producción. En este ejemplo, establecemos
domain-filterenexample.com. - Establece la variable de entorno
CF_API_TOKENen tu token de API de Cloudflare. En lugar de<your-API-token>, introduce el token real o un Secret que contenga el token. En este último caso, también debes proyectar el Secret en el contenedor mediante una variable de entorno. - Establece la variable de entorno
FREE_TIERen"true"(opción adecuada, salvo que tenga una suscripción de pago a Cloudflare).
Desplegar la aplicación de ejemplo
Utilice la aplicación de ejemplo estándar de NGINX Ingress Controller llamada «Cafe» para realizar pruebas.
- Despliega la aplicación Cafe.
$ kubectl apply -f ./kubernetes-ingress/examples/ingress-resources/complete-example/cafe.yamldeployment.apps/coffee created
service/coffee-svc created
deployment.apps/tea created
service/tea-svc created- Implemente NGINX Ingress Controller para la aplicación Cafe. Tenga en cuenta la siguiente configuración: el tiempo que tarda en completarse este paso depende en gran medida del proveedor de DNS, ya que Kubernetes interactúa con la API de DNS del proveedor.
$ kubectl apply -f - <<EOFapiVersion: k8s.nginx.org/v1 kind: VirtualServer metadata: name: cafe spec: host: cafe.example.com tls: secret: cafe-secret cert-manager: cluster-issuer: example-issuer externalDNS: enable: true upstreams: - name: tea service: tea-svc port: 80 - name: coffee service: coffee-svc port: 80 routes: - path: /tea action: pass: tea - path: /coffee action: pass: coffee EOF
virtualserver.k8s.nginx.org/cafe createdkind: VirtualServer– Estamos utilizando el recurso personalizado VirtualServer de NGINX, no el recurso Ingress estándar de Kubernetes.spec.host– Sustituyacafe.example.compor el nombre del host que va a desplegar. El host debe pertenecer al dominio gestionado con ExternalDNS.spec.tls.cert-manager.cluster-issuer– Si ha estado utilizando los valores especificados en esta publicación, este esexample-issuer. Si es necesario, sustitúyalo por el nombre que eligió en el paso 3 de Implementar cert‑manager.spec.externalDNS.enable– El valortrueindica a ExternalDNS que cree un registroAde DNS.
Validar la solución
- Verifique el registro DNS
A; en particular, compruebe que en el bloqueANSWERSECTIONel FQDN (en este caso,cafe.example.com) esté asociado a la dirección IP correcta (www.xxx.yyy.zzz).
$ dig cafe.example.com
; <<>> DiG 9.10.6 <<>> cafe.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22633
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;cafe.example.com. IN A
;; ANSWER SECTION:
cafe.example.com. 279 IN A www.xxx.yyy.zzz
;; Query time: 1 msec
;; SERVER: 2607:fb91:119b:4ac4:2e0:xxxx:fe1e:1359#53(2607:fb91:119b:4ac4:2e0:xxxx:fe1e:1359)
;; WHEN: Day Mon DD hh:mm:ss TZ YYYY
;; MSG SIZE rcvd: 67- Comprueba que el certificado sea válido (el valor del campo
READYesTrue).
$ kubectl get certificatesNAME READY SECRET AGE
cafe-secret True cafe-secret 8m51s- Comprueba que puedes acceder a la aplicación.
$ curl https://cafe.example.com/coffeeServer address: 10.2.2.4:8080
Server name: coffee-7c86d7d67c-lsfs6
Date: DD/Mon/YYYY:hh:mm:ss +TZ-offset
URI: /coffee
Request ID: 91077575f19e6e735a91b9d06e9684cd
$ curl https://cafe.example.com/tea
Server address: 10.2.2.5:8080
Server name: tea-5c457db9-ztpns
Date: DD/Mon/YYYY:hh:mm:ss +TZ-offset
URI: /tea
Request ID: 2164c245a495d22c11e900aa0103b00fQué sucede cuando un desarrollador implementa NGINX Ingress Controller
Una vez implementada la solución, ocurren muchas cosas entre bastidores. El diagrama muestra lo que sucede cuando un desarrollador implementa NGINX Ingress Controller con un recurso personalizado NGINX VirtualServer. Tenga en cuenta que se han omitido algunos detalles operativos.

- El desarrollador despliega un recurso VirtualServer mediante la CRD de NGINX
- Kubernetes crea el VirtualServer mediante NGINX Ingress Controller
- NGINX Ingress Controller llama a ExternalDNS para crear un registro DNS
Arecord - ExternalDNS crea el registro
Aen el DNS - NGINX Ingress Controller llama a cert-manager para solicitar un certificado TLS
- cert-manager añade un registro DNS para utilizarlo durante el desafío DNS-01
- cert-manager se pone en contacto con Let’s Encrypt para completar el desafío
- Let’s Encrypt valida el desafío mediante DNS
- Let’s Encrypt emite el certificado TLS
- cert-manager proporciona el certificado TLS al controlador de entrada NGINX
- NGINX Ingress Controller enruta las solicitudes externas protegidas mediante TLS a los pods de la aplicación
Solución de problemas
Dada la complejidad de Kubernetes y de los componentes que utilizamos, resulta difícil ofrecer una guía exhaustiva para la resolución de problemas. No obstante, hay algunas recomendaciones básicas que pueden ayudarle a identificar el problema.
- Utilice los comandos
kubectlgetykubectldescribepara validar la configuración de los objetos desplegados. - Utilice el comando
kubectllogs<component>para ver los archivos de registro de los distintos componentes desplegados. - Utilice K9s para inspeccionar la instalación; el software resalta los problemas en amarillo o rojo (según su gravedad) y proporciona una interfaz para acceder a los registros y a los detalles de los objetos.
Si sigues teniendo problemas, búscanos en NGINXCommunity Slack y pide ayuda. Contamos con una comunidad muy activa y siempre estaremos encantados de ayudarte a resolver cualquier problema.
Para probar NGINX Ingress Controller basado en NGINX Plus, comience hoy mismo su prueba gratuita de 30 días o póngase en contacto con nosotros para hablar sobre sus casos 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.