Pasar una instalación existente a Traefik
Las instalaciones nuevas sirven su host con Traefik y la Gateway API de Kubernetes. Las versiones anteriores
usaban ingress-nginx, que el proyecto Kubernetes ha retirado. Esta página es para una instalación que ya ejecuta
ingress-nginx: el paso se da por etapas y el host sigue respondiendo todo el tiempo. Un clúster sin ingress-nginx
no necesita nada de esto; dcctl install le instala solo Traefik.
Qué hace cada comando en un clúster que todavía tiene ingress-nginx:
dcctl installdejaingress-nginxsirviendo e instala Traefik y las definiciones de la Gateway API a su lado. Traefik recibe un balanceador de carga propio, y por tanto una dirección propia.dcctl upgradeda a cada instancia un Gateway y HTTPRoutes, y mantiene sus objetos Ingress a su lado mientrasingress-nginxsiga en el clúster. Ambos sirven el host.- El DNS lo mueves tú, cuando estés listo.
dcctl upgrade --drop-legacy-ingressdeja de generar los objetos Ingress de la instancia.dcctl install --remove-legacy-ingressquitaingress-nginx, y solo cuando ningún objeto Ingress nombra su clase.
Antes de empezar
- Conoce qué cambia en el borde. Consulta Qué cambia en el borde.
- Si la instancia obtiene su certificado de un emisor ACME (
ingress.tls.selfSigned: falsey unClusterIssuer), lee Certificados de un emisor ACME: necesita un cambio una vez movido el DNS, no antes. - Pasa a
dcctl installlos ajustes con los que se instaló el clúster, como--ha, además de la nueva--version, igual que en cualquier actualización progresiva.
Los pasos
-
Instala el controlador nuevo. Esto deja
ingress-nginxsirviendo.dcctl install <provider> --version <new-version> -
Actualiza cada instancia. Con
--dry-runprimero se imprime qué front end tendrá la instancia.dcctl upgrade <provider> <instance> --version <new-version> --dry-rundcctl upgrade <provider> <instance> --version <new-version>La instancia tiene ahora un Gateway llamado
devicechainen su namespace (dci-<instance>), con un listenerhttpy otrohttps, y HTTPRoutes detrás. Sus objetos Ingress siguen ahí. Los dos tienen certificados distintos: los objetos Ingress conservandevicechain-tls, que es a lo que el DNS sigue llegando, de modo que el host en producción nunca espera un certificado nuevo; el Gateway usadevicechain-tls-gateway. El Gateway conserva ese nombre para siempre, incluso cuando los objetos Ingress ya no existan.Después la actualización comprueba el certificado del Gateway. Consulta La compuerta del certificado.
-
Busca la dirección de Traefik y comprueba la instancia a través de ella, antes de mover el DNS.
kubectl -n traefik get service traefikkubectl -n dci-<instance> get gateway devicechaincurl --resolve <host>:443:<traefik-address> https://<host>/El
EXTERNAL-IPdel Service (o el nombre de host, en AWS) es la dirección de Traefik. El Gateway debe informarProgrammed.--resolvehace quecurlenvíe la solicitud a Traefik usando aun así tu nombre de host, de modo que el certificado y las rutas son los que vería un navegador. Añade-k(o--cacertcon la CA de la instancia, véase TLS, flags e instalación en un portátil) cuando la instancia es autofirmada. -
Mueve el DNS. Apunta el host a la dirección de Traefik. No hace falta nada más, y nada tiene que ser rápido: los objetos Ingress siguen respondiendo mientras haya clientes que resuelvan la dirección antigua.
-
Comprueba el certificado del Gateway. En una instancia que termina TLS con su propia CA (la configuración autofirmada por defecto), confirma que el certificado del Gateway lo emitió la CA de la instancia antes de quitar los objetos Ingress. Una instancia actualizada a través del cambio de emisor puede quedar con un certificado del Gateway emitido por el emisor autofirmado anterior: tiene el sujeto vacío y no es una hoja firmada por una CA, así que un cliente basado en OpenSSL no tiene nada con lo que anclarlo, aunque un navegador que acepta excepciones no muestra la diferencia.
Las versiones desde la v0.26.1 firman con un nombre de emisor nuevo, así que un certificado emitido por una actualización ya no puede salir así, y
dcctl upgrade --drop-legacy-ingresslee el propio certificado y se niega, nombrando el Secret, cuando es autofirmado o no lo firmó su propioca.crt. Lo que sigue es la alternativa: para una instancia cuyo certificado emitió una versión anterior, y para cuando esa negativa nombra el Secret. El cambio de nombre también hace que cert-manager emita una vez más cada certificado de host de la instancia, desde la misma CA; cada Secret sigue sirviendo su certificado actual hasta que el nuevo esté listo, así que no hay corte.kubectl -n dci-<instance> get secret devicechain-tls-gateway -o jsonpath='{.data.tls\.crt}' \| base64 -d | openssl x509 -noout -subject -issuerEl sujeto no debe estar vacío y el emisor debe ser la CA de la instancia,
CN=<instance> DeviceChain CA. Si no lo es, pide a cert-manager que lo emita de nuevo desde la CA de la instancia y vuelve a comprobar:cmctl renew -n dci-<instance> devicechain-tls-gateway# sin cmctl: borra el Secret y cert-manager lo vuelve a crearkubectl -n dci-<instance> delete secret devicechain-tls-gatewayUna instancia cuyo certificado procede de un
ClusterIssuerACME u otro no tiene nada que hacer aquí. -
Quita los objetos Ingress. Cuando el tráfico se haya movido, deja de generarlos:
dcctl upgrade <provider> <instance> --drop-legacy-ingressHazlo para todas las instancias del clúster.
-
Quita
ingress-nginx.dcctl install <provider> --remove-legacy-ingressPasa los mismos ajustes que en el paso 1. Quitar el controlador no quita los objetos Ingress, y uno que se quedara atrás dejaría de responder sin que se informara de ningún fallo, así que el comando se niega mientras exista alguno:
ingress-nginx is still serving 1 Ingress object(s), and removing the controller leaves them in place withnothing to serve them, so every host they carry stops answering:dci-beta/devicechain-apiMove each instance to the Gateway first: point DNS at the new controller, then run`dcctl upgrade <provider> <instance> --drop-legacy-ingress` for it. Nothing has been changedLa lista nombra todos los Ingress servidos por la clase de
ingress-nginx, en cualquier namespace, incluidos los que hayas creado tú. Muévelos o elimínalos también. El Ingress que creó la instalación para Grafana no cuenta: pasa a Traefik en la misma aplicación.
En un clúster local
Un clúster local (kind) publica los puertos 80 y 443 de un nodo, y solo un controlador puede ocuparlos. Mientras los dos controladores estén instalados, ingress-nginx conserva los puertos y Traefik solo es accesible en un NodePort.
En un clúster local no hay DNS que mover: el navegador llega al controlador que ocupe los puertos del nodo. Los pasos 3 y 4 (la dirección externa y el DNS) no se aplican, y un dcctl upgrade normal ya lleva a la ventana a una instancia que tiene objetos Ingress. Ejecuta los pasos 6 y 7 seguidos: el host no responde desde --drop-legacy-ingress hasta que la eliminación haya entregado los puertos a Traefik, y espera un corte breve mientras ocurre.
Un clúster local nuevo no tiene ingress-nginx, y Traefik ocupa los puertos desde el principio. En un clúster local que tiene ambos, una instancia nueva la sirve ingress-nginx hasta la eliminación.
Varias instancias
El paso del clúster es compartido y cada instancia se mueve a su propio ritmo. ingress-nginx se queda hasta que la
última instancia haya ejecutado --drop-legacy-ingress. Si las instancias de un clúster usan hosts distintos, hay que
mover el DNS de cada uno.
La compuerta del certificado
Un Gateway sin certificado responde https con el certificado por defecto del controlador, así que el paso comprueba el certificado del Gateway en cuatro momentos. Las comprobaciones se aplican cuando la instancia termina TLS y el clúster tiene cert-manager; --no-tls las omite. Un Gateway cuyo Secret aportas tú (no lleva anotación de emisor de cert-manager ni kubernetes.io/tls-acme: "true") no tiene nada que esperar y las supera.
- Durante la ventana,
dcctl upgradeespera 30 segundos al certificado y después avisa y continúa. Los objetos Ingress siguen sirviendo el host, y muchos emisores solo pueden emitir el certificado del Gateway cuando el DNS apunta a Traefik. dcctl upgrade --drop-legacy-ingressse niega, antes de generar o cambiar nada, salvo que el Certificate de cert-manager del Gateway estéReadyy lo controle el Gateway. También se niega cuando la instancia aún no tiene Gateway. Mueve antes el DNS para que se pueda emitir el certificado, compruebakubectl -n dci-<instance> get certificatey ejecuta de nuevo el comando.dcctl install --remove-legacy-ingresscomprueba el Gateway de cada instancia del clúster y nombra las que no tienen el certificadoReady. Quitaringress-nginxno cambia cómo se sirven esas instancias; la comprobación evita que un certificado roto del Gateway pase inadvertido hasta que nada más sirva el host.- Una actualización que deja una instancia solo en el Gateway espera hasta cinco minutos y falla indicando el motivo. Los servicios ya están en marcha cuando falla.
Un rechazo termina con "Nothing has been changed". Arregla lo que nombra y ejecuta de nuevo el mismo comando. Las causas habituales:
- Existe un Certificate para el Secret, pero el Gateway no lo controla. cert-manager no adopta un Certificate que no creó para el Gateway, así que uno sobrante de un Ingress, o hecho a mano, con el mismo nombre de Secret deja al Gateway sin ninguno. El mensaje imprime el comando que lo elimina (
kubectl -n dci-<instance> delete certificate <name>); entonces se crea el del propio Gateway. - No se crea ningún Certificate. El soporte de Gateway API de cert-manager no está activado, o cert-manager arrancó antes de que existieran las definiciones de la Gateway API.
kubectl -n cert-manager logs deploy/cert-managerlo indica. Undcctl installde esta versión lo activa. - El Certificate no está
Ready. El mensaje incluye el texto del propio emisor. Con un emisor ACME, véase más abajo.
Certificados de un emisor ACME
Un emisor HTTP-01 que resuelve a través de la clase de ingress nginx sigue funcionando durante la ventana, también para el certificado del Gateway: el desafío lo sirve ingress-nginx, adonde el DNS sigue apuntando. Déjalo como está hasta que el DNS se haya movido. Después, antes de --drop-legacy-ingress y --remove-legacy-ingress, dale un solver gatewayHTTPRoute, o sus renovaciones fallarán cuando ingress-nginx ya no esté. Un solver gatewayHTTPRoute fijado antes de mover el DNS falla, porque el desafío llega a ingress-nginx, que no tiene ruta para él. Un solver DNS-01 funciona en todo momento.
El solver gatewayHTTPRoute nombra el listener http del Gateway de la instancia, devicechain:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
# server, email and privateKeySecretRef as before
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: devicechain
sectionName: http
El parentRef no lleva namespace, y uno solo cubre todas las instancias: cert-manager crea la ruta del solver en el namespace del Certificate que se está emitiendo, así que se asocia al Gateway devicechain de esa instancia. La redirección de http a https del chart es una coincidencia menos específica que la ruta del desafío, así que no lo intercepta.
Volver atrás
Mientras ingress-nginx siga en el clúster, una instancia puede volver a él:
dcctl upgrade <provider> <instance> --ingress-controller nginx
La elección queda registrada en la instancia y la conservan todas las actualizaciones posteriores, porque una
actualización vuelve a derivar todo lo que genera, y un retroceso que una actualización normal deshiciera no sería tal.
--ingress-controller gateway registra la otra elección. --ingress-controller auto borra el registro, y la instancia
se vuelve a decidir según el clúster: el Gateway donde se ejecuta Traefik.
nginxnecesitaingress-nginxen el clúster, ygatewaynecesita Traefik. Cada uno se rechaza, sin cambiar nada, cuando falta el controlador que nombra.--ingress-controller nginxy--drop-legacy-ingressjuntos se rechazan: uno hace de los objetos Ingress el único front end y el otro deja de generarlos.- Si el DNS ya apunta a Traefik, vuelve a apuntarlo a la dirección de
ingress-nginx: el retroceso elimina el Gateway. - Una vez quitado
ingress-nginxya no hay vuelta atrás a él, y una instalación no devuelve un controlador quitado.
Qué cambia en el borde
El Gateway sirve los mismos hosts, rutas y backends que servían los objetos Ingress. Lo que cambia es quién configura el borde:
- Las anotaciones dejan de aplicarse.
ingress.className,ingress.annotationseingress.uploadMaxBodySizeen una superposición de valores pertenecen a los objetos Ingress. En una instancia servida solo por el Gateway, un valor que escribas para ellos en una ejecución se rechaza, y uno que la instancia ya había registrado se omite del render con un aviso y se conserva en el registro, de modo que vuelve a aplicarse con--ingress-controller nginx. - Las cargas no tienen tope ni búfer. Traefik transmite el cuerpo de la solicitud en flujo, y el servicio de
actualizaciones aplica su propio límite. El tiempo de lectura de Traefik acota la solicitud completa, cuerpo
incluido, así que se deriva del artefacto más grande que acepta el clúster: la variable de OpenTofu
traefik_max_artifact_bytes, 512 MiB por defecto, da una ventana de 2.228 segundos. Súbela antes de subir elupdates.maxArtifactBytesde una instancia. Esa misma ventana es el tiempo que un cliente que envía las cabeceras muy despacio puede mantener una conexión, frente a los 60 segundos de antes. - Las cadenas de consulta de las descargas quedan fuera del registro de accesos, que está desactivado por defecto.
La capacidad de descarga viaja en
?cap=. - Las rutas distinguen mayúsculas y terminan en un límite de segmento.
/API/<area>y/api/<area>Xcaen en la consola en lugar de llegar al área. - Direcciones de cliente. Traefik escribe el par real en
X-Forwarded-Fory su Service usaexternalTrafficPolicy: Local; consulta Direcciones de cliente y proxies de confianza. En AWS un Classic Load Balancer oculta la dirección del cliente.dcctl install --aws-nlb traefikda al Service de Traefik un Network Load Balancer, y es el valor que conviene durante la ventana porqueingress-nginxsigue sirviendo con su propio balanceador. Cambiar un Service sustituye su balanceador y cambia su nombre de host, así que repunta el DNS después. - Los despliegues drenan. Detrás de un balanceador de carga en la nube (
externalTrafficPolicy: Local) el balanceador sigue enviando a un nodo hasta que su comprobación de estado lo descarta, así que un pod del controlador que se iba de inmediato perdía solicitudes mientras el balanceador se enteraba. Ahora ambos controladores siguen atendiendo durante 40 segundos después de recibir la orden de parar, y un pod nuevo debe estar listo 15 segundos antes de retirar uno antiguo, de modo que un despliegue o un pod que cambia de nodo no pierde nada. Por eso un despliegue tarda aproximadamente un minuto más por réplica. La espera solo se aplica detrás de un balanceador de carga: en un clúster local, donde el controlador usa los puertos del nodo o un NodePort, no hay nada que esperar y los despliegues son tan rápidos como antes. Las variables de OpenTofudrain_secondsymin_ready_secondsde cada módulo de controlador lo ajustan;0lo desactiva.
Relacionado
dcctl installydcctl upgradelistan todos los flags usados aquí.- Versiones y actualizaciones contiene las notas de la versión que incluye este cambio.