Hospedagem do Kubernetes

O Kubernetes é uma opção popular para hospedar aplicativos Orleans. Orleans é executado no Kubernetes sem configuração específica; no entanto, ele também pode aproveitar o conhecimento extra que a plataforma de hospedagem fornece.

O pacote Microsoft.Orleans.Hosting.Kubernetes adiciona integração para hospedar um aplicativo Orleans em um cluster do Kubernetes. O pacote fornece um método de extensão, UseKubernetesHostingexecutando as seguintes ações:

Observe que o pacote de hospedagem do Kubernetes não usa o Kubernetes para clustering. Um provedor de clustering separado ainda é necessário. Para obter mais informações sobre como configurar o clustering, consulte a documentação de configuração do servidor.

Implantar no Kubernetes com Aspire

Aspire simplifica a implantação no Kubernetes ao gerar automaticamente manifestos do Kubernetes com base na configuração do AppHost. Em vez de gravar manualmente arquivos YAML, Aspire pode produzir os recursos de implantação, serviço e configuração necessários com base no grafo de dependência do aplicativo.

Adicionar a integração de hospedagem do Kubernetes

Primeiro, instale o pacote NuGet Aspire.Hosting.Kubernetes em seu projeto AppHost.

dotnet add package Aspire.Hosting.Kubernetes

Em seguida, adicione um ambiente do Kubernetes ao AppHost:

var builder = DistributedApplication.CreateBuilder(args);

// Add the Kubernetes environment
var k8s = builder.AddKubernetesEnvironment("k8s");

// Add your Orleans silo project
var silo = builder.AddProject<Projects.MySilo>("silo");

builder.Build().Run();

Opcionalmente, você pode personalizar as propriedades de ambiente do Kubernetes:

builder.AddKubernetesEnvironment("k8s")
    .WithProperties(k8s =>
    {
        k8s.HelmChartName = "my-orleans-app";
    });

Gerar manifestos do Kubernetes

Use a CLI do Aspire para gerar manifestos do Kubernetes a partir do seu projeto Aspire:

aspire publish -o ./k8s-manifests

Isso gera um conjunto completo de arquivos YAML do Kubernetes no diretório de saída especificado, incluindo:

  • Implantações ou StatefulSets para cada serviço no seu AppHost
  • Serviços para conectividade de rede
  • ConfigMaps e Secrets para configuração
  • Gráficos do Helm para facilitar o gerenciamento de implantação
  • PersistentVolumes e PersistentVolumeClaims para recursos de armazenamento

Implantar em seu cluster

Depois de gerar os manifestos, implemente-os usando kubectl ou Helm.

# Using kubectl
kubectl apply -f ./k8s-manifests

# Or using Helm (if Helm charts were generated)
helm install my-orleans-app ./k8s-manifests/charts/my-orleans-app

Benefícios de manifestos gerados por Aspire

  • Configuração consistente: as variáveis de ambiente, as portas e as referências de recursos são sincronizadas automaticamente.
  • Gerenciamento de dependência: os serviços são configurados com cadeias de conexão corretas e referências de serviço.
  • Consciente de Orleans: a Orleans integração de hospedagem garante que a configuração de silo adequada esteja incluída.
  • Suporte do Helm: os gráficos do Helm gerados permitem implantações parametrizadas entre ambientes.

Dica

Para implantações de produção, examine e personalize os manifestos gerados conforme necessário. Use parâmetros externos para configurar valores específicos do ambiente.

Para obter informações detalhadas sobre a integração do Aspire Kubernetes, consulte a documentação de integração doAspire Kubernetes.

Para obter mais informações sobre como configurar Orleans com Aspire, consulte AspireOrleans integração.

Configuração manual do Kubernetes

Essa funcionalidade impõe alguns requisitos na implantação do serviço:

  • Os nomes de silo devem corresponder aos nomes de pod.
  • Os pods precisam ter rótulos orleans/serviceId e orleans/clusterId que correspondam aos silos ServiceId e ClusterId. O UseKubernetesHosting método propaga esses rótulos para as opções correspondentes Orleans de variáveis de ambiente.
  • Os pods devem ter as seguintes variáveis de ambiente definidas: POD_NAME, POD_NAMESPACE, POD_IP, ORLEANS_SERVICE_ID, ORLEANS_CLUSTER_ID.

O exemplo a seguir mostra como configurar esses rótulos e variáveis de ambiente corretamente:

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 identifies the service to Orleans
        orleans/serviceId: dictionary-app

        # This label identifies an instance of a cluster to Orleans.
        # Typically, this is the same value as the previous label, or any
        # fixed value.
        # In cases where you don't use rolling deployments (for example,
        # blue/green deployments),
        # this value can allow for distinct clusters that don't communicate
        # directly with each other,
        # but 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 Orleans uses
          - containerPort: 11111
          - containerPort: 30000
          env:
          # The Azure Storage connection string for clustering is injected as an
          # environment variable.
          # You must create it 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's 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

Para clusters habilitados para RBAC, a concessão do acesso necessário à conta de serviço do Kubernetes para os pods também pode ser necessária:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: orleans-hosting
rules:
- apiGroups: [ "" ]
  resources: ["pods"]
  verbs: ["get", "watch", "list", "delete", "patch"]
---
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: ''

Investigações de atividade, preparação e inicialização

O Kubernetes pode sondar pods para determinar a integridade do serviço. Para obter mais informações, consulte Configurar Liveness, Readiness e Startup Probes na documentação do Kubernetes.

Orleans usa um protocolo de associação de cluster para detectar e recuperar prontamente de falhas de processo ou de rede. Cada nó monitora um subconjunto de outros nós, enviando investigações periódicas. Se um nó não responder a várias sondagens sucessivas de vários outros nós, o cluster o removerá forçosamente. Depois que um nó com falha souber de sua remoção, ele será encerrado imediatamente. O Kubernetes reinicia o processo encerrado, que então tenta se reunir ao cluster.

As sondas do Kubernetes ajudam a determinar se um processo em um pod está sendo executado e não está travado em um estado zumbi. Essas sondas não verificam a conectividade ou a responsividade entre pods, nem executam verificações de funcionalidade no nível da aplicação. Se um pod não responder a uma investigação de atividade, o Kubernetes poderá eventualmente encerrar esse pod e reagendá-lo. As sondas do Kubernetes e as sondas Orleans são, portanto, complementares.

A abordagem recomendada é configurar Liveness Probes no Kubernetes que executem uma verificação simples e somente local para garantir que o aplicativo funcione conforme o esperado. Essas sondas servem para encerrar o processo se houver um congelamento total, por exemplo, devido a uma falha de execução ou outro evento improvável.

Cotas de recursos

O Kubernetes trabalha com o sistema operacional para implementar cotas de recursos. Isso permite a imposição de reservas de CPU e memória e/ou limites. Para um aplicativo primário que atende a carga interativa, a implementação de limites restritivos não é recomendada, a menos que seja necessário. É importante observar que as solicitações e os limites diferem substancialmente no significado e no local da implementação. Antes de definir solicitações ou limites, reserve um tempo para obter uma compreensão detalhada de como elas são implementadas e impostas. Por exemplo, a memória pode não ser medida uniformemente entre o Kubernetes, o kernel linux e o sistema de monitoramento. As cotas de CPU podem não ser impostas conforme o esperado.

Solução de problemas

Falha nos pods com reclamação de KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined

Mensagem de exceção completa:

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()
  • Verifique se as variáveis de ambiente KUBERNETES_SERVICE_HOST e KUBERNETES_SERVICE_PORT estão definidas dentro do Pod. Verifique executando o comando kubectl exec -it <pod_name> /bin/bash -c env.
  • Verifique se automountServiceAccountToken está definido como true no Kubernetes deployment.yaml. Para obter mais informações, confira Configurar contas de serviço para pods.