Configure YuniKorn for Spark on Kubernetes using CLI

Prerequisites

  • A Kubernetes cluster (1.32 or later) with access configured through kubectl.

  • The CLI tool that is unpacked from your offline package.

  • Spark operator is deployed in Kubernetes according to the instruction.

  • The following images that are unpacked and pushed to your repository:

    • hub.arenadata.io/adc-enterprise/yunikorn-k8shim:<version>

    • hub.arenadata.io/adc-enterprise/yunikorn-web:<version>

    • hub.arenadata.io/adc-enterprise/pause:<version>

    These artifacts can be found in the offline package, which can be requested from the Arenadata support team.

Step 1. Install YuniKorn

  1. Initialize YuniKorn:

    $ ./adc init --yunikorn -o yunikorn.yaml

    This operation creates the yunikorn.yaml file with a configuration template.

  2. Edit the configuration file to your needs:

    yunikorn.yaml
    apiVersion: adc.arenadata.io/v1alpha1
    kind: YuniKorn
    metadata:
      name: yunikorn
      namespace: yunikorn (1)
    spec:
      image: hub.arenadata.io/adc-enterprise/yunikorn-k8shim:<tag> (2)
      web:
        image: hub.arenadata.io/adc-enterprise/yunikorn-web:<tag> (3)
        #resources:
        #  limits:
        #    cpu: 200m
        #    memory: 500Mi
        #  requests:
        #    cpu: 100m
        #    memory: 100Mi
    
        goMemoryLimitPercentage: 60 (4)
        goGC: 100 (5)
    
        ## Environment variables passed to the component container.
        #envs:
        #  - name: YUNIKORN_LDAP_BIND_DN
        #    valueFrom:
        #      secretKeyRef:
        #        key: adminDN
        #        name: yunikorn-ldap-credentials
        #  - name: YUNIKORN_LDAP_BIND_PASSWORD
        #    valueFrom:
        #      secretKeyRef:
        #        key: adminPW
        #        name: yunikorn-ldap-credentials
        #  - name: YUNIKORN_LDAP_BASE_DN
        #    value: cn=accounts,dc=example,dc=com
        #  - name: YUNIKORN_LDAP_USER_BASE_DN
        #    value: cn=users,cn=accounts,dc=example,dc=com
        #  - name: YUNIKORN_LDAP_ADMIN_GROUPS
        #    value: admins
        #  - name: YUNIKORN_LDAP_ALLOWED_GROUPS
        #    value: ipausers
        #  - name: YUNIKORN_AUTH_SHARED_SECRET
        #    valueFrom:
        #      secretKeyRef:
        #        key: shared-secret
        #        name: yunikorn-web-auth
    
      ## LDAP authentication configuration.
      ## Uncomment and fill url and userBindPattern.
      ## For ldaps:// URLs the ssl: or ca: section must also be configured (depends on product)
      #ldap:
      #  # LDAP service url.
      #  url: ldap://ldap.example.com:389
      #
      #  # LDAP user Bind pattern.
      #  userBindPattern: uid=#UID,cn=users,dc=example,dc=com
    
      ## Kerberos configuration for authentication.
      #kerberos:
      #  realm: EXAMPLE.COM
      #
      #  # Service name in the Kerberos principal. Defaults to the product name.
      #  service: HTTP
      #
      #  # Hostname in the Kerberos principal.
      #  # Required for a fixed service principal; leave it empty only to derive one principal per pod from the cluster domain.
      #  hostname: yunikorn.example.com
      #  keytab:
      #    # true - kerberos-operator creates the keytab Secret.
      #    # false (default) - reference an existing keytab Secret with name keytab.secretName.
      #    create: false
      #
      #    # Name of the keytab Secret.
      #    # Optional when create: true - names the generated Secret (default: <name>-keytab).
      #    # Required when create: false - must reference an existing Secret.
      #    secretName: yunikorn-keytab
      #
      #    # Label selector for the Pod that generates the keytab.
      #    # Required when create: true; ignored when create: false.
      #    labelSelector:
      #      env: prod
      #    rotation:
      #      interval: 24h
      #      checkInterval: 1h
    
      ## HTTPS on the user-facing YuniKorn Web UI endpoint on port 9889.
      ## Together with monitoring.exportMetrics it also serves the scheduler /metrics over HTTPS
      ## using the same certificate and key, keeping the fixed "metrics" port name.
      ## The Web UI to k8shim unix socket is not changed.
      ## Set externalSecretName to reference an existing Secret,
      ## or set files and optional secretName to have ADC create it.
      #webTLS:
      #  ## Optional name of the Secret ADC creates from local files.
      #  #secretName: custom-yunikorn-web-tls
      #  externalSecretName: existing-yunikorn-web-tls
      #
      #  # Key in the Secret containing the web TLS certificate.
      #  certificateKey: tls.crt
      #
      #  # Key in the Secret containing the web TLS private key.
      #  privateKey: tls.key
      #
      #  ## Local files 'adc apply' puts into the Secret named by webTLS.secretName.
      #  ## Relative paths are resolved against the config file.
      #  #files:
      #  #  certificatePath: /path/to/tls.crt
      #  #  privateKeyPath: /path/to/tls.key
    
      # Whether the CLI creates the product namespace.
      # The namespace name is set in metadata.namespace.
      namespace:
        create: true
    
      # ServiceAccount used by the YuniKorn scheduler. The CLI creates it, plus a ClusterRole, Role
      # and their bindings, by default (create: true). Set create: false to skip all of them and only
      # reference a ServiceAccount (and RBAC) managed elsewhere. name is optional; when empty, it
      # defaults to the release name.
      serviceAccount: (6)
        create: true
        name: yunikorn
    
      ## Image pull secret for a private registry.
      ## Set 'externalSecretName' to reference an existing Secret,
      ## or set 'credentials' and optionally 'secretName' to let the CLI create one.
      #imagePullSecret:
      #  # Use a Secret managed outside ADC.
      #  externalSecretName: existing-registry-secret
      #
      #  ## Or let ADC create the Secret.
      #  #secretName: custom-registry-secret
      #
      #  #credentials:
      #  #  registry: registry.example.com
      #  #  username: user
      #  #  password: pass
    
      #resources:
      #  limits:
      #    cpu: "4"
      #    memory: 2Gi
      #  requests:
      #    cpu: 200m
      #    memory: 1Gi
    
      goMemoryLimitPercentage: 80 (7)
      goGC: 100 (8)
    
      ## Bootstrap config rendered into the yunikorn-defaults ConfigMap.
      ## Put the queue hierarchy under the "queues.yaml" key as a YAML string;
      ## k8shim reads it and creates the queues. Leave empty to use the built-in root queue.
      yunikornDefaults: (9)
        queues.yaml: | (10)
          partitions:
            - name: default
              queues:
                - name: root
                  submitacl: '*'
                  queues:
                    - name: engineering
                    - name: analytics
                    - name: ad-hoc
        service.exposeMetricsOnly: "true"
        service.placeholderImage: hub.arenadata.io/adc-enterprise/pause:<tag> (11)
    
      ## Controls whether Secret/ConfigMap changes restart pods.
      ## Set enabled: false to update referenced Secrets without restarting
      ## the workload; pods keep running the previous configuration until
      ## the policy is re-enabled. Defaults to enabled.
      #configurationRollout:
      #  enabled: false
    
      ## Monitoring configuration.
      #monitoring:
      #  # Enables Prometheus metrics export from this product's pods.
      #  exportMetrics: true
      #
      #  ## Renders a namespace-scoped vmagent that sends metrics to an external ADM.
      #  #vmagent:
      #  #  remoteWrite:
      #  #    url: http://vminsert.example.com:8480/insert/0/prometheus/api/v1/write
      #  #  scrapeInterval: 30s
      #  #
      #  #  ## HTTPS settings used by vmagent when scraping product metrics.
      #  #  #tls:
      #  #  #  ## CA certificate source used to verify the metrics endpoint.
      #  #  #  #ca:
      #  #  #  #  # Use a Secret managed outside ADC.
      #  #  #  #  externalSecretName: existing-product-metrics-ca
      #  #  #  #
      #  #  #  #  ## Or let ADC create the Secret.
      #  #  #  #  #secretName: product-metrics-ca
      #  #  #  #
      #  #  #  #  # Key containing the CA certificate in the referenced Secret.
      #  #  #  #  certificateKey: ca.crt
      #  #  #  #
      #  #  #  #  ## Local CA certificate read by ADC to create the configured Secret.
      #  #  #  #  #files:
      #  #  #  #  #  certificatePath: /path/to/ca.crt
      #  #  #
      #  #  #  ## Server name used to verify the metrics endpoint certificate hostname.
      #  #  #  #serverName: metrics.example.com
      #  #  #
      #  #  #  # Skip verification of the metrics endpoint certificate. Do not use together with ca.
      #  #  #  insecureSkipVerify: true
    1 Namespace that YuniKorn will use.
    2 URL to the YuniKorn k8shim image in your repository.
    3 URL to the YuniKorn web UI image in your repository.
    4 Percentage of web.resources.limits.memory used to compute the GOMEMLIMIT web UI value.
    5 GOGC web UI value.
    6 Service account settings.
    7 Percentage of resources.limits.memory used to compute the GOMEMLIMIT environment value.
    8 GOGC environment value.
    9 Bootstrap configuration keys. Leave empty to use the YuniKorn’s built-in root queue.
    10 Queue hierarchy in YuniKorn’s queues.yaml format (partitionsqueueschildren, with per-queue resources/properties).
    11 Image used for gang scheduling placeholder pods. adc adds the product default when omitted.
  3. You can check the configuration about to be applied by running the apply command with the --dry-run option:

    $ ./adc apply -f yunikorn.yaml --dry-run > yunikorn-render.yaml
    yunikorn-render.yaml
    ---
    apiVersion: v1
    kind: Namespace
    metadata:
      name: yunikorn
    spec: {}
    status: {}
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: yunikorn
      namespace: yunikorn
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: yunikorn-scheduler
    rules:
    - apiGroups:
      - ""
      resources:
      - namespaces
      verbs:
      - get
      - watch
      - list
    - apiGroups:
      - scheduling.k8s.io
      resources:
      - priorityclasses
      verbs:
      - get
      - watch
      - list
    - apiGroups:
      - storage.k8s.io
      resources:
      - volumeattachments
      verbs:
      - get
      - watch
      - list
    - apiGroups:
      - ""
      resources:
      - pods
      verbs:
      - get
      - watch
      - list
      - create
      - patch
      - update
      - delete
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: yunikorn-scheduler
      namespace: yunikorn
    rules:
    - apiGroups:
      - ""
      resources:
      - secrets
      verbs:
      - get
      - watch
      - list
      - update
    - apiGroups:
      - ""
      resources:
      - configmaps
      verbs:
      - get
      - watch
      - list
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: yunikorn-rbac
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: yunikorn-scheduler
    subjects:
    - kind: ServiceAccount
      name: yunikorn
      namespace: yunikorn
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: yunikorn-rbac-kube-scheduler
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:kube-scheduler
    subjects:
    - kind: ServiceAccount
      name: yunikorn
      namespace: yunikorn
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: yunikorn-rbac-volume-scheduler
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:volume-scheduler
    subjects:
    - kind: ServiceAccount
      name: yunikorn
      namespace: yunikorn
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: yunikorn-rbac
      namespace: yunikorn
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: yunikorn-scheduler
    subjects:
    - kind: ServiceAccount
      name: yunikorn
      namespace: yunikorn
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/component: yunikorn-scheduler
        app.kubernetes.io/instance: yunikorn
        app.kubernetes.io/managed-by: adc-cli
        app.kubernetes.io/name: yunikorn
      name: yunikorn-scheduler
      namespace: yunikorn
    spec:
      replicas: 1
      selector:
        matchLabels:
          app.kubernetes.io/component: yunikorn-scheduler
          app.kubernetes.io/instance: yunikorn
          app.kubernetes.io/managed-by: adc-cli
          app.kubernetes.io/name: yunikorn
      strategy: {}
      template:
        metadata:
          labels:
            app.kubernetes.io/component: yunikorn-scheduler
            app.kubernetes.io/instance: yunikorn
            app.kubernetes.io/managed-by: adc-cli
            app.kubernetes.io/name: yunikorn
        spec:
          containers:
          - env:
            - name: NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: YUNIKORN_K8SHIM_SOCKET_PATH
              value: /var/run/yunikorn/k8shim.sock
            - name: GOMEMLIMIT
              value: "1717986918"
            - name: GOGC
              value: "100"
            image: hub.arenadata.io/adc-enterprise/yunikorn-k8shim:<tag>
            imagePullPolicy: Always
            name: app
            ports:
            - containerPort: 9080
              name: metrics
              protocol: TCP
            resources:
              limits:
                cpu: "4"
                memory: 2Gi
              requests:
                cpu: 200m
                memory: 1Gi
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
              privileged: false
              readOnlyRootFilesystem: true
              runAsGroup: 4444
              runAsNonRoot: true
              runAsUser: 4444
            volumeMounts:
            - mountPath: /var/run/yunikorn
              name: k8shim-socket
          - env:
            - name: YUNIKORN_K8SHIM_URL
              value: unix:///var/run/yunikorn/k8shim.sock
            - name: GOMEMLIMIT
              value: "314572800"
            - name: GOGC
              value: "100"
            image: hub.arenadata.io/adc-enterprise/yunikorn-web:<tag>
            imagePullPolicy: Always
            name: yunikorn-scheduler-web
            ports:
            - containerPort: 9889
              name: web
              protocol: TCP
            resources:
              limits:
                cpu: 200m
                memory: 500Mi
              requests:
                cpu: 100m
                memory: 100Mi
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - ALL
              privileged: false
              readOnlyRootFilesystem: true
              runAsGroup: 4444
              runAsNonRoot: true
              runAsUser: 4444
            volumeMounts:
            - mountPath: /var/run/yunikorn
              name: k8shim-socket
          securityContext:
            fsGroup: 4444
            fsGroupChangePolicy: OnRootMismatch
            runAsGroup: 4444
            runAsNonRoot: true
            runAsUser: 4444
            supplementalGroups:
            - 4444
          serviceAccountName: yunikorn
          volumes:
          - emptyDir: {}
            name: k8shim-socket
    status: {}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/component: yunikorn-scheduler
        app.kubernetes.io/instance: yunikorn
        app.kubernetes.io/managed-by: adc-cli
        app.kubernetes.io/name: yunikorn
      name: yunikorn-service
      namespace: yunikorn
    spec:
      ports:
      - name: metrics
        port: 9080
        protocol: TCP
        targetPort: metrics
      - name: web
        port: 9889
        protocol: TCP
        targetPort: web
      selector:
        app.kubernetes.io/component: yunikorn-scheduler
        app.kubernetes.io/instance: yunikorn
        app.kubernetes.io/managed-by: adc-cli
        app.kubernetes.io/name: yunikorn
      type: ClusterIP
    status:
      loadBalancer: {}
    ---
    apiVersion: v1
    data:
      queues.yaml: |
        partitions:
          - name: default
            queues:
              - name: root
                submitacl: '*'
                queues:
                  - name: engineering
                  - name: analytics
                  - name: ad-hoc
      service.exposeMetricsOnly: "true"
      service.placeholderImage: hub.arenadata.io/adc-enterprise/pause:<tag>
    kind: ConfigMap
    metadata:
      name: yunikorn-defaults
      namespace: yunikorn
  4. If the manifest is correct, apply the configuration and deploy YuniKorn:

    $ ./adc apply -f yunikorn.yaml

    The expected output contains the confirmation of success:

    time="20260916080558UTC" level="info" msg="yunikorn applied to namespace yunikorn"
  5. Verify that the YuniKorn pods are running:

    $ kubectl get pods -n yunikorn

    The expected output should be similar to:

    NAME                                 READY   STATUS    RESTARTS   AGE
    yunikorn-scheduler-7dfd5df97-92xzb   2/2     Running   0          8s

Step 2. Provide access to YuniKorn web UI

To access the YuniKorn web UI, you need to expose the service using one of the supported publication methods, for example, through a load balancer or Ingress controller. All configurations related to exposing a service, including DNS, annotations, Ingress settings, load balancing rules, and other platform-specific settings, must be specified according to your Kubernetes environment.

  1. Get the external IP address of your load balancer or Ingress controller. For example:

    NAME                                        TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)           AGE
    yunikorn-lb                                    LoadBalancer   10.85.56.180   10.92.41.69   9889:30226/TCP   119s
  2. Open the YuniKorn web UI in your browser, using the http://10.92.41.69:9889 URL.

    YuniKorn web UI
    YuniKorn web UI
    YuniKorn web UI
    YuniKorn web UI

Step 3. Submit a Spark application

  1. Initialize a Spark application:

    $ ./adc init --spark-application -o spark-application.yaml

    This operation creates the spark-application.yaml file with a configuration template.

  2. Edit the configuration file to your needs:

    spark-application.yaml
    apiVersion: adc.arenadata.io/v1alpha1
    kind: SparkApplication
    metadata:
      name: spark-application
      namespace: spark-applications
    spec:
      image: hub.adsw.io/adc-develop-enterprise/spark3:<tag>
    
      ## Image pull secret for a private registry.
      ## Set 'externalSecretName' to reference an existing Secret,
      ## or set 'credentials' and optionally 'secretName' to let the CLI create one.
      #imagePullSecret:
      #
      #  # Use a Secret managed outside ADC.
      #  externalSecretName: existing-registry-secret
      #
      #  ## Or let ADC create the Secret.
      #  #secretName: custom-registry-secret
      #  #credentials:
      #  #  registry: registry.example.com
      #  #  username: user
      #  #  password: pass
      # hadoop:
      #   core:
      #   hive:
    
    
      ## Kerberos configuration for authentication.
      #kerberos:
      #  principal: user@EXAMPLE.COM
      #
      #  # CLI reads the local files and creates the kerberos-ccache Secret on 'adc apply'.
      #  # Alternative - keytab mode: replace this block with:
      #  #   keytab:
      #  #     secretName: <name-of-existing-keytab-secret>
      #  ticketCache:
      #    #secretName: custom-ticket-cache
      #    externalSecretName: existing-ticket-cache
      #    #ticketPath: /tmp/krb5cc_1000
      #    #krb5ConfPath: /etc/krb5.conf
    
      ## Ranger plugin configuration.
      ## Uncomment and fill the lines below. adc apply derives the rest.
      #ranger:
      #  # fill ranger.plugin.spark.policy.rest.url below with Ranger endpoint, e.g. https://adps-adc.ru-central1.internal:6182
      #  # fill ranger.plugin.spark.service.name below with Ranger service name you want to use for product, e.g. adc_spark_id_1
      #  security:
      #    ranger.plugin.spark.policy.rest.url: ""
      #    ranger.plugin.spark.service.name: ""
      #
      #  # fill xasecure.audit.destination.solr.zookeepers below with Zookeepers endpoints to resolve solr service, e.g. adps-adc.ru-central1.internal:2181/Arenadata.Hadoop-2.solr.server
      #  audit:
      #    xasecure.audit.destination.solr.zookeepers: ""
      #
      #  # Local Ranger files 'adc apply' writes into the configs Secret.
      #  # Relative paths are resolved against the config file.
      #  files:
      #    jceksStorePath: /path/to/ranger.jceks
    
      ## Java KeyStore/TrustStore certificate configuration.
      ## Set externalSecretName to reference an existing Secret,
      ## or set files and optional secretName to have ADC create it.
      #ssl:
      #  ## Name of the Secret containing Java keystores.
      #  #secretName: custom-ssl-secret
      #  externalSecretName: existing-ssl-secret
      #
      #  # Key in the Secret containing the truststore file.
      #  trustStoreKey: truststore.jks
      #
      #  ## Password for the truststore (optional).
      #  #trustStorePassword: bigdata
      #
      #  ## Key in the Secret containing the keystore file (optional).
      #  #keyStoreKey: keystore.jks
      #
      #  ## Password for the keystore (optional).
      #  #keyStorePassword: bigdata
      #
      #  ## Local files 'adc apply' puts into the Secret named by ssl.secretName.
      #  ## Relative paths are resolved against the config file.
      #  #files:
      #  #  trustStorePath: /path/to/truststore.jks
      #  #  #keyStorePath: /path/to/keystore.jks
    
      ## Use an external Hadoop configs Secret instead of the one rendered by ADC.
      #hadoopConfigsSecret:
      #  # Use a Secret managed outside ADC.
      #  externalSecretName: existing-spark-hadoop-configs
      #
      #  ## Or let ADC create the Secret.
      #  #secretName: custom-spark-hadoop-configs
    
      ## Use an external Ranger configs Secret instead of the one rendered by ADC.
      #rangerConfigsSecret:
      #  # Use a Secret managed outside ADC.
      #  externalSecretName: existing-spark-ranger-configs
      #
      #  ## Or let ADC create the Secret.
      #  #secretName: custom-spark-ranger-configs
    
      # Spark application main resource (e.g. local:///opt/spark/examples/jars/spark-examples.jar).
      mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.13-3.5.4.4-4.3.0-2.jar"
    
      ## HDFS or local directory for the Spark event log.
      ## When set, the CLI adds spark.eventLog.enabled=true, spark.eventLog.dir,
      ## spark.eventLog.rolling.enabled=true and spark.eventLog.rolling.interval=30s to sparkConf.
      #eventLogDir: ""
    
      ## Fully-qualified main class name. Required for Java/Scala applications.
      mainClass: "org.apache.spark.examples.SparkPi"
    
      # ServiceAccount used by the Spark driver, also injected into
      # spark.kubernetes.authenticate.driver.serviceAccountName. The CLI creates it, plus a Role
      # and RoleBinding for Spark pods, by default (create: true). Set create: false to skip that
      # and only reference a ServiceAccount managed elsewhere.
      # The Role rules are managed by the CLI and cannot be customized.
      serviceAccount:
        create: true
        name: spark-application
      job:
        ## true (default) deletes the spark-submit Job pod after it finishes; set false to keep it for debugging.
        deleteOnTermination: false
    
        #resources:
        #  limits:
        #    cpu: 500m
        #    memory: 512Mi
        #  requests:
        #    cpu: 250m
        #    memory: 256Mi
    
        ## Component arguments. Key-value pairs passed to the component configuration.
        args:
          driver-memory: 4g
          executor-memory: 4g
    
      ## Application arguments appended after mainApplicationFile.
      #args:
      #  - "100"
    
      # Spark configuration entries (spark.*).
      sparkConf:
        spark.artifactory.dir.path: /tmp/artifacts
        spark.jars.ivy: /tmp/ivy
        spark.local.dir: /tmp/data
        spark.sql.catalog.spark_catalog: org.apache.iceberg.spark.SparkSessionCatalog
        spark.sql.extensions: org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
        spark.sql.security.confblacklist: spark.sql.extensions
    
    
      ## Seconds after the application finishes (Succeeded, or Failed with no
      ## retries left) before the SparkApplication is deleted. Omit to keep it
      ## until explicit deletion.
      #ttlSecondsAfterFinished: 3600
    
      ## Celeborn remote shuffle service for Spark.
      ## tiers mirror the cluster's storage.tiers: local (SSD/HDD) and MEMORY advertise their name only,
      ## remote (S3/HDFS) also set dir (and, for S3, credentials). Ozone is an HDFS tier with an ofs:// dir.
      #celeborn:
        #  # Storage tiers mirroring the cluster's storage.tiers so the client advertises the same layers.
        #  # type: SSD, HDD, S3, HDFS, MEMORY. SSD/HDD and MEMORY are advertise-only here (no dir; worker-only
        #  # fields ignored); remote S3/HDFS set dir (s3a:// for S3; hdfs:// or ofs:// for Ozone on HDFS). Example:
        #  #   - type: MEMORY   # cache tier; pair with a durable tier below, no dir
        #  #   - type: SSD      # advertise-only on the client, no dir needed
        #  #   - dir: s3a://bucket/celeborn
        #  #     s3: { endpoint: https://s3:9878, region: us-east-1 }
        #  #     type: S3
        #  #   - dir: hdfs://nn/celeborn   # or ofs://om/volume/bucket/celeborn for Ozone
        #  #     type: HDFS
        #  tiers:
        #    - dir: s3a://shuffle/my-cluster
        #      s3:
        #        accessKey: <access-key>
        #        endpoint: https://s3.endpoint:443
        #        pathStyleAccess: true
        #        region: <region>
        #        secretKey: <secret-key>
        #      type: S3
        #  masterEndpoint: ""
        #  extraSparkConf:
        #    spark.sql.adaptive.enabled: "true"
    
        # Enable TLS on the client's RPC connection to the Celeborn cluster.
        # When true the CLI renders spark.celeborn.ssl.* into the Spark conf
        # and requires the ssl section with trustStoreKey.
        rpcEncryption: false
    
      ## YuniKorn scheduler configuration for queue selection and Gang scheduling.
      ## Uncomment the block to route the Spark job into a YuniKorn queue; the CLI renders the
      ## scheduler name, queue labels and gang annotations into sparkConf.
      yunikorn:
        queue: root.analytics
        taskGroups:
          - minMember: 1
            minResource:
              cpu: "1"
              memory: 1433Mi
            name: spark-driver
          - minMember: 2
            minResource:
              cpu: "1"
              memory: 1433Mi
            name: spark-executor
    
      ## Monitoring configuration.
      monitoring:
        # Enables Prometheus metrics export from this product's pods.
        exportMetrics: true
  3. Submit the Spark application:

    $ ./adc apply -f spark-application.yaml

    The expected output contains a confirmation of success:

    time="20260916081434UTC" level="info" msg="cluster spark-application applied to namespace spark-applications"
  4. Check the information about resource allocation in the YuniKorn pod logs:

    $ kubectl logs yunikorn-scheduler-7dfd5df97-92xzb -n yunikorn

    The output should contain the lines like:

    2026-09-16T08:23:30.755Z	INFO	shim.cache.task	cache/task.go:378	successfully bound pod	{"podName": "spark-pi-485570a0a9505508-exec-2"}
    2026-09-16T08:23:30.756Z	INFO	shim.fsm	cache/task_state.go:381	Task state transition	{"app": "spark-520890f663bb4d678b7cc8b5c715f15e", "task": "8e801dcc-12ec-4b57-9af0-b4e067d25d40", "taskAlias": "spark-applications/spark-pi-485570a0a9505508-exec-2", "source": "Allocated", "destination": "Bound", "event": "TaskBound"}

Delete instances

To delete the Spark application, run the following command:

$ ./adc delete -f spark-application.yaml

To delete YuniKorn, run the following command:

$ ./adc delete -f yunikorn.yaml
Found a mistake? Seleсt text and press Ctrl+Enter to report it