ExternalDNS mit STACKIT DNS verwenden
Zuletzt aktualisiert am
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“- 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.
- STACKIT CLI: Stellen Sie sicher, dass Sie die STACKIT CLI installiert und mit dem STACKIT Service Account authentifiziert ist.
- 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“Zone erstellen
Abschnitt betitelt „Zone erstellen“Erstellen Sie eine DNS-Zone. Dies kann entweder über unsere Benutzeroberfläche (UI) oder die REST-API erfolgen. Letzteres geschieht über die STACKIT CLI. In dieser Anleitung verwenden wir die STACKIT DNS API.
export PROJECTID="4ec710a8-fe7c-42d3-aca4-84d9ff69a14e"export DNS_ZONE="example.runs.onstackit.cloud"stackit curl --location "https://dns.api.stackit.cloud/v1/projects/$PROJECTID/zones" \--header 'Content-Type: application/json' \--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 Service Account-Keys. Dieser Key wird im Container gemountet und unterstützt unseren Webhook bei der Authentifizierung an unserer API.
kubectl create ns external-dns && \kubectl create secret generic external-dns-stackit-webhook \-n external-dns \--from-file=sa.json=/path/to/stackit-service-account-key.jsonExternalDNS 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 volumes: - name: stackit-sa-key secret: secretName: external-dns-stackit-webhook items: - key: sa.json path: sa.json 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_KEY_PATH value: /var/run/secrets/stackit/sa.json volumeMounts: - name: stackit-sa-key mountPath: /var/run/secrets/stackit readOnly: trueEOFBeachten 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:
bash kubectl get pods -n external-dns Sie erhalten die folgende Ausgabe: NAME READY STATUS RESTARTS AGE external-dns-7fb65c6899-lqcsp 2/2 Running 0 18s
Eine 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:
stackit curl --location --globoff "https://dns.api.stackit.cloud/v1/projects/$PROJECTID/zones/$ZONEID/rrsets" | \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.