ExternalDNS mit STACKIT DNS verwenden
ExternalDNS ist ein Add-on für Kubernetes, das die Verwaltung von Domain-Name-System-Einträgen (DNS-Einträgen) für Kubernetes-Dienste durch die Nutzung verschiedener DNS-Anbieter automatisiert. Während Kubernetes DNS-Einträge traditionell intern verwaltet, erweitert ExternalDNS diese Funktionalität, indem es die Verantwortung für die Verwaltung der DNS-Einträge an einen externen DNS-Anbieter wie STACKIT überträgt. Folglich ermöglicht der STACKIT-Webhook die Verwaltung Ihrer STACKIT-Domains innerhalb Ihres Kubernetes-Clusters mithilfe von ExternalDNS.
Voraussetzungen
Abschnitt betitelt „Voraussetzungen“- Kompatibilität der Kubernetes-Cluster-Version: Um ExternalDNS bereitzustellen, stellen Sie sicher, dass Sie einen Kubernetes-Cluster mit den Versionen 1.24 bis 1.26 betreiben. Obwohl andere Versionen kompatibel sein könnten, wurden diese Versionen für optimale Leistung und Stabilität validiert.
- Cluster-Typ – SKE: Diese Anleitung enthält spezifische Anweisungen für das Deployment auf einem SKE-Cluster. Alternative Cluster-Konfigurationen können abweichende Implementierungsschritte erfordern.
- Erforderliche Zugangsdaten: Ein dediziertes Servicekonto und ein entsprechender Authentifizierungstoken sind für den Bereitstellungsprozess erforderlich. ExternalDNS wird programmgesteuert Einträge in der DNS-Zone erstellen und löschen, wofür das Servicekonto Berechtigungen auf Projektmitgliedsebene benötigt.
- Mechanismus zur Anwendungsbereitstellung: Diese Dokumentation setzt die Verwendung eines SKE-Clusters voraus. Daher können die Methoden zur Bereitstellung von Anwendungen über LoadBalancer- oder NodePort-Dienste je nach Ihrer Cluster-Konfiguration variieren.
Durch die Einhaltung dieser Voraussetzungen sind Sie besser auf die folgenden Schritte in diesem Tutorial vorbereitet.
Implementierung
Abschnitt betitelt „Implementierung“STACKIT-Authentifizierungstoken konfigurieren
Abschnitt betitelt „STACKIT-Authentifizierungstoken konfigurieren“Beginnen Sie mit dem Abrufen Ihres STACKIT-Authentifizierungstokens. Diesen finden Sie im Servicekonto innerhalb des Projekts, in dem Sie die DNS-Zone und die Einträge erstellen möchten. Hinweis: ExternalDNS wird automatisch Einträge aus Ihren Kubernetes-Ingresses oder -Diensten innerhalb dieser angegebenen Zone erstellen.
export AUTHENTICATION_TOKEN="ey..."Zone erstellen
Abschnitt betitelt „Zone erstellen“Erstellen Sie eine DNS-Zone. Dies kann entweder über unsere Benutzeroberfläche (UI) oder die REST-API erfolgen. In dieser Anleitung verwenden wir die STACKIT DNS API.
export PROJECTID="4ec710a8-fe7c-42d3-aca4-84d9ff69a14e"export DNS_ZONE="example.runs.onstackit.cloud"curl --location "https://dns.api.stackit.cloud/v1/projects/$PROJECTID/zones" \--header 'Content-Type: application/json' \--header "Authorization: Bearer $AUTHENTICATION_TOKEN" \--data '{ "name": "external-dns", "dnsName": "'"$DNS_ZONE"'"}'Sobald die Zone über die API erstellt wurde, erhalten Sie eine Antwort mit einer eindeutigen Kennung für die Zone, der sogenannten zone.id. Diese ID ist für zukünftige API-Aufrufe im Zusammenhang mit dieser Zone erforderlich.
export ZONEID="1035d922-7a90-4a20-ba89-308ed9eb0cff"Kubernetes-Secret einrichten
Abschnitt betitelt „Kubernetes-Secret einrichten“Erstellen Sie ein Kubernetes-Secret unter Verwendung des oben genannten Authentifizierungstokens. Dieses Secret unterstützt unseren Webhook bei der Authentifizierung an unserer API.
kubectl create ns external-dns && kubectl create secret generic external-dns-stackit-webhook --from-literal=auth-token=$AUTHENTICATION_TOKEN -n external-dnsExternalDNS mit Webhook bereitstellen
Abschnitt betitelt „ExternalDNS mit Webhook bereitstellen“Nachdem die Vorbereitungen abgeschlossen sind, können Sie ExternalDNS mit unserem Webhook bereitstellen:
kubectl apply -f - <<EOFapiVersion: v1kind: ServiceAccountmetadata: name: external-dns namespace: external-dns labels: app.kubernetes.io/name: external-dns app.kubernetes.io/instance: external-dnsimagePullSecrets: - name: docker-secret---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: external-dns labels: app.kubernetes.io/name: external-dns app.kubernetes.io/instance: external-dnsrules: - apiGroups: [""] resources: ["nodes"] verbs: ["list","watch"] - apiGroups: [""] resources: ["pods"] verbs: ["get","watch","list"] - apiGroups: [""] resources: ["services","endpoints"] verbs: ["get","watch","list"] - apiGroups: ["extensions","networking.k8s.io"] resources: ["ingresses"] verbs: ["get","watch","list"]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: external-dns-viewer labels: app.kubernetes.io/name: external-dns app.kubernetes.io/instance: external-dnsroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: external-dnssubjects: - kind: ServiceAccount name: external-dns namespace: external-dns---apiVersion: v1kind: Servicemetadata: name: external-dns namespace: external-dns labels: app.kubernetes.io/name: external-dns app.kubernetes.io/instance: external-dnsspec: type: ClusterIP selector: app.kubernetes.io/name: external-dns app.kubernetes.io/instance: external-dns ports: - name: http port: 7979 targetPort: http protocol: TCP---apiVersion: apps/v1kind: Deploymentmetadata: name: external-dns namespace: external-dns labels: app.kubernetes.io/name: external-dns app.kubernetes.io/instance: external-dnsspec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: external-dns app.kubernetes.io/instance: external-dns strategy: type: Recreate template: metadata: labels: app.kubernetes.io/name: external-dns app.kubernetes.io/instance: external-dns spec: serviceAccountName: external-dns securityContext: fsGroup: 65534 containers: - name: external-dns securityContext: capabilities: drop: - ALL readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 65534 image: registry.k8s.io/external-dns/external-dns:v0.14.0 imagePullPolicy: IfNotPresent args: - --log-level=info - --log-format=text - --interval=1m - --source=service - --source=ingress - --policy=sync # set it upsert-only if you don't want it to delete records - --txt-owner-id=my-testcluster # has to be uniq for each cluster if multiple external-dns managing one zone - --provider=webhook ports: - name: http protocol: TCP containerPort: 7979 livenessProbe: failureThreshold: 2 httpGet: path: /healthz port: http initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 readinessProbe: failureThreshold: 6 httpGet: path: /healthz port: http initialDelaySeconds: 5 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 - name: webhook securityContext: capabilities: drop: - ALL readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 65534 image: ghcr.io/stackitcloud/external-dns-stackit-webhook:v0.2.0 imagePullPolicy: IfNotPresent args: - --project-id=$PROJECTID - --domain-filter=$DNS_ZONE ports: - name: http protocol: TCP containerPort: 8888 livenessProbe: failureThreshold: 2 httpGet: path: /healthz port: http initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 readinessProbe: failureThreshold: 6 httpGet: path: /healthz port: http initialDelaySeconds: 5 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 env: - name: AUTH_TOKEN valueFrom: secretKeyRef: name: external-dns-stackit-webhook key: auth-tokenEOFBeachten Sie, dass das Setzen eines Domain-Filters nicht zwingend ist. Es kann jedoch von Vorteil sein, wenn Ihr Cluster über mehrere mit unterschiedlichen Zonen verknüpfte Datensätze verfügt.
Um zu überprüfen, ob ExternalDNS betriebsbereit ist, verwenden Sie den unten angegebenen Befehl:
kubectl get pods -n external-dnsSie erhalten die folgende Ausgabe:
NAME READY STATUS RESTARTS AGEexternal-dns-7fb65c6899-lqcsp 2/2 Running 0 18sEine Beispielanwendung bereitstellen
Abschnitt betitelt „Eine Beispielanwendung bereitstellen“Stellen Sie einen Reverse-Proxy bereit, wie zum Beispiel den Nginx Ingress Controller:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginxhelm repo updatekubectl create ns ingress-nginxhelm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginxStellen Sie als praktisches Beispiel eine Testanwendung auf Ihrem Kubernetes-Cluster bereit und machen Sie diese über eine Ingress-Ressource zugänglich. Dadurch veranschaulichen Sie die Fähigkeit von ExternalDNS, Einträge in der zuvor erstellten Zone zu generieren.
kubectl apply -f - <<EOFapiVersion: v1kind: Namespacemetadata: name: example-app---apiVersion: v1kind: ConfigMapmetadata: name: example-app namespace: example-appdata: index.html: | <!DOCTYPE html> <html> <head> <title>ExampleApp</title> </head> <body> <header> <h1 id="Hello World">Hello World</h1> </header> </body> </html>---apiVersion: apps/v1kind: Deploymentmetadata: name: example-app namespace: example-appspec: replicas: 1 selector: matchLabels: app: example-app template: metadata: labels: app: example-app spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: config-volume mountPath: /usr/share/nginx/html volumes: - name: config-volume configMap: name: example-app---apiVersion: v1kind: Servicemetadata: name: example-app namespace: example-appspec: selector: app: example-app ports: - protocol: TCP port: 80 targetPort: 80---apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: app-ingress namespace: example-app annotations: ingress.kubernetes.io/rewrite-target: / kubernetes.io/ingress.class: "nginx"spec: rules: - host: "app.example.runs.onstackit.cloud" http: paths: - path: / pathType: Prefix backend: service: name: example-app port: number: 80EOFUm die Funktionalität der Anwendung zu überprüfen:
kubectl get pods -n example-appSie erhalten die folgende Ausgabe:
NAME READY STATUS RESTARTS AGEexample-app-588974765d-r6shs 1/1 Running 0 23sLassen Sie einen kurzen Zeitraum verstreichen und bestätigen Sie dann, dass ExternalDNS die Einträge für unsere Beispielanwendung generiert hat:
curl --location --globoff "https://dns.api.stackit.cloud/v1/projects/$PROJECTID/zones/$ZONEID/rrsets" \--header "Authorization: Bearer $AUTHENTICATION_TOKEN" | \jq '.rrSets[] | {name, type, records}'{ "name": "a-app.example.runs.onstackit.cloud.", "type": "TXT", "records": [ { "content": "\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/example-app/app-ingress\"", "id": "a316420b-4c0b-4aad-b089-5af5a361f0f9" } ]}{ "name": "app.example.runs.onstackit.cloud.", "type": "TXT", "records": [ { "content": "\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/example-app/app-ingress\"", "id": "cacd591c-d62c-4a61-99e4-7a70ca642cf6" } ]}{ "name": "app.example.runs.onstackit.cloud.", "type": "A", "records": [ { "content": "45.129.45.243", "id": "06a9c311-1a13-4835-a694-589897db5008" } ]}{ "name": "example.runs.onstackit.cloud.", "type": "SOA", "records": [ { "content": "ns1.stackit.cloud hostmaster.stackit.cloud. 2023090500 3600 600 1209600 60", "id": "0268092d-63cd-45b2-ad39-364f026cb0a2" } ]}{ "name": "example.runs.onstackit.cloud.", "type": "NS", "records": [ { "content": "ns1.stackit.cloud.", "id": "49ea254f-c8c5-4db0-952a-ee9a47bd8f04" }, { "content": "ns2.stackit.cloud.", "id": "d8a5c03d-3048-49e1-a2ff-2534307be56e" } ]}Testen Sie den Zugriff auf Ihre Website mit curl:
curl http://app.example.runs.onstackit.cloud<!DOCTYPE html><html> <head> <title>ExampleApp</title> </head> <body> <header> <h1 id="Hello World">Hello World</h1> </header> </body></html>Wie Sie vielleicht bemerkt haben, ist das aktuelle Setup nicht abgesichert. Für eine erhöhte Sicherheit sollten Sie die Bereitstellung des Cert-Managers und dessen Integration mit STACKIT DNS in Betracht ziehen. Eine Anleitung zur Durchführung finden Sie unter STACKIT DNS für DNS01 verwenden, um als DNS01-ACME-Issuer mit Cert-Manager zu fungieren.