Hospedaje de Kubernetes

Kubernetes es una opción popular para hospedar aplicaciones de Orleans. Orleans se ejecutará en Kubernetes sin una configuración específica. Sin embargo, también puede aprovechar los conocimientos adicionales que puede proporcionar la plataforma de hospedaje.

El paquete Microsoft.Orleans.Hosting.Kubernetes agrega integración para hospedar una aplicación de Orleans en un clúster de Kubernetes. El paquete proporciona un método de extensión, UseKubernetesHosting, que realiza las siguientes acciones:

  • SiloOptions.SiloName se establece en el nombre del pod.
  • EndpointOptions.AdvertisedIPAddress se establece en la IP del pod.
  • EndpointOptions.SiloListeningEndpoint y EndpointOptions.GatewayListeningEndpoint están configurados para escuchar en cualquier dirección, con SiloPort y GatewayPort configurados. Los valores de puerto predeterminados de 11111 y 30000 se usan si no se establecen valores explícitamente.
  • ClusterOptions.ServiceId se establece en el valor de la etiqueta de pod con el nombre orleans/serviceId.
  • ClusterOptions.ClusterId se establece en el valor de la etiqueta de pod con el nombre orleans/clusterId.
  • Al principio del proceso de inicio, el silo sondeará Kubernetes para encontrar qué silos no tienen pods correspondientes y marcar esos silos como inactivos.
  • El mismo proceso se producirá en tiempo de ejecución para un subconjunto de todos los silos y así quitar la carga en el servidor de la API de Kubernetes. De manera predeterminada, 2 silos del clúster vigilarán Kubernetes.

Tenga en cuenta que el paquete de hospedaje de Kubernetes no usa Kubernetes para la agrupación en clústeres. Para la agrupación en clústeres, todavía se necesita un proveedor de agrupación en clústeres independiente. Para más información sobre la configuración de la agrupación en clústeres, consulte la documentación de Configuración del servidor.

Esta funcionalidad impone algunos requisitos sobre cómo se implementa el servicio:

  • Los nombres de los silos deben coincidir con los nombres de los pods.
  • Los pods deben tener una etiqueta orleans/serviceId y orleans/clusterId que corresponda a los ServiceId y ClusterId de los silos. El método mencionado anteriormente propagará esas etiquetas a las opciones correspondientes de Orleans desde variables de entorno.
  • Los pods deben tener establecidas las siguientes variables de entorno: POD_NAME, POD_NAMESPACE, POD_IP, ORLEANS_SERVICE_ID, ORLEANS_CLUSTER_ID.

En el ejemplo siguiente se muestra cómo configurar correctamente estas etiquetas y variables de entorno:

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

En el caso de los clústeres habilitados para RBAC, es posible que también haya que conceder el acceso necesario a la cuenta de servicio de Kubernetes para los pods:

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

Sondeos de ejecución, preparación e inicio

Kubernetes puede sondear pods para determinar el estado de un servicio. Para más información, consulte Configuración de los sondeos de ejecución, preparación e inicio en la documentación de Kubernetes.

Orleans usa un protocolo de pertenencia a clústeres para detectar y recuperarse rápidamente de errores de proceso o de red. Cada nodo supervisa un subconjunto de otros nodos, enviando sondeos periódicos. Si un nodo no responde a varios sondeos sucesivos de otros nodos, se quitará forzosamente del clúster. Una vez que un nodo con errores detecta que ha sido quitado, finaliza inmediatamente. Kubernetes reiniciará el proceso finalizado e intentará volver a unirse al clúster.

Los sondeos de Kubernetes pueden ayudar a determinar si el proceso de un pod se está ejecutando y no está bloqueado en un estado zombie. los sondeos no comprueban la conectividad entre pods ni la capacidad de respuesta, ni realizan ninguna comprobación de funcionalidad al nivel de la aplicación. Si un pod no responde a un sondeo de ejecución, Kubernetes puede finalizar ese pod y volver a programarlo. Por lo tanto, los sondeos de Kubernetes y los de Orleans son complementarios.

El enfoque recomendado es configurar sondeos de ejecución en Kubernetes, que simplemente realizan una comprobación del entorno local para ver si la aplicación funciona según lo previsto. Estos sondeos sirven para finalizar el proceso si hay una inmovilización total, por ejemplo, debido a un error del tiempo de ejecución u otro evento poco probable.

Cuotas de recursos

Kubernetes trabaja junto al sistema operativo para implementar cuotas de recursos. Esto permite aplicar límites o reservas de la CPU y la memoria. En el caso de una aplicación principal que atiende la carga interactiva, se recomienda no implementar límites restrictivos a menos que sea necesario. Es importante tener en cuenta que las solicitudes y los límites son sustancialmente diferentes en su significado y en la ubicación en la que se implementan. Antes de establecer solicitudes o límites, dedique tiempo a comprender detalladamente cómo se implementan y aplican. Por ejemplo, es posible que la memoria no se mida uniformemente entre Kubernetes, el kernel de Linux y el sistema de supervisión. Es posible que las cuotas de la CPU no se apliquen de la manera esperada.

Solución de problemas

Los pods se bloquean, con la queja KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined

Mensaje de excepción 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()
  • Compruebe que las variables de entorno KUBERNETES_SERVICE_HOST y KUBERNETES_SERVICE_PORT están establecidas dentro del pod. Puede comprobarlo si ejecuta el siguiente comando kubectl exec -it <pod_name> /bin/bash -c env.
  • Asegúrese de que automountServiceAccountToken está establecido en true en el deployment.yaml de Kubernetes. Para más información, consulte Configuración de cuentas de servicio para pods