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.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.
Vérifiez que vous pouvez vous connecter au cluster 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'.
À l’aide de Helm, déployez NGINX Ingress Controller. Notez que nous ajoutons trois options de configuration non standard :
controller.enableCustomResources
– Vous indique à Helm d’installer les définitions des ressources personnalisées (CRD) nécessaires à la création des 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.$ 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.
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-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 3h8m
Dans la solution, cert-manager utilise le type de défi DNS-01 pour obtenir un certificat TLS, ce qui vous oblige à fournir le jeton API Cloudflare lors de la création de la ressource ClusterIssuer. Dans la solution, vous fournissez le jeton API 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=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!
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
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
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
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
Vérifiez que le ClusterIssuer est déployé et prêt (la valeur dans le champ READY
est True
).
$ kubectl get clusterissuerNAME READY AGE
example-issuer True 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.yamlcustomresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.nginx.org created
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
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 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: 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
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.yamldeployment.apps/coffee created
service/coffee-svc created
deployment.apps/tea created
service/tea-svc created
Déployez NGINX Ingress Controller pour l'application Cafe. Notez les paramètres suivants :
type : VirtualServer
– Nous utilisons la ressource personnalisée NGINX VirtualServer, pas 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
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 created
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
;; 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
Vérifiez que le certificat est valide (la valeur dans le champ READY
est True
).
$ kubectl get certificatesNAME READY SECRET AGE
cafe-secret True cafe-secret 8m51s
Vérifiez que vous pouvez accéder à l'application.
$ 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: 2164c245a495d22c11e900aa0103b00f
Beaucoup de choses se passent en coulisses dès que vous déployez la solution. Le schéma illustre ce que vous voyez quand un développeur déploie le contrôleur d'entrée NGINX avec une ressource personnalisée NGINX VirtualServer. Certaines précisions opérationnelles sont volontairement écartées.
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."