L’objectif ultime du développement d’applications est, bien sûr, d’exposer des applications sur Internet. Pour un développeur, Kubernetes simplifie ce processus dans une certaine mesure en fournissant le contrôleur Ingress comme mécanisme de routage des requêtes vers l'application. Mais tout n’est pas aussi libre-service que vous le souhaiteriez probablement : vous avez toujours besoin d’un enregistrement dans le système de noms de domaine (DNS) pour mapper le nom de domaine de l’application à l’adresse IP du contrôleur d’entrée et d’un certificat TLS pour sécuriser les connexions à l’aide de HTTPS. Dans la plupart des organisations, vous ne possédez pas vous-même le DNS ou le TLS et devez donc vous coordonner avec le ou les groupes opérationnels qui le font.
Les choses ne sont pas forcément plus faciles pour les opérateurs. Dans la plupart des organisations, le besoin de mettre à jour les enregistrements DNS est suffisamment rare pour que les procédures (à la fois les règles métier et les étapes techniques réelles) aient tendance à être rares, voire inexistantes. Cela signifie que lorsque vous devez ajouter un enregistrement DNS, vous devez d'abord trouver la documentation, demander à un collègue ou (dans le pire des cas) le comprendre. Vous devez également vous assurer que vous respectez toutes les règles de sécurité de l’entreprise et que l’entrée est correctement étiquetée pour les pare-feu.
Heureusement, il existe un moyen de faciliter la vie des développeurs et des opérateurs. Dans cet article, nous montrons comment les opérateurs peuvent configurer un déploiement Kubernetes pour permettre aux développeurs de mettre à jour les enregistrements DNS et de générer des certificats TLS dans un environnement Kubernetes en libre-service. En construisant l’infrastructure à l’avance, vous pouvez garantir que toutes les exigences commerciales et techniques nécessaires sont satisfaites.
Une fois la solution en place, tout ce qu’un développeur doit faire pour exposer une application à Internet est de créer un contrôleur d’entrée en suivant un modèle fourni qui inclut un nom de domaine complet (FQDN) dans un domaine géré par l’installation Kubernetes. Kubernetes utilise le modèle pour allouer une adresse IP au contrôleur Ingress, créer l'enregistrement DNS A
pour mapper le FQDN à l'adresse IP, générer des certificats TLS pour le FQDN et les ajouter au contrôleur Ingress. Le nettoyage est tout aussi simple : lorsque l'entrée est supprimée, les enregistrements DNS sont nettoyés.
La solution s'appuie sur les technologies suivantes (nous fournissons des instructions d'installation et de configuration ci-dessous) :
Avant de configurer la solution, vous avez besoin de :
LoadBalancer
). La solution utilise Linode, mais d'autres fournisseurs de cloud fonctionnent également.kubectl
comme interface de ligne de commande pour Kubernetes.Nous supposons également que vous avez une compréhension de base de Kubernetes (comment appliquer un manifeste, utiliser un graphique Helm et émettre des commandes kubectl
pour afficher la sortie et résoudre les problèmes). Comprendre les concepts de base de Let's Encrypt est utile mais pas obligatoire ; pour un aperçu, consultez notre blog . Vous n'avez pas non plus besoin de savoir comment fonctionne cert-manager , mais si vous souhaitez savoir comment il (et les certificats en général) fonctionne avec NGINX Ingress Controller, consultez mon article récent, Automatisation de la gestion des certificats dans un environnement Kubernetes .
Nous avons testé la solution sur macOS et Linux. Nous n'avons pas testé sur le sous-système Windows pour Linux version 2 (WSL2), mais nous ne prévoyons aucun problème.
Note: La solution est destinée à servir d'exemple de preuve de concept et non à être utilisée en production. En particulier, il n’intègre pas toutes les meilleures pratiques en matière d’exploitation et de sécurité. Pour plus d'informations sur ces sujets, consultez la documentation cert-manager et ExternalDNS .
Suivez les étapes de ces sections pour déployer la solution :
Cloner le référentiel NGINX Ingress Controller :
$ git clone https://github.com/nginxinc/kubernetes-ingress.git Clonage dans « kubernetes-ingress »... à distance : Énumération des objets : 45176, terminé. à distance : Compter les objets : 100% (373/373), terminé. à distance : Compression d'objets : 100% (274/274), terminé. à distance : Total 45176 (delta 173), réutilisé 219 (delta 79), pack-réutilisé 44803 Objets reçus : 100 % (45176/45176), 60,45 Mio | 26,81 Mio/s, terminé.
Résolution des deltas : 100% (26592/26592), terminé.
Vérifiez que vous pouvez vous connecter au cluster Kubernetes.
Le plan de contrôle Kubernetes s'exécute à l'adresse https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443 KubeDNS s'exécute à l'adresse https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy Pour déboguer et diagnostiquer davantage les problèmes de cluster, utilisez « kubectl cluster-info dump ».
À l’aide de Helm, déployez NGINX Ingress Controller. Notez que nous ajoutons trois options de configuration non standard :
controller.enableCustomResources
– Demande à Helm d’installer les définitions de ressources personnalisées (CRD) utilisées pour créer les ressources personnalisées NGINX VirtualServer et VirtualServerRoute .controller.enableCertManager
– Configure NGINX Ingress Controller pour communiquer avec les composants cert-manager .controller.enableExternalDNS
– Configure le contrôleur d’entrée pour communiquer avec les composants ExternalDNS.NOM : nginx-kic DERNIÈRE DATE DE DÉPLOIEMENT : Jour Lun JJ hh : mm : ss AAAA ESPACE DE NOM : nginx-ingress STATUT : déployé RÉVISION : 1 SUITE DE TESTS : Aucun REMARQUES :
Le contrôleur d'entrée NGINX a été installé.
Vérifiez que NGINX Ingress Controller est en cours d'exécution et notez la valeur dans le champ EXTERNAL-IP
: il s'agit de l'adresse IP de NGINX Ingress Controller (ici, www.xxx.yyy.zzz
). La sortie est répartie sur deux lignes pour plus de lisibilité.
$ kubectl get services --namespace nginx-ingress NOM TYPE CLUSTER-IP ... nginx-kic-nginx-ingress LoadBalancer 10.128.152.88 ... ... ÂGE DES PORTS IP EXTERNES ... www.xxx.yyy.zzz 80:32457/TCP,443:31971/TCP 3h8m
Dans la solution, cert-manager utilise le type de défi DNS-01 lors de l'obtention d'un certificat TLS, ce qui nécessite que le jeton API Cloudflare soit fourni lors de la création de la ressource ClusterIssuer . Dans la solution, le jeton API est fourni sous forme de secret Kubernetes.
En utilisant Helm, déployez cert-manager :
$ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.9.1 --set installCRDs=true NOM : cert-manager DERNIÈRE UTILISATION : Jour Lun JJ hh : mm : ss AAAA ESPACE DE NOM : cert-manager STATUT : déployé RÉVISION : 1 SUITE DE TESTS : Aucune REMARQUE : cert-manager v1.9.1 a été déployé avec succès !
Déployez le jeton d'API Cloudflare en tant que secret Kubernetes, en le remplaçant par <votre-jeton-API>
:
$ kubectl apply -f - <<EOFapiVersion: v1
type: Métadonnées secrètes : nom : Espace de noms Cloudflare-api-token-secret : type de gestionnaire de certificats : Opaque
stringData :
api-token : "<votre-jeton-API>"
Énoncé des faits
secret/Cloudflare-api-token-secret créé
Créez un objet ClusterIssuer, en spécifiant Cloudflare-api-token-secret
(défini à l’étape précédente) comme emplacement pour récupérer le jeton. Si vous le souhaitez, vous pouvez remplacer example-issuer
dans le champ metadata.name
(et example-issuer-account-key
dans le champ spec.acme.privateKeySecretRef.name
) par un nom différent.
$ kubectl apply -f - <<EOFapiVersion: cert-manager.io/v1
type: Métadonnées ClusterIssuer : nom : example-issuer espace de noms : cert-manager spec : acme : e-mail : example@example.com serveur : https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef : nom : example-issuer-account-key solveurs : - dns01 :
Cloudflare : apiTokenSecretRef : nom : Clé secrète du jeton d'API Cloudflare : jeton d'API EOF clusterissuer.cert-manager.io/example-issuer créé
Vérifiez que le ClusterIssuer est déployé et prêt (la valeur dans le champ READY
est True
).
$ kubectl get clusterissuer NOM PRÊT ÂGE exemple-émetteur Vrai 3h9m
Comme cert-manager, le projet ExternalDNS nécessite un jeton API Cloudflare pour gérer le DNS. Le même jeton peut être utilisé pour les deux projets, mais cela n'est pas obligatoire.
Créez les CRD ExternalDNS pour NGINX Ingress Controller pour permettre l’intégration entre les projets.
$ kubectl create -f ./kubernetes-ingress/deployments/common/crds/externaldns.nginx.org_dnsendpoints.yaml customresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.nginx.org créé
Créez le service DNS externe ( external-dns
). Parce que le manifeste est assez long, nous le divisons ici en deux parties. La première partie configure les comptes, les rôles et les autorisations :
external-dns
pour gérer toutes les opérations d'écriture et de mise à jour pour la gestion du DNS.external-dns
) qui définit les autorisations requises.$ kubectl apply -f - <<EOFapiVersion: v1
type: Métadonnées du compte de service : nom : external-dns --- apiVersion : rbac.authorization.k8s.io/v1 type : ClusterRole métadonnées : nom : règles DNS externes : - apiGroups : [""] ressources : ["services","endpoints","pods"] verbes : ["get","watch","list"] - apiGroups : ["extensions","networking.k8s.io"] ressources : ["ingresses"] verbes : ["get","watch","list"] - apiGroups : ["externaldns.nginx.org"] ressources : ["dnsendpoints"] verbes : ["get","watch","list"] - apiGroups : ["externaldns.nginx.org"] ressources : ["dnsendpoints/status"] verbes : ["update"] - apiGroups : [""] ressources : ["nodes"] verbes : ["list","watch"] --- apiVersion : rbac.authorization.k8s.io/v1 kind : Métadonnées ClusterRoleBinding : nom : external-dns-viewer roleRef : apiGroup : rbac.authorization.k8s.io kind : Nom du rôle de cluster : externe-dns sujets : - type : Nom du compte de service : external-dns espace de noms : par défaut EOF serviceaccount/external-dns créé clusterrole.rbac.authorization.k8s.io/external-dns créé clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer créé
La deuxième partie du manifeste crée le déploiement ExternalDNS :
domain-filter
sur example.com
.CF_API_TOKEN
sur votre jeton API Cloudflare. Pour <votre-jeton-API>
, remplacez soit le jeton réel, soit un secret contenant le jeton. Dans ce dernier cas, vous devez également projeter le secret dans le conteneur à l’aide d’une variable d’environnement.FREE_TIER
sur « true »
(approprié sauf si vous disposez d'un abonnement Cloudflare payant).$ kubectl apply -f - <<EOF
---
apiVersion: apps/v1
kind: Métadonnées de déploiement : nom : spécification DNS externe : stratégie : type : Recréer le sélecteur : matchLabels : application : modèle DNS externe : métadonnées : étiquettes : application : spécification DNS externe : serviceAccountName : conteneurs DNS externe : - nom : image DNS externe : 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 : - nom : CF_API_TOKEN
valeur : "<votre-jeton-API>"
- nom: Valeur FREE_TIER : « true » EOF serviceaccount/external-dns créé clusterrole.rbac.authorization.k8s.io/external-dns créé clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer créé deployment.apps/external-dns créé
Utilisez l’exemple d’application standard NGINX Ingress Controller appelé Cafe à des fins de test.
Déployez l'application Café.
$ kubectl apply -f ./kubernetes-ingress/examples/ingress-resources/complete-example/cafe.yaml déploiement.apps/coffee créé service/coffee-svc créé déploiement.apps/tea créé service/tea-svc créé
Déployez NGINX Ingress Controller pour l'application Cafe. Notez les paramètres suivants :
gentil: VirtualServer
– Nous utilisons la ressource personnalisée NGINX VirtualServer, et non la ressource Kubernetes Ingress standard.spec.host
– Remplacez cafe.example.com
par le nom de l’hôte que vous déployez. L'hôte doit se trouver dans le domaine géré avec ExternalDNS.spec.tls.cert-manager.cluster-issuer
– Si vous avez utilisé les valeurs spécifiées dans cet article, il s'agit de example-issuer
. Si nécessaire, remplacez le nom que vous avez choisi à l’étape 3 de Déployer cert-manager .spec.externalDNS.enable
– La valeur true
indique à ExternalDNS de créer un enregistrement DNS A.
Notez que le temps nécessaire à cette étape dépend fortement du fournisseur DNS, car Kubernetes interagit avec l’API DNS du fournisseur.
$ kubectl apply -f - <<EOFapiVersion: k8s.nginx.org/v1
type: Métadonnées du serveur virtuel : nom : café spécifications : hôte : cafe.example.com tls : secret : cafe-secret cert-manager : cluster-issuer : example-issuer externalDNS : enable : true en amont : - nom : thé service : tea-svc port : 80 - nom : service de café : port de service de café : 80 routes : - chemin : /thé action : passe : thé - chemin : /café action : passe : café EOF virtualserver.k8s.nginx.org/cafe créé
Vérifiez l'enregistrement DNS A
, en particulier que dans le bloc SECTION
RÉPONSE,
le FQDN (ici, cafe.example.com
) est mappé à l'adresse IP correcte ( www.xxx.yyy.zzz
).
$ dig cafe.example.com ; <<>> DiG 9.10.6 <<>> cafe.example.com ;; options globales : +cmd ;; Réponse obtenue : ;; ->>HEADER<<- opcode : REQUÊTE, statut : PAS D'ERREUR, id: 22633 ;; drapeaux : qr rd ra ; REQUÊTE : 1, RÉPONSE : 1. AUTORITÉ : 0, SUPPLÉMENTAIRE : 1 ;; OPTER LA PSEUDOSECTION : ; EDNS : version : 0, drapeaux : ; udp : 4096 ;; SECTION QUESTION : ;cafe.example.com. DANS UNE SECTION RÉPONSE : cafe.example.com. 279 IN A www.xxx.yyy.zzz ;; Heure de la requête : 1 msec ;; SERVEUR : 2607:fb91:119b:4ac4:2e0: xxxx :fe1e:1359#53(2607:fb91:119b:4ac4:2e0: xxxx :fe1e:1359) ;; QUAND : Jour Lun JJ hh : mm : ss TZ AAAA ;; TAILLE MSG reçu : 67
Vérifiez que le certificat est valide (la valeur dans le champ READY
est True
).
$ kubectl get certificates NOM PRÊT SECRET ÂGE cafe-secret Vrai cafe-secret 8m51s
Vérifiez que vous pouvez accéder à l'application.
$ curl https://cafe.example.com/coffee Adresse du serveur : 10.2.2.4:8080 Nom du serveur : coffee-7c86d7d67c-lsfs6 Date : JJ/Lun/AAAA:hh:mm:ss +décalage TZ URI : /coffee ID de la requête : 91077575f19e6e735a91b9d06e9684cd $ curl https://cafe.example.com/tea Adresse du serveur : 10.2.2.5:8080 Nom du serveur : tea-5c457db9-ztpns Date : JJ/Lun/AAAA:hh:mm:ss +TZ-offset URI : /tea ID de la requête : 2164c245a495d22c11e900aa0103b00f
Beaucoup de choses se passent sous les couvertures une fois la solution en place. Le diagramme montre ce qui se passe lorsqu’un développeur déploie le contrôleur d’entrée NGINX avec une ressource personnalisée NGINX VirtualServer. Veuillez noter que certains détails opérationnels sont omis.
A
A
dans DNSCompte tenu de la complexité de Kubernetes ainsi que des composants que nous utilisons, il est difficile de fournir un guide de dépannage complet. Cela dit, il existe quelques suggestions de base pour vous aider à déterminer le problème.
kubectl
get
et kubectl
describe
pour valider la configuration des objets déployés.kubectl
journaux
<composant>
commande permettant d'afficher les fichiers journaux des différents composants déployés.Si vous rencontrez toujours des problèmes, retrouvez-nous sur le Slack de la communauté NGINX et demandez de l'aide ! Nous avons une communauté dynamique et sommes toujours heureux de résoudre les problèmes.
Pour essayer le contrôleur d'entrée NGINX basé sur NGINX Plus, démarrez votre essai gratuit de 30 jours dès aujourd'hui ou contactez-nous pour discuter de vos cas d'utilisation .
« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."