Kubernetes-Hosting

Kubernetes ist eine beliebte Wahl zum Hosten von Orleans-Anwendungen. Orleans kann in Kubernetes ohne spezifische Konfiguration ausgeführt werden, kann jedoch auch von zusätzlichem Wissen profitieren, das die Hostingplattform bereitstellt.

Das Paket Microsoft.Orleans.Hosting.Kubernetes fügt die Integration zum Hosten einer Orleans-Anwendung in einem Kubernetes-Cluster hinzu. Das Paket stellt die Erweiterungsmethode UseKubernetesHosting bereit, die die folgenden Aktionen ausführt:

  • SiloOptions.SiloName wird auf den Podnamen festgelegt.
  • EndpointOptions.AdvertisedIPAddress wird auf die IP-Adresse des Pods festgelegt.
  • EndpointOptions.SiloListeningEndpoint und EndpointOptions.GatewayListeningEndpoint sind so konfiguriert, dass alle Adressen mit den konfigurierten SiloPort und GatewayPort überwacht werden. Die Standardportwerte 11111 und 30000 werden verwendet, wenn keine Werte explizit festgelegt werden.
  • ClusterOptions.ServiceId wird auf den Wert der Podbezeichnung mit dem Namen orleans/serviceId festgelegt.
  • ClusterOptions.ClusterId wird auf den Wert der Podbezeichnung mit dem Namen orleans/clusterId festgelegt.
  • Zu Beginn des Startvorgangs wird Kubernetes vom Silo untersucht, um zu ermitteln, welche Silos nicht über entsprechende Pods verfügen, und diese Silos als inaktiv zu markieren.
  • Derselbe Prozess wird zur Laufzeit für eine Teilmenge aller Silos ausgeführt, um die Last auf dem API-Server von Kubernetes zu entfernen. Standardmäßig überwachen zwei Silos im Cluster Kubernetes.

Beachten Sie, dass das Kubernetes-Hostingpaket nicht Kubernetes für das Clustering verwendet. Für das Clustering ist weiterhin ein separater Clusteringanbieter erforderlich. Weitere Informationen zum Konfigurieren des Clusterings finden Sie in der Dokumentation zur Serverkonfiguration.

Diese Funktionalität stellt einige Anforderungen an die Bereitstellung des Diensts:

  • Silonamen müssen mit Podnamen übereinstimmen.
  • Pods müssen Bezeichnungen für orleans/serviceId und orleans/clusterId aufweisen, die ServiceId und ClusterId des Silos entsprechen. Die oben genannte Methode verteilt diese Bezeichnungen in die entsprechenden Optionen in Orleans aus Umgebungsvariablen.
  • Für Pods müssen die folgenden Umgebungsvariablen festgelegt sein: POD_NAME, POD_NAMESPACE, POD_IP, ORLEANS_SERVICE_ID, ORLEANS_CLUSTER_ID.

Das folgende Beispiel zeigt, wie diese Bezeichnungen und Umgebungsvariablen richtig konfiguriert werden:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dictionary-app
  labels:
    orleans/serviceId: dictionary-app
spec:
  selector:
    matchLabels:
      orleans/serviceId: dictionary-app
  replicas: 3
  template:
    metadata:
      labels:
        # This label is used to identify the service to Orleans
        orleans/serviceId: dictionary-app

        # This label is used to identify an instance of a cluster to Orleans.
        # Typically, this will be the same value as the previous label, or any
        # fixed value.
        # In cases where you are not using rolling deployments (for example,
        # blue/green deployments),
        # this value can allow for distinct clusters which do not communicate
        # directly with each others,
        # but which still share the same storage and other resources.
        orleans/clusterId: dictionary-app
    spec:
      containers:
        - name: main
          image: my-registry.azurecr.io/my-image
          imagePullPolicy: Always
          ports:
          # Define the ports which Orleans uses
          - containerPort: 11111
          - containerPort: 30000
          env:
          # The Azure Storage connection string for clustering is injected as an
          # environment variable
          # It must be created separately using a command such as:
          # > kubectl create secret generic az-storage-acct `
          #     --from-file=key=./az-storage-acct.txt
          - name: STORAGE_CONNECTION_STRING
            valueFrom:
              secretKeyRef:
                name: az-storage-acct
                key: key
          # Configure settings to let Orleans know which cluster it belongs to
          # and which pod it is running in
          - name: ORLEANS_SERVICE_ID
            valueFrom:
              fieldRef:
                fieldPath: metadata.labels['orleans/serviceId']
          - name: ORLEANS_CLUSTER_ID
            valueFrom:
              fieldRef:
                fieldPath: metadata.labels['orleans/clusterId']
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
          - name: DOTNET_SHUTDOWNTIMEOUTSECONDS
            value: "120"
          request:
            # Set resource requests
      terminationGracePeriodSeconds: 180
      imagePullSecrets:
        - name: my-image-pull-secret
  minReadySeconds: 60
  strategy:
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1

Für RBAC-fähige Cluster muss dem Kubernetes-Dienstkonto für die Pods möglicherweise auch der erforderliche Zugriff gewährt werden:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: orleans-hosting
rules:
- apiGroups: [ "" ]
  resources: ["pods"]
  verbs: ["get", "watch", "list", "delete"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: orleans-hosting-binding
subjects:
- kind: ServiceAccount
  name: default
  apiGroup: ''
roleRef:
  kind: Role
  name: orleans-hosting
  apiGroup: ''

Live-, Bereitschafts- und Starttests

Kubernetes kann Pods testen, um die Integrität eines Diensts zu ermitteln. Weitere Informationen finden Sie unter Configure Liveness, Readiness and Startup Probes (Konfigurieren von Live-, Bereitschafts- und Starttests) in der Kubernetes-Dokumentation.

Orleans verwendet ein Clustermitgliedschaftsprotokoll, um einen Prozess- oder Netzwerkfehler umgehend zu erkennen und den ursprünglichen Zustand wiederherzustellen. Jeder Knoten überwacht eine Teilmenge anderer Knoten und sendet regelmäßige Tests. Wenn ein Knoten auf mehrere aufeinanderfolgende Tests von mehreren anderen Knoten nicht reagiert, wird er zwangsweise aus dem Cluster entfernt. Sobald ein fehlerhafter Knoten erfährt, dass er entfernt wurde, wird er sofort beendet. Kubernetes startet den beendeten Prozess neu, und dieser versucht erneut, dem Cluster beizutreten.

Kubernetes-Tests können helfen, zu ermitteln, ob ein Prozess in einem Pod ausgeführt wird oder sich in einem Zombiezustand befindet. Tests überprüfen die Konnektivität zwischen Pods oder die Reaktionsfähigkeit nicht und führen keine Funktionsüberprüfungen auf Anwendungsebene durch. Wenn ein Pod längere Zeit nicht auf einen Livetest reagiert, kann Kubernetes diesen Pod beenden und neu planen. Die Teste von Kubernetes und Orleans ergänzen sich somit.

Der empfohlene Ansatz besteht darin, Livetests in Kubernetes zu konfigurieren, die einfach lokal überprüfen, ob die Anwendung wie vorgesehen ausgeführt wird. Diese Tests dienen dazu, den Prozess zu beenden, wenn es zu einem vollständigen Einfrieren kommt, z. B. aufgrund eines Laufzeitfehlers oder eines anderen unwahrscheinlichen Ereignisses.

Ressourcenkontingente

Kubernetes implementiert in Verbindung mit dem Betriebssystem Ressourcenkontingente. Dadurch können CPU- und Arbeitsspeicherreservierungen oder -grenzwerte erzwungen werden. Für eine primäre Anwendung, die interaktive Last bereitstellt, wird empfohlen, keine restriktiven Grenzwerte zu implementieren, sofern dies nicht erforderlich ist. Es ist wichtig zu beachten, dass Anforderungen und Grenzwerte sich in ihrer Bedeutung und dem Ort, an dem sie implementiert werden, erheblich unterscheiden. Nehmen Sie sich vor dem Festlegen von Anforderungen oder Grenzwerten Zeit, sich ein ausführliches Verständnis der Implementierung und Durchsetzung dieser Anforderungen zu verschaffen. Beispielsweise wird der Arbeitsspeicher möglicherweise nicht einheitlich zwischen Kubernetes, dem Linux-Kernel und Ihrem Überwachungssystem gemessen. CPU-Kontingente werden möglicherweise nicht wie erwartet erzwungen.

Problembehandlung

Pods stürzen ab und geben die Beschwerde aus: KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined.

Vollständige Ausnahmemeldung:

Unhandled exception. k8s.Exceptions.KubeConfigException: unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined
at k8s.KubernetesClientConfiguration.InClusterConfig()
  • Vergewissern Sie sich, dass die Umgebungsvariablen KUBERNETES_SERVICE_HOST und KUBERNETES_SERVICE_PORT in Ihrem Pod festgelegt sind. Sie können dies überprüfen, indem Sie den Befehl kubectl exec -it <pod_name> /bin/bash -c env ausführen.
  • Stellen Sie sicher, dass automountServiceAccountToken für Ihre Kubernetes-Datei deployment.yaml auf true festgelegt ist. Weitere Informationen finden Sie unter Konfigurieren von Dienstkonten für Pods.