Istio Service Mesh
Istio ist ein Service Mesh für Kubernetes. Diese Anleitung beschreibt die Installation in einem Gardener-Shoot-Cluster der noris Sovereign Cloud (nSC). Die konkrete Konfiguration, etwa für Traffic Management, mTLS, Tracing oder Canary Releases, obliegt Ihnen als Kundin oder Kunde.
Die Anleitung orientiert sich am Upstream-Tutorial Gardener yourself a Shoot with Istio, custom Domains, and Certificates.
Voraussetzungen
Abschnitt betitelt „Voraussetzungen“Netzwerkkonfiguration (Cilium)
Abschnitt betitelt „Netzwerkkonfiguration (Cilium)“Damit Istio mit dem Cilium-CNI zusammenarbeitet, sind zwei Anpassungen an der Netzwerkkonfiguration des Shoots erforderlich. Fügen Sie Folgendes zur Shoot-Deklaration hinzu:
apiVersion: core.gardener.cloud/v1beta1kind: Shoot...spec: networking: type: cilium providerConfig: apiVersion: cilium.networking.extensions.gardener.cloud/v1alpha1 kind: NetworkConfig bpfSocketLBHostnsOnly: enabled: false cni: exclusive: falseZertifikate und DNS
Abschnitt betitelt „Zertifikate und DNS“Für eingehenden Traffic kann Istio als Ingress-Gateway dienen. Alternativ lässt sich auch die Kubernetes Gateway API einsetzen, die Istio ebenfalls unterstützt. Beide Varianten profitieren von TLS-Zertifikaten und DNS-Einträgen, die Gardener über die Erweiterungen shoot-cert-service und shoot-dns-service verwaltet. Diese sind im Abschnitt Zertifikate der Gardener-Dokumentation beschrieben. Die Ausstellung über Let’s Encrypt macht die Nutzung komfortabel und wird empfohlen, sie ist jedoch nicht zwingend erforderlich. Richten Sie beide Erweiterungen gemäß jener Anleitung ein, bevor Sie mit der Istio-Installation fortfahren.
Der dort vergebene Issuer-Name (im Beispiel custom-issuer) wird im nächsten Schritt bei der Istio-Installation referenziert.
Istio installieren
Abschnitt betitelt „Istio installieren“Istio bietet zahlreiche Konfigurationsmöglichkeiten. Hier wird exemplarisch nur die Ingress-Gateway-Funktion konfiguriert. Weitere Optionen beschreibt die Istio-Dokumentation.
Installieren Sie istioctl gemäß der offiziellen Installationsanleitung.
Legen Sie anschließend die Umgebungsvariablen für Ihre Domain und den Issuer fest. Die Domain entspricht einer Subdomain Ihres Shoot-Clusters:
export domainname="istio-mesh.g5lxqfthcn.k8s.nsc02.noris.cloud"export issuer="custom-issuer"Installieren Sie Istio mit dem Default-Profil und annotieren Sie den Ingress-Gateway-Service, sodass Gardener DNS und Zertifikate übernimmt:
cat <<EOF | istioctl install -y -f -apiVersion: install.istio.io/v1alpha1kind: IstioOperatorspec: profile: default components: ingressGateways: - name: istio-ingressgateway enabled: true k8s: serviceAnnotations: cert.gardener.cloud/issuer: "${issuer}" cert.gardener.cloud/secretname: wildcard-tls dns.gardener.cloud/class: garden dns.gardener.cloud/dnsnames: "${domainname}" dns.gardener.cloud/ttl: "120"EOFInstallation überprüfen
Abschnitt betitelt „Installation überprüfen“Prüfen Sie, ob DNS-Einträge und Zertifikate erfolgreich erstellt wurden:
kubectl -n istio-system describe service istio-ingressgatewayIm Ereignisbereich sollten Meldungen wie certificate ready und dns entry active erscheinen. Die Ausstellung der Zertifikate über Let’s Encrypt dauert etwa 70 Sekunden, warten Sie diese Wartezeit ab, bevor Sie die Verifikation durchführen.
Verifizieren Sie den DNS-Eintrag:
dig ${domainname}Weitere Schritte wie das Freigeben einer Anwendung über Istio Gateway- und VirtualService-Ressourcen beschreibt das Upstream-Tutorial im Abschnitt Ingress at Your Service.
Bei Konfigurationsproblemen hilft istioctl analyze.
Istio entfernen
Abschnitt betitelt „Istio entfernen“Um Istio wieder zu entfernen:
istioctl uninstall --purgeImplementierungsbeispiel: mTLS
Abschnitt betitelt „Implementierungsbeispiel: mTLS“Das folgende Beispiel demonstriert mTLS zwischen Namespaces. Es legt drei Namespaces an: foo und bar mit Istio-Injection, legacy ohne Sidecar. In foo wird PeerAuthentication mit STRICT mTLS erzwungen.
Speichern Sie das Manifest als mtls-demo.yaml und wenden Sie es an:
kubectl apply -f mtls-demo.yaml---# Namespace: foo (mit Istio injection)apiVersion: v1kind: Namespacemetadata: name: foo labels: istio-injection: enabled---# Namespace: bar (mit Istio injection)apiVersion: v1kind: Namespacemetadata: name: bar labels: istio-injection: enabled---# Namespace: legacy (ohne Istio injection)apiVersion: v1kind: Namespacemetadata: name: legacy---# web in fooapiVersion: v1kind: ServiceAccountmetadata: name: web namespace: foo---apiVersion: v1kind: Servicemetadata: name: web namespace: foospec: ports: - port: 80 name: http selector: app: web---apiVersion: apps/v1kind: Deploymentmetadata: name: web namespace: foospec: replicas: 1 selector: matchLabels: app: web template: metadata: labels: app: web spec: serviceAccountName: web containers: - name: nginx image: nginx:alpine ports: - containerPort: 80---# sleep in fooapiVersion: v1kind: ServiceAccountmetadata: name: sleep namespace: foo---apiVersion: v1kind: Servicemetadata: name: sleep namespace: foospec: ports: - port: 80 name: http selector: app: sleep---apiVersion: apps/v1kind: Deploymentmetadata: name: sleep namespace: foospec: replicas: 1 selector: matchLabels: app: sleep template: metadata: labels: app: sleep spec: serviceAccountName: sleep containers: - name: sleep image: curlimages/curl:latest command: ["/bin/sleep", "infinity"]---# sleep in barapiVersion: v1kind: ServiceAccountmetadata: name: sleep namespace: bar---apiVersion: v1kind: Servicemetadata: name: sleep namespace: barspec: ports: - port: 80 name: http selector: app: sleep---apiVersion: apps/v1kind: Deploymentmetadata: name: sleep namespace: barspec: replicas: 1 selector: matchLabels: app: sleep template: metadata: labels: app: sleep spec: serviceAccountName: sleep containers: - name: sleep image: curlimages/curl:latest command: ["/bin/sleep", "infinity"]---# sleep in legacy (kein Sidecar)apiVersion: v1kind: ServiceAccountmetadata: name: sleep namespace: legacy---apiVersion: v1kind: Servicemetadata: name: sleep namespace: legacyspec: ports: - port: 80 name: http selector: app: sleep---apiVersion: apps/v1kind: Deploymentmetadata: name: sleep namespace: legacyspec: replicas: 1 selector: matchLabels: app: sleep template: metadata: labels: app: sleep spec: serviceAccountName: sleep containers: - name: sleep image: curlimages/curl:latest command: ["/bin/sleep", "infinity"]---# PeerAuthentication: STRICT mTLS im Namespace fooapiVersion: security.istio.io/v1beta1kind: PeerAuthenticationmetadata: name: default namespace: foospec: mtls: mode: STRICTTest 1: mTLS von bar nach foo, erwartet 200:
kubectl exec -n bar deploy/sleep -- curl -s -o /dev/null -w "%{http_code}" http://web.foo.svc.cluster.local/Test 2: Plaintext von legacy nach foo wird durch STRICT mTLS geblockt, erwartet 000:
kubectl exec -n legacy deploy/sleep -- curl -s -o /dev/null -w "%{http_code}" http://web.foo.svc.cluster.local/Test 3: Auf PERMISSIVE umstellen, dann geht Plaintext auch:
kubectl patch peerauthentication default -n foo --type=json -p='[{"op":"replace","path":"/spec/mtls/mode","value":"PERMISSIVE"}]'Der Curl-Befehl aus Test 2 müsste jetzt 200 statt 000 zurückgeben.
