Hosting Kubernetes

Kubernetes è una scelta comune per l'hosting di applicazioni Orleans. Orleans verrà eseguito in Kubernetes senza una configurazione specifica, ma può anche sfruttare informazioni aggiuntive che la piattaforma di hosting può fornire.

Il pacchetto Microsoft.Orleans.Hosting.Kubernetes aggiunge l'integrazione per l'hosting di un'applicazione Orleans in un cluster Kubernetes. Il pacchetto fornisce un metodo di estensione, UseKubernetesHosting, che esegue le azioni seguenti:

  • SiloOptions.SiloName è impostato sul nome del pod.
  • EndpointOptions.AdvertisedIPAddress è impostato sull'indirizzo IP del pod.
  • EndpointOptions.SiloListeningEndpoint e EndpointOptions.GatewayListeningEndpoint sono configurati per l'ascolto su qualsiasi indirizzo, con i valori configurati SiloPort e GatewayPort. Vengono usati i valori di porta predefiniti di 11111 e 30000 se non vengono impostati dei valori in modo esplicito.
  • ClusterOptions.ServiceId è impostato sul valore dell'etichetta del pod con il nome orleans/serviceId.
  • ClusterOptions.ClusterId è impostato sul valore dell'etichetta del pod con il nome orleans/clusterId.
  • All'inizio del processo di avvio, il silo eseguirà il probe di Kubernetes per individuare quali silo non hanno pod corrispondenti e contrassegnare tali silo come morti.
  • Lo stesso processo verrà eseguito in fase di esecuzione per un subset di tutti i silo, per rimuovere il carico nel server API di Kubernetes. Per impostazione predefinita, 2 silo nel cluster osserveranno Kubernetes.

Si noti che il pacchetto di hosting Kubernetes non usa Kubernetes per il clustering. Per il clustering, è ancora necessario un provider di clustering separato. Per altre informazioni sulla configurazione del clustering, vedere la documentazione sulla configurazione del server.

Questa funzionalità impone alcuni requisiti sulla modalità di distribuzione del servizio:

  • I nomi silo devono corrispondere ai nomi dei pod.
  • I pod devono avere un'etichetta orleans/serviceId e orleans/clusterId che corrisponde a ServiceId e ClusterId del silo. Il metodo indicato in precedenza propaga tali etichette nelle opzioni corrispondenti in Orleans dalle variabili di ambiente.
  • I pod devono avere le variabili di ambiente seguenti impostate: POD_NAME, POD_NAMESPACE, POD_IP, ORLEANS_SERVICE_ID, ORLEANS_CLUSTER_ID.

L'esempio seguente illustra come configurare correttamente queste etichette e variabili di ambiente:

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

Per i cluster abilitati per il controllo degli accessi in base al ruolo, potrebbe essere necessario concedere anche all'account del servizio Kubernetes per i pod l'accesso necessario:

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: ''

Probe di attività, idoneità e avvio

Kubernetes può eseguire il probe dei pod per determinare l'integrità di un servizio. Per altre informazioni, vedere Configurare probe di attività, idoneità e avvio nella documentazione di Kubernetes.

Orleans usa un protocollo di appartenenza al cluster per rilevare e ripristinare tempestivamente da un processo o da errori di rete. Ogni nodo monitora un subset di altri nodi, inviando probe periodici. Se un nodo non risponde a più probe successivi da più nodi, verrà rimosso forzatamente dal cluster. Una volta che un nodo non riuscito apprende che è stato rimosso, termina immediatamente. Kubernetes riavvierà il processo terminato e tenterà di rientrare nel cluster.

I probe di Kubernetes possono aiutare a determinare se un processo in un pod è in esecuzione e non è bloccato in uno stato zombie. i probe non verificano la connettività tra pod o la velocità di risposta o eseguono controlli delle funzionalità a livello di applicazione. Se un pod non risponde a un probe di attività, Kubernetes potrebbe terminare il pod e riprogrammarlo. I probe di Kubernetes e i probe di Orleans sono quindi complementari.

L'approccio consigliato consiste nel configurare i probe di liveness in Kubernetes che eseguono un semplice controllo locale che l'applicazione esegue come previsto. Questi probe servono per terminare il processo se è presente un blocco totale, ad esempio a causa di un errore di runtime o di un altro evento improbabile.

Quote di risorse

Kubernetes funziona insieme al sistema operativo per implementare quote di risorse. In questo modo è possibile applicare prenotazioni di CPU e memoria e/o limiti. Per un'applicazione primaria che gestisce il caricamento interattivo, è consigliabile non implementare limiti restrittivi, a meno che non sia necessario. È importante notare che le richieste e i limiti sono sostanzialmente diversi nel loro significato e rispetto a dove vengono implementati. Prima di impostare richieste o limiti, dedicare il tempo necessario per comprendere in dettaglio il modo in cui vengono implementate e applicate. Ad esempio, la memoria potrebbe non essere misurata in modo uniforme tra Kubernetes, il kernel Linux e il sistema di monitoraggio. Le quote della CPU potrebbero non essere applicate nel modo previsto.

Risoluzione dei problemi

Arresto anomalo dei pod, lamentando che KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined

Messaggio di eccezione completo:

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()
  • Verificare che le variabili di ambiente KUBERNETES_SERVICE_HOST e KUBERNETES_SERVICE_PORT siano impostate all'interno del pod. È possibile controllare eseguendo il comando kubectl exec -it <pod_name> /bin/bash -c env seguente.
  • Assicurarsi che automountServiceAccountToken sia impostato su true nel deployment.yaml Kubernetes. Per altre informazioni, vedere Configurare gli account del servizio per i pod