El objetivo final del desarrollo de aplicação es, por supuesto, exponer aplicaciones en Internet. Para un desarrollador, Kubernetes simplifica este proceso hasta cierto punto al proporcionar el controlador de Ingress como mecanismo para enrutar solicitudes a la aplicação. Pero no todo es tan autoservicio como probablemente quisieras: aún necesitas un registro en el Sistema de nombres de dominio (DNS) para asignar el nombre de dominio de la aplicación a la dirección IP del controlador de Ingress y un certificado TLS para proteger las conexiones usando HTTPS. En la mayoría de las organizaciones, usted no es propietario de DNS o TLS y, por lo tanto, debe coordinarse con el grupo operativo (o los grupos) que sí lo tienen.
Las cosas no son necesariamente más fáciles para los operadores. En la mayoría de las organizaciones, la necesidad de actualizar registros DNS es tan poco frecuente que los procedimientos (tanto las reglas comerciales como los pasos técnicos reales) tienden a ser escasos o inexistentes. Esto significa que cuando necesitas agregar un registro DNS primero debes buscar la documentación, preguntar a un colega o (en el peor de los casos) averiguarlo. También debe asegurarse de cumplir con todas las normas de seguridad corporativas y de que el ingreso esté etiquetado correctamente para los firewalls.
Afortunadamente, existe una manera de hacer la vida más fácil tanto a los desarrolladores como a los operadores. En esta publicación, mostramos cómo los operadores pueden configurar una implementación de Kubernetes para permitir el autoservicio para que los desarrolladores actualicen registros DNS y generen certificados TLS en un entorno de Kubernetes. Al desarrollar la infraestructura con anticipación, puede asegurarse de que se cumplan todos los requisitos comerciales y técnicos necesarios.
Con la solución implementada, todo lo que un desarrollador necesita hacer para exponer una aplicação a Internet es crear un controlador de Ingress siguiendo una plantilla proporcionada que incluye un nombre de dominio completo (FQDN) dentro de un dominio administrado por la instalación de Kubernetes. Kubernetes usa la plantilla para asignar una dirección IP para el controlador de Ingress, crear el registro DNS A
para asignar el FQDN a la dirección IP y generar certificados TLS para el FQDN y agregarlos al controlador de Ingress. La limpieza es igual de sencilla: cuando se elimina el Ingress, se limpian los registros DNS.
La solución aprovecha las siguientes tecnologías (proporcionamos instrucciones de instalación y configuración a continuación):
Antes de configurar la solución, necesita:
LoadBalancer
). La solución utiliza Linode, pero también funcionan otros proveedores de nube.kubectl
como interfaz de línea de comandos para Kubernetes.También asumimos que tienes un conocimiento básico de Kubernetes (cómo aplicar un manifiesto, usar un gráfico de Helm y emitir comandos kubectl
para ver la salida y solucionar problemas). Comprender los conceptos básicos de Let's Encrypt es útil, pero no obligatorio; para obtener una descripción general, consulte nuestro blog . Tampoco es necesario que sepas cómo funciona cert-manager , pero si te interesa saber cómo funciona (y los certificados en general) con NGINX Ingress Controller, consulta mi publicación reciente, Automatizar la gestión de certificados en un entorno de Kubernetes .
Hemos probado la solución tanto en macOS como en Linux. No hemos realizado pruebas en el Subsistema de Windows para Linux versión 2 (WSL2), pero no prevemos ningún problema.
Nota: La solución está pensada como una muestra de prueba de concepto y no para su uso en producción. En particular, no incorpora todas las mejores prácticas de operación y seguridad. Para obtener información sobre estos temas, consulte la documentación de cert-manager y ExternalDNS .
Siga los pasos de estas secciones para implementar la solución:
Clonar el repositorio del controlador de ingreso NGINX:
$ git clone https://github.com/nginxinc/kubernetes-ingress.git Clonando en 'kubernetes-ingress'... remoto: Enumeración de objetos: 45176, listo. remoto: Contando objetos: 100% (373/373), hecho. remoto: Comprimiendo objetos: 100% (274/274), hecho. remoto: Total 45176 (delta 173), reutilizados 219 (delta 79), paquete reutilizado 44803 Objetos recibidos: 100% (45176/45176), 60,45 MiB | 26,81 MiB/s, listo.
Resolviendo deltas: 100% (26592/26592), listo.
Verifique que pueda conectarse al clúster de Kubernetes.
$ kubectl cluster-info El plano de control de Kubernetes se está ejecutando en https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443 KubeDNS se está ejecutando en https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy Para depurar y diagnosticar mejor los problemas del clúster, utilice 'kubectl cluster-info dump'.
Usando Helm, implemente el controlador de ingreso NGINX. Tenga en cuenta que estamos agregando tres opciones de configuración no estándar :
controller.enableCustomResources
: indica a Helm que instale las definiciones de recursos personalizadas (CRD) utilizadas para crear los recursos personalizados NGINX VirtualServer y VirtualServerRoute .controller.enableCertManager
: configura el controlador de ingreso NGINX para comunicarse con los componentes del administrador de certificados .controller.enableExternalDNS
: configura el controlador de ingreso para comunicarse con componentes ExternalDNS.NOMBRE: nginx-kic ÚLTIMA IMPLEMENTACIÓN: Día Lun DD hh : mm : ss AAAA ESPACIO DE NOMBRES: nginx-ingress ESTADO: implementado REVISIÓN: 1 CONJUNTO DE PRUEBAS: Ninguna NOTAS:
Se ha instalado el controlador de ingreso NGINX.
Verifique que el controlador de ingreso NGINX se esté ejecutando y anote el valor en el campo IP EXTERNA
: es la dirección IP del controlador de ingreso NGINX (aquí, www.xxx.yyy.zzz
). La salida se distribuye en dos líneas para facilitar la legibilidad.
$ kubectl get services --namespace nginx-ingress NOMBRE TIPO IP DEL CLÚSTER ... nginx-kic-nginx-ingress Balanceador de carga 10.128.152.88 ... ... PUERTO(S) IP EXTERNO(S) EDAD ... www.xxx.yyy.zzz 80:32457/TCP,443:31971/TCP 3h8m
En la solución, cert-manager utiliza el tipo de desafío DNS-01 al obtener un certificado TLS, lo que requiere que se proporcione el token de API de Cloudflare durante la creación del recurso ClusterIssuer . En la solución, el token de API se proporciona como un secreto de Kubernetes.
Usando Helm, implemente cert-manager :
$ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.9.1 --set installCRDs=true NOMBRE: cert-manager ÚLTIMA IMPLEMENTACIÓN: Día Lun DD hh : mm : ss AAAA ESPACIO DE NOMBRES: cert-manager ESTADO: implementado REVISIÓN: 1 CONJUNTO DE PRUEBAS: Ninguna NOTAS: ¡cert-manager v1.9.1 se ha implementado correctamente!
Implemente el token de API de Cloudflare como un secreto de Kubernetes, sustituyéndolo por <su-token-API>
:
$ kubectl apply -f - <<EOFapiVersion: v1
tipo: Metadatos secretos: nombre: Espacio de nombres de Cloudflare-api-token-secret: tipo de administrador de certificados: Opaco
stringData:
api-token: "<su-token-API>"
Final de carrera
Se creó el secreto/token de API de Cloudflare secreto
Cree un objeto ClusterIssuer, especificando Cloudflare-api-token-secret
(definido en el paso anterior) como el lugar para recuperar el token. Si lo desea, puede reemplazar example-issuer
en el campo metadata.name
(y example-issuer-account-key
en el campo spec.acme.privateKeySecretRef.name
) con un nombre diferente.
$ kubectl apply -f - <<EOFapiVersion: cert-manager.io/v1
tipo: Metadatos de ClusterIssuer: nombre: example-issuer espacio de nombres: cert-manager especificación: acme: correo electrónico: example@example.com servidor: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: nombre: example-issuer-account-key solucionadores: - dns01:
Cloudflare: apiTokenSecretRef: nombre: Clave secreta del token de API de Cloudflare: api-token EOF clusterissuer.cert-manager.io/example-issuer creado
Verifique que ClusterIssuer esté implementado y listo (el valor en el campo READY
es True
).
$ kubectl get clusterissuer NOMBRE LISTO EDAD ejemplo-emisor Verdadero 3h9m
Al igual que cert-manager, el proyecto ExternalDNS requiere un token de API de Cloudflare para administrar DNS. Se puede usar el mismo token para ambos proyectos, pero no es obligatorio.
Cree los CRD de ExternalDNS para el controlador de ingreso NGINX para permitir la integración entre los proyectos.
$ kubectl create -f ./kubernetes-ingress/deployments/common/crds/externaldns.nginx.org_dnsendpoints.yaml customresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.nginx.org creado
Cree el servicio DNS externo ( external-dns
). Como el manifiesto es bastante largo, aquí lo dividiremos en dos partes. La primera parte configura cuentas, roles y permisos:
external-dns
para administrar todas las operaciones de escritura y actualización para administrar DNS.external-dns
) que define los permisos necesarios.$ kubectl apply -f - <<EOFapiVersion: v1
tipo: Metadatos de ServiceAccount: nombre: external-dns --- apiVersion: rbac.authorization.k8s.io/v1 tipo: Metadatos de ClusterRole: nombre: external-dns reglas: - apiGroups: [""] recursos: ["servicios","puntos finales","pods"] verbos: ["obtener","vigilar","listar"] - apiGroups: ["extensiones","networking.k8s.io"] recursos: ["ingresos"] verbos: ["obtener","vigilar","listar"] - apiGroups: ["externaldns.nginx.org"] recursos: ["dnsendpoints"] verbos: ["obtener","vigilar","listar"] - apiGroups: ["externaldns.nginx.org"] recursos: ["dnsendpoints/estado"] verbos: ["actualizar"] - apiGroups: [""] recursos: ["nodos"] verbos: ["listar","vigilar"] --- apiVersion: rbac.authorization.k8s.io/v1 tipo: Metadatos de ClusterRoleBinding: nombre: external-dns-viewer roleRef: apiGroup: rbac.authorization.k8s.io tipo: Nombre de ClusterRole: dns externos sujetos: - tipo: Nombre de cuenta de servicio: external-dns espacio de nombres: predeterminado EOF serviceaccount/external-dns creado clusterrole.rbac.authorization.k8s.io/external-dns creado clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer creado
La segunda parte del manifiesto crea la implementación de ExternalDNS:
domain-filter
en example.com
.CF_API_TOKEN
en su token de API de Cloudflare. Para <su-token-API>
, sustituya el token real o un secreto que contenga el token. En el último caso, también es necesario proyectar el secreto en el contenedor mediante una variable de entorno.FREE_TIER
en "verdadero"
(apropiado a menos que tenga una suscripción paga de Cloudflare).$ kubectl apply -f - <<EOF
---
apiVersion: apps/v1
kind: Metadatos de implementación: nombre: dns externo especificación: estrategia: tipo: Recrear selector: matchLabels: app: external-dns plantilla: metadatos: etiquetas: app: external-dns especificación: serviceAccountName: external-dns contenedores: - nombre: external-dns imagen: k8s.gcr.io/external-dns/external-dns:v0.12.0 argumentos: - --source=servicio - --source=ingress - --source=crd - --crd-source-apiversion=externaldns.nginx.org/v1 - --crd-source-kind=DNSEndpoint - --domain-filter=example.com - --provider=Cloudflare env: - nombre: CF_API_TOKEN
valor: "<su-token-API>"
- nombre: Valor FREE_TIER: "verdadero" EOF serviceaccount/external-dns creado clusterrole.rbac.authorization.k8s.io/external-dns creado clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer creadoployment.apps/external-dns creado
Utilice la aplicação de muestra estándar NGINX Ingress Controller llamada Cafe para fines de prueba.
Implementar la aplicação Cafe.
$ kubectl apply -f ./kubernetes-ingress/examples/ingress-resources/complete-example/cafe.yaml implementación.apps/coffee creado servicio/coffee-svc creado implementación.apps/tea creado servicio/tea-svc creado
Implementar el controlador de ingreso NGINX para la aplicação Cafe. Tenga en cuenta la siguiente configuración:
amable: VirtualServer
: utilizamos el recurso personalizado NGINX VirtualServer, no el recurso estándar Kubernetes Ingress.spec.host
– Reemplace cafe.example.com
con el nombre del host que está implementando. El host debe estar dentro del dominio que se administra con ExternalDNS.spec.tls.cert-manager.cluster-issuer
– Si ha estado utilizando los valores especificados en esta publicación, este es example-issuer
. Si es necesario, sustituya el nombre que eligió en el Paso 3 de Implementar cert-manager .spec.externalDNS.enable
– El valor true
le indica a ExternalDNS que cree un registro DNS A.
Tenga en cuenta que 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
tipo: Metadatos del servidor virtual: nombre: cafe especificación: host: cafe.example.com tls: secreto: cafe-secreto administrador de certificados: cluster-issuer: example-issuer externalDNS: habilitar: verdadero upstreams: - nombre: tea servicio: tea-svc puerto: 80 - nombre: servicio de café: puerto de servicio de café: 80 rutas: - ruta: /tea acción: contraseña: té - ruta: /café acción: contraseña: café EOF virtualserver.k8s.nginx.org/cafe creado
Verifique el registro A
del DNS, en particular que en el bloque SECCIÓN DE
RESPUESTA
el FQDN (aquí, cafe.example.com
) esté asignado a la dirección IP correcta ( www.xxx.yyy.zzz
).
$ dig cafe.example.com ; <<>> DiG 9.10.6 <<>> cafe.example.com ;; opciones globales: +cmd ;; Obtuve la respuesta: ;; ->>HEADER<<- código de operación: CONSULTA, estado: NO ERROR, id: 22633 ;; banderas: qr rd ra; CONSULTA: 1, RESPUESTA: 1. AUTORIDAD: 0, ADICIONAL: 1;; OPTAR PSEUDOSECCIÓN: ; EDNS: versión: 0, banderas:; udp: 4096 ;; SECCIÓN DE PREGUNTAS: ;cafe.example.com. EN UNA SECCIÓN DE RESPUESTAS ;;: cafe.example.com. 279 EN A www.xxx.yyy.zzz ;; Hora de consulta: 1 mseg ;; SERVIDOR: 2607:fb91:119b:4ac4:2e0: xxxx :fe1e:1359#53(2607:fb91:119b:4ac4:2e0: xxxx :fe1e:1359) ;; CUANDO: Día Lun DD hh : mm : ss TZ AAAA ;; TAMAÑO DEL MENSAJE recibido: 67
Compruebe que el certificado sea válido (el valor en el campo READY
es True
).
$ kubectl obtener certificados NOMBRE LISTO SECRETO EDAD cafe-secret True cafe-secret 8m51s
Verifique que pueda acceder a la aplicação.
$ curl https://cafe.example.com/coffee Dirección del servidor: 10.2.2.4:8080 Nombre del servidor: coffee-7c86d7d67c-lsfs6 Fecha: DD/Lun/AAAA:hh:mm:ss +TZ-offset URI: /coffee ID de solicitud: 91077575f19e6e735a91b9d06e9684cd $ curl https://cafe.example.com/tea Dirección del servidor: 10.2.2.5:8080 Nombre del servidor: tea-5c457db9-ztpns Fecha: DD/Lun/AAAA:hh:mm:ss +TZ-offset URI: /tea ID de solicitud: 2164c245a495d22c11e900aa0103b00f
Una vez que se implementa la solución, ocurren muchas cosas bajo tierra. El diagrama muestra lo que sucede cuando un desarrollador implementa el controlador de ingreso NGINX con un recurso personalizado NGINX VirtualServer. Téngase en cuenta que se omiten algunos detalles operativos.
A
A
en DNSDada la complejidad de Kubernetes junto con los componentes que utilizamos, es difícil proporcionar una guía completa de solución de problemas. Dicho esto, hay algunas sugerencias básicas para ayudarle a determinar el problema.
kubectl
get
y kubectl
describe
para validar la configuración de los objetos implementados.kubectl
registros
<componente>
Comando para ver los archivos de registro de los distintos componentes implementados.Si aún tienes problemas, encuéntranos en el Slack de la comunidad NGINX y solicita ayuda. Tenemos una comunidad vibrante y siempre estamos felices de resolver los problemas.
Para probar el controlador de ingreso NGINX basado en NGINX Plus, comience hoy su prueba gratuita de 30 días o contáctenos para analizar sus casos 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.