Todos os produtos
Search
Central de documentação

Container Service for Kubernetes:Multi-cluster scheduling and distribution of Spark jobs

Última atualização: Jun 27, 2026

Use instâncias Fleet do ACK One (Distributed Cloud Container Platform for Kubernetes) para agendar e distribuir jobs do Apache Spark entre vários clusters. Essa abordagem permite executar workloads em lote do Spark na capacidade ociosa dos clusters, sem competir por recursos com workloads de serviços online.

Como funciona

image

  1. Instale o componente ack-spark-operator em cada sub-cluster onde os jobs do Spark serão executados.

  2. Crie um SparkApplication e uma PropagationPolicy na instância Fleet.

  3. O Global Scheduler (componente de agendamento multicluster da instância Fleet) compara as solicitações de recursos do job do Spark com a capacidade restante de cada sub-cluster associado e seleciona o melhor destino.

    Em sub-clusters com Kubernetes 1.28 ou posterior, a instância Fleet oferece suporte à pré-ocupação de recursos para aumentar as taxas de sucesso do agendamento.

  4. A instância Fleet distribui o SparkApplication para o sub-cluster selecionado.

  5. O ACK Spark Operator no sub-cluster inicia os Pods driver e executor do Spark. A instância Fleet monitora o status de execução do job. Se o driver falhar ao iniciar devido a recursos insuficientes, a instância Fleet recupera o SparkApplication após um tempo limite e o reagenda para outro sub-cluster com capacidade suficiente.

Pré-requisitos

Antes de começar, verifique se você tem:

Etapa 1: Instalar o ack-spark-operator nos sub-clusters

Instale o componente ack-spark-operator em cada sub-cluster onde deseja executar jobs do Spark.

  1. Faça login no ACK console. No painel de navegação à esquerda, escolha Marketplace > Marketplace.

  2. Na página Marketplace, clique em App Catalog, localize e clique em ack-spark-operator.

  3. Na página do ack-spark-operator, clique em Deploy.

  4. No painel Deploy, selecione um cluster e namespace e clique em Next.

  5. Na etapa Parameters, configure os parâmetros e clique em OK.

A tabela a seguir descreve os principais parâmetros. Todas as configurações de parâmetros estão disponíveis na seção Parameters da página do ack-spark-operator.

Parâmetro

Descrição

Padrão

controller.replicas

Quantidade de réplicas do controlador.

1

webhook.replicas

Quantidade de réplicas do webhook.

1

spark.jobNamespaces

Namespaces onde os jobs do Spark podem ser executados. Defina como [""] para todos os namespaces ou liste namespaces específicos separados por vírgulas, por exemplo, ["ns1","ns2","ns3"].

["default"]

spark.serviceAccount.name

Nome da ServiceAccount criada automaticamente em cada namespace listado em spark.jobNamespaces. O operador também cria os recursos correspondentes de controle de acesso baseado em função (RBAC). Especifique um nome personalizado aqui se planeja referenciá-lo ao enviar jobs do Spark.

spark-operator-spark

Etapa 2: Criar uma PriorityClass e distribuí-la aos sub-clusters

Atribua uma prioridade baixa aos jobs do Spark para evitar que eles compitam por recursos com workloads de serviços online.

  1. Com o arquivo kubeconfig da instância Fleet, crie uma PriorityClass de baixa prioridade com um value negativo:

    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata:
      name: low-priority
    value: -1000
    globalDefault: false
    description: "Low priority for Spark applications"
  2. Crie uma ClusterPropagationPolicy na instância Fleet para distribuir a PriorityClass aos sub-clusters de destino. Para distribuir a todos os clusters associados, remova o campo clusterAffinity.

    apiVersion: policy.one.alibabacloud.com/v1alpha1
    kind: ClusterPropagationPolicy
    metadata:
      name: priority-policy
    spec:
      preserveResourcesOnDeletion: false
      resourceSelectors:
      - apiVersion: scheduling.k8s.io/v1
        kind: PriorityClass
      placement:
        clusterAffinity:
          clusterNames:
          - ${cluster1-id} # The ID of your cluster.
          - ${cluster2-id} # The ID of your cluster.
    #      labelSelector:
    #        matchLabels:
    #          key: value
        replicaScheduling:
          replicaSchedulingType: Duplicated

Etapa 3: Enviar um job do Spark na instância Fleet

(Opcional) Criar e distribuir namespaces para os sub-clusters

Se o namespace onde o SparkApplication será executado ainda não existir na instância Fleet, crie-o primeiro. Esse namespace também deve estar listado no parâmetro spark.jobNamespaces configurado na Etapa 1.

  1. Crie o namespace na instância Fleet:

    kubectl create ns xxx
  2. Crie uma ClusterPropagationPolicy para distribuir o namespace para cada sub-cluster:

    apiVersion: policy.one.alibabacloud.com/v1alpha1
    kind: ClusterPropagationPolicy
    metadata:
      name: ns-policy
    spec:
      resourceSelectors:
      - apiVersion: v1
        kind: Namespace
        name: xxx
      placement:
        clusterAffinity:
          clusterNames:
          - ${cluster1-id} # The ID of your cluster.
          - ${cluster2-id} # The ID of your cluster.
        replicaScheduling:
          replicaSchedulingType: Duplicated

Criar uma PropagationPolicy para SparkApplication

Crie uma PropagationPolicy na instância Fleet. Essa política instrui o Global Scheduler a distribuir todos os recursos SparkApplication da versão de API sparkoperator.k8s.io/v1beta2 para os sub-clusters de destino usando agendamento Gang.

apiVersion: policy.one.alibabacloud.com/v1alpha1
kind: PropagationPolicy
metadata:
  name: sparkapp-policy
  namespace: default
spec:
  preserveResourcesOnDeletion: false
  propagateDeps: true   # Automatically propagates dependent resources (such as the ServiceAccount referenced in the driver spec) to the target sub-clusters.
  placement:
    clusterAffinity:
      clusterNames:
      - ${cluster1-id} # The ID of your cluster.
      - ${cluster2-id} # The ID of your cluster.
#      labelSelector:
#        matchLabels:
#          key: value
    replicaScheduling:
      replicaSchedulingType: Divided
      customSchedulingType: Gang
  resourceSelectors:
    - apiVersion: sparkoperator.k8s.io/v1beta2
      kind: SparkApplication

Enviar um SparkApplication

Crie um SparkApplication na instância Fleet. Defina priorityClassName como a PriorityClass criada na Etapa 2 tanto para o driver quanto para o executor.

O Global Scheduler usa os valores de memory e cores nas especificações do driver e do executor como solicitações de recursos do Kubernetes. Ele compara o total de recursos solicitados com a capacidade restante de cada sub-cluster para selecionar o cluster de destino. Dimensione esses valores para refletir os recursos reais necessários ao seu job. Valores subdimensionados podem resultar em agendamento bem-sucedido, mas falha na execução. Valores superdimensionados podem impedir o agendamento se nenhum cluster tiver capacidade suficiente.

Após criar o SparkApplication, a PropagationPolicy da etapa anterior o distribui para o sub-cluster selecionado.

apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
  name: spark-pi
  namespace: default     # Make sure this namespace is listed in the spark.jobNamespaces parameter.
spec:
  type: Scala
  mode: cluster
  image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/spark:3.5.4
  imagePullPolicy: IfNotPresent
  mainClass: org.apache.spark.examples.SparkPi
  mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-3.5.4.jar
  arguments:
  - "1000"
  sparkVersion: 3.5.4
  driver:
    cores: 1
    memory: 512m
    priorityClassName: low-priority
    serviceAccount: spark-operator-spark   # Replace with the custom name you specified in Step 1.
  executor:
    instances: 1
    cores: 1
    memory: 512m
    priorityClassName: low-priority
  restartPolicy:
    type: Never

Etapa 4: Verificar o job do Spark

Verificar o status do job e o resultado do agendamento

  1. Execute o seguinte comando na instância Fleet para visualizar o status do job do Spark:

    kubectl get sparkapp

    Saída esperada:

    NAME       STATUS    ATTEMPTS   START                  FINISH       AGE
    spark-pi   RUNNING   1          2025-02-24T12:10:34Z   <no value>   11s
  2. Execute o comando abaixo para confirmar em qual sub-cluster o job foi agendado:

    kubectl describe sparkapp spark-pi

    Saída esperada:

    Normal   ScheduleBindingSucceed  2m29s                  default-scheduler                   Binding has been scheduled successfully. Result: {c6xxxxx:0,[{driver 1} {executor 1}]}
  3. Use o seguinte comando para visualizar o status do job no sub-cluster associado:

    kubectl amc get sparkapp -M

    Saída esperada:

    NAME       CLUSTER     STATUS      ATTEMPTS   START                  FINISH                 AGE   ADOPTION
    spark-pi   c6xxxxxxx   COMPLETED   1          2025-02-24T12:10:34Z   2025-02-24T12:11:20Z   61s   Y
  4. Consulte o status dos Pods executando este comando:

    kubectl amc get pod -M

    Saída esperada:

    NAME              CLUSTER     READY   STATUS      RESTARTS   AGE
    spark-pi-driver   c6xxxxxxx   0/1     Completed   0          68s
  5. Visualize os detalhes completos do job do Spark no sub-cluster com o comando a seguir:

    kubectl amc get sparkapp spark-pi -m ${member clusterid} -oyaml

Solução de problemas

Caso o job não atinja o status COMPLETED, utilize os comandos abaixo para diagnosticar o problema.

Job preso em PENDING ou não agendado:

Verifique os eventos no SparkApplication para identificar se o Global Scheduler relatou uma falha de agendamento:

kubectl describe sparkapp spark-pi

Procure por eventos com o motivo ScheduleBindingFailed ou similar. Causas comuns incluem recursos insuficientes em todos os sub-clusters ou uma PriorityClass ausente no cluster de destino.

Pod do Driver não está iniciando:

Verifique os eventos do Pod do driver no sub-cluster:

kubectl amc get pod -M
kubectl amc describe pod spark-pi-driver -m ${member clusterid}

Operator não está em execução no sub-cluster:

Confirme se o ack-spark-operator está em execução no sub-cluster:

kubectl amc get pod -n spark-operator -M

Próximos passos