Настройка Kerberos для Spark History Server в Kubernetes
Требования
-
Установленный и керберизованный кластер ADH совместимой версии (требуется, только если логи событий будут сохраняться в HDFS или Ozone).
-
Извлеченный и загруженный в ваш репозиторий образ
hub.arenadata.io/adc-enterprise/spark3:<version>. -
Оператор Spark, развернутый в Kubernetes согласно инструкции. Убедитесь, что пространство имен Spark History Server включено в
payloadNamespacesоператора Spark. -
Оператор Kerberos, развернутый в Kubernetes согласно инструкции. Убедитесь, что пространство имен Spark History Server включено в
payloadNamespacesоператора Kerberos.
Шаг 1. Установка Spark History Server
-
Подготовьте файл hadoop_conf.yaml с настройками Hadoop (необходимо, только если используются S3 или сервисы Hadoop):
hadoop_conf.yamlsites: core: fs.defaultFS: hdfs://adh hadoop.security.authentication: kerberos dfs.client.failover.proxy.provider.adh: org.apache.hadoop.hdfs.server.namenode.ha.ObserverReadProxyProvider dfs.ha.namenodes.adh: nn_tsn-adh-k8s-1,nn_tsn-adh-k8s-3 dfs.namenode.rpc-address.adh.nn_tsn-adh-k8s-1: tsn-adh-k8s-1.ru-central1.internal:8020 dfs.namenode.rpc-address.adh.nn_tsn-adh-k8s-3: tsn-adh-k8s-3.ru-central1.internal:8020 dfs.nameservices: adh dfs.namenode.kerberos.principal: hdfs-namenode/_HOST@AD.RANGER-TEST dfs.journalnode.kerberos.principal: hdfs-journalnode/_HOST@AD.RANGER-TEST dfs.datanode.kerberos.principal: hdfs-datanode/_HOST@AD.RANGER-TEST hadoop.ssl.enabled: false hdfs: dfs.client.read.shortcircuit: false ozone: ozone.om.address.adh.om_tsn-adh-k8s-1: tsn-adh-k8s-1.ru-central1.internal:9862 ozone.om.address.adh.om_tsn-adh-k8s-2: tsn-adh-k8s-2.ru-central1.internal:9862 ozone.om.address.adh.om_tsn-adh-k8s-3: tsn-adh-k8s-3.ru-central1.internal:9862 ozone.om.nodes.adh: om_tsn-adh-k8s-1,om_tsn-adh-k8s-2,om_tsn-adh-k8s-3 ozone.om.kerberos.principal: om/_HOST@AD.RANGER-TEST ozone.om.service.ids: adhom hive: hive.metastore.sasl.enabled: true hive.metastore.uris: thrift://tsn-adh-k8s-1.ru-central1.internal:9083 hive.metastore.kerberos.principal: hive/_HOST@AD.RANGER-TEST metastore.use.SSL: false -
Инициализируйте Spark History Server:
$ ./adc init --spark-history-server --hadoop-file=hadoop_conf.yaml -o spark-history-server.yamlДанная команда создаст файл spark-history-server.yaml с шаблоном конфигурации.
-
Отредактируйте конфигурационный файл:
spark-history-server.yamlapiVersion: adc.arenadata.io/v1alpha1 kind: SparkHistoryServer metadata: name: spark-history-server namespace: spark-history-server (1) spec: image: hub.arenadata.io/adc-enterprise/spark3:<tag> (2) ## 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: (3) core: dfs.client.failover.proxy.provider.adh: org.apache.hadoop.hdfs.server.namenode.ha.ObserverReadProxyProvider dfs.ha.namenodes.adh: nn_tsn-adh-k8s-1,nn_tsn-adh-k8s-3 dfs.datanode.kerberos.principal: hdfs-datanode/_HOST@AD.RANGER-TEST dfs.journalnode.kerberos.principal: hdfs-journalnode/_HOST@AD.RANGER-TEST dfs.namenode.kerberos.principal: hdfs-namenode/_HOST@AD.RANGER-TEST dfs.namenode.rpc-address.adh.nn_tsn-adh-k8s-1: tsn-adh-k8s-1.ru-central1.internal:8020 dfs.namenode.rpc-address.adh.nn_tsn-adh-k8s-3: tsn-adh-k8s-3.ru-central1.internal:8020 dfs.nameservices: adh fs.defaultFS: hdfs://adh hadoop.security.authentication: kerberos hdfs: dfs.client.read.shortcircuit: "false" hive: hive.metastore.kerberos.principal: hive/_HOST@AD.RANGER-TEST hive.metastore.sasl.enabled: "true" hive.metastore.uris: thrift://tsn-adh-k8s-1.ru-central1.internal:9083 metastore.use.SSL: "false" ozone: ozone.om.kerberos.principal: om/_HOST@AD.RANGER-TEST ozone.om.address.adh.om_tsn-adh-k8s-1: tsn-adh-k8s-1.ru-central1.internal:9862 ozone.om.address.adh.om_tsn-adh-k8s-2: tsn-adh-k8s-2.ru-central1.internal:9862 ozone.om.address.adh.om_tsn-adh-k8s-3: tsn-adh-k8s-3.ru-central1.internal:9862 ozone.om.nodes.adh: om_tsn-adh-k8s-1,om_tsn-adh-k8s-2,om_tsn-adh-k8s-3 ozone.om.service.ids: adhom ## Kerberos configuration for authentication. kerberos: (4) realm: AD.RANGER-TEST # # # Service name in the Kerberos principal. Defaults to the product name. service: spark-history # # # 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: spark-history-server.ru-central1.internal keytab: (5) # # true - kerberos-operator creates the keytab Secret. # # false (default) - reference an existing keytab Secret with name keytab.secretName. create: true # # # 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: spark-history-keytab # # # Label selector for the Pod that generates the keytab. # # Required when create: true; ignored when create: false. labelSelector: env: prod # #additionalPrincipals: # # - HTTP/history-lb.example.com # rotation: interval: 720h checkInterval: 1h spnego: true ## 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-spark-history-ssl # externalSecretName: existing-spark-history-ssl # # # 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-history-hadoop-configs # # ## Or let ADC create the Secret. # #secretName: custom-history-hadoop-configs ## Use an external Spark History properties Secret instead of the one rendered by ADC. #historyPropertiesSecret: # # Use a Secret managed outside ADC. # externalSecretName: existing-history-properties # # ## Or let ADC create the Secret. # #secretName: custom-history-properties eventLogDir: "hdfs:///logs/spark/apps" (6) store: path: /var/log/spark/history (7) emptyDir: {} #pvc: (8) # size: 10Gi # storageClassName: my-storage-class # accessModes: # - ReadWriteOnce ## Monitoring configuration. #monitoring: # # Enables Prometheus metrics export from this product's pods. # exportMetrics: true #properties: # spark.history.store.maxDiskUsage: 16g server: replicas: 1 #resources: # limits: # cpu: "1" # memory: 1Gi # requests: # cpu: 400m # memory: 256Mi #extraMountSecrets: # - mountPath: /etc/spark/extra-secret # options: # containerName: app # secretName: extra-secret ## 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: false1 Пространство имен, используемое Spark History Server. 2 URL образа Spark в вашем репозитории. 3 Настройки Hadoop, взятые из ранее созданного файла hadoop_conf.yaml. 4 Настройки Kerberos. Значение kerberos.hostnameиспользуется для генерации сервисного принципала Spark History Server и HTTP-принципала для SPNEGO.5 Если параметр keytab.createимеет значениеtrue, оператор Kerberos сгенерирует секрет с именем, указанным в параметреkeytab.secretName; если параметрkeytab.secretNameне указан, имя секрета будет иметь формат<metadata.name>-keytab. Если параметрkeytab.createимеет значениеfalse, имеющийся секрет с именемkeytab.secretNameбудет использован для получения keytab-файла.6 URI директории в файловой системе, из которой History Server будет считывать данные (например, hdfs:///var/log/spark/apps,ofs://vol.bucket/spark/apps,s3a://bucket/spark/apps). Директория должна уже существовать. Приложения Spark должны записывать логи в эту же директорию. Принципалу приложения Spark необходимо иметь праваw+xна эту директорию, а принципалу Spark History Server —r+x.7 Локальный путь хранения логов событий. 8 Запрос на хранилище PVC. Должен быть установлен либо параметр pvc, либо параметрemptyDir. -
Вы можете проверить конфигурацию перед ее применением, выполнив команду
applyс флагом--dry-run:$ ./adc apply -f spark-history-server.yaml --dry-run > spark-history-server-render.yamlspark-history-server-render.yaml--- apiVersion: v1 kind: Secret metadata: name: spark-history-server-configs namespace: spark-history-server stringData: core-site.xml: |- <configuration> <property> <name>dfs.client.failover.proxy.provider.adh</name> <value>org.apache.hadoop.hdfs.server.namenode.ha.ObserverReadProxyProvider</value> </property> <property> <name>dfs.client.read.shortcircuit</name> <value>false</value> </property> <property> <name>dfs.datanode.kerberos.principal</name> <value>hdfs-datanode/_HOST@AD.RANGER-TEST</value> </property> <property> <name>dfs.ha.namenodes.adh</name> <value>nn_tsn-adh-k8s-1,nn_tsn-adh-k8s-3</value> </property> <property> <name>dfs.journalnode.kerberos.principal</name> <value>hdfs-journalnode/_HOST@AD.RANGER-TEST</value> </property> <property> <name>dfs.namenode.kerberos.principal</name> <value>hdfs-namenode/_HOST@AD.RANGER-TEST</value> </property> <property> <name>dfs.namenode.rpc-address.adh.nn_tsn-adh-k8s-1</name> <value>tsn-adh-k8s-1.ru-central1.internal:8020</value> </property> <property> <name>dfs.namenode.rpc-address.adh.nn_tsn-adh-k8s-3</name> <value>tsn-adh-k8s-3.ru-central1.internal:8020</value> </property> <property> <name>dfs.nameservices</name> <value>adh</value> </property> <property> <name>fs.defaultFS</name> <value>hdfs://adh</value> </property> <property> <name>hadoop.security.authentication</name> <value>kerberos</value> </property> <property> <name>ozone.om.address.adh.om_tsn-adh-k8s-1</name> <value>tsn-adh-k8s-1.ru-central1.internal:9862</value> </property> <property> <name>ozone.om.address.adh.om_tsn-adh-k8s-2</name> <value>tsn-adh-k8s-2.ru-central1.internal:9862</value> </property> <property> <name>ozone.om.address.adh.om_tsn-adh-k8s-3</name> <value>tsn-adh-k8s-3.ru-central1.internal:9862</value> </property> <property> <name>ozone.om.kerberos.principal</name> <value>om/_HOST@AD.RANGER-TEST</value> </property> <property> <name>ozone.om.nodes.adh</name> <value>om_tsn-adh-k8s-1,om_tsn-adh-k8s-2,om_tsn-adh-k8s-3</value> </property> <property> <name>ozone.om.service.ids</name> <value>adhom</value> </property> </configuration> hive-site.xml: |- <configuration> <property> <name>hive.metastore.kerberos.principal</name> <value>hive/_HOST@AD.RANGER-TEST</value> </property> <property> <name>hive.metastore.sasl.enabled</name> <value>true</value> </property> <property> <name>hive.metastore.uris</name> <value>thrift://tsn-adh-k8s-1.ru-central1.internal:9083</value> </property> <property> <name>metastore.use.SSL</name> <value>false</value> </property> </configuration> type: Opaque --- apiVersion: v1 kind: Secret metadata: name: spark-history-server-spark-history-properties namespace: spark-history-server stringData: history-server.properties: | spark.eventLog.dir hdfs:///logs/spark/apps spark.eventLog.enabled true spark.history.fs.logDirectory hdfs:///logs/spark/apps spark.history.kerberos.enabled true spark.history.kerberos.keytab /opt/spark/kerberos/keytab spark.history.kerberos.principal spark-history/spark-history-server.ru-central1.internal@AD.RANGER-TEST spark.history.provider org.apache.spark.deploy.history.FsHistoryProvider spark.history.store.path /var/log/spark/history spark.history.ui.port 18080 spark.org.apache.spark.filter.AuthenticationFilter.param.kerberos.keytab /opt/spark/kerberos/keytab spark.org.apache.spark.filter.AuthenticationFilter.param.kerberos.name.rules DEFAULT spark.org.apache.spark.filter.AuthenticationFilter.param.kerberos.principal HTTP/spark-history-server.ru-central1.internal@AD.RANGER-TEST spark.org.apache.spark.filter.AuthenticationFilter.param.token.validity 36000 spark.org.apache.spark.filter.AuthenticationFilter.param.type kerberos spark.ui.filters org.apache.spark.filter.AuthenticationFilter type: Opaque --- apiVersion: krb5.arenadata.io/v1alpha1 kind: Keytab metadata: name: spark-history-keytab namespace: spark-history-server spec: items: - labelSelector: env: prod principals: - spark-history/spark-history-server.ru-central1.internal - HTTP/spark-history-server.ru-central1.internal realm: AD.RANGER-TEST rotation: checkInterval: 1h interval: 720h --- apiVersion: spark.arenadata.io/v1alpha1 kind: SparkHistoryServer metadata: name: spark-history-server namespace: spark-history-server spec: properties: secretKey: history-server.properties secretName: spark-history-server-spark-history-properties server: metadata: {} replicas: 1 spec: emptyDirs: - /var/log/spark/history envs: - name: KRB5_CONFIG value: /opt/spark/kerberos/krb5.conf - name: SPARK_DAEMON_JAVA_OPTS value: -Djava.security.krb5.conf=/opt/spark/kerberos/krb5.conf image: hub.arenadata.io/adc-enterprise/spark3:<tag> imagePullPolicy: Always mountSecrets: - mountPath: /etc/hadoop/conf options: containerName: app secretName: spark-history-server-configs - mountPath: /opt/spark/kerberos options: containerName: app readOnly: true secretName: spark-history-keytab ports: - containerPort: 18080 name: http servicePort: 18080 status: {} -
Если манифест корректный, примените конфигурацию Spark History Server:
$ ./adc apply -f spark-history-server.yamlОжидаемый вывод содержит сообщение с подтверждением успеха:
time="20260827130158UTC" level="info" msg="cluster spark-history-server applied to namespace spark-history-server"
-
Проверьте работоспособность подов Spark History Server:
$ kubectl get pods -n spark-history-serverОжидаемый вывод должен быть похож на следующий:
NAME READY STATUS RESTARTS AGE spark-history-server-spark-history-server-0 1/1 Running 0 67s
Шаг 2. Предоставление доступа к веб-интерфейсу Spark History Server
Для доступа к веб-интерфейсу Spark History Server необходимо настроить один из способов публикации сервиса, например, используя балансировщик нагрузки (load balancer) или Ingress-контроллер. Все настройки, связанные с публикацией сервиса, включая DNS, аннотации, параметры Ingress, правила балансировщика и прочие, должны быть указаны в соответствии с вашей инфраструктурой Kubernetes.
-
Получите внешний адрес балансировщика или Ingress-контроллера. Например:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE spark-lb LoadBalancer 10.85.56.180 10.92.40.88 18080:30930/TCP 119s
-
Добавьте следующую строку в файл /etc/hosts на машине, с которой будет производиться доступ:
<lb_ip> spark-history-server.ru-central1.internal
-
Откройте веб-интерфейс Spark History Server в браузере, используя URL http://spark-history-server.ru-central1.internal:18080 (измените протокол на
httpsи номер порта наspec.ssl.port, если используете SSL).
Веб-интерфейс Spark History Server
Веб-интерфейс Spark History Server
Шаг 3. Проверка запуском приложения Spark
-
Создайте приложение Spark согласно инструкции.
-
Измените в конфигурации приложения параметр
spec.eventLogDir. Значение этого параметра и значение параметраspec.eventLogDirв конфигурации Spark History Server должны совпадать:eventLogDir: "hdfs:///logs/spark/apps" -
Запустите приложение Spark:
$ ./adc apply -f spark-application.yaml -
Получите логи задач с помощью команды
curl:$ curl --negotiate -u : http://spark-history-server.ru-central1.internal:18080/api/v1/applicationsВывод:
[ { "id" : "spark-595fd320089e46f4ab2baea0c325caed", "name" : "Spark SQL basic example", "attempts" : [ { "startTime" : "2026-08-31T09:49:06.344GMT", "endTime" : "2026-08-31T09:49:21.897GMT", "lastUpdated" : "2026-08-31T09:49:22.029GMT", "duration" : 15553, "sparkUser" : "spark", "completed" : true, "appSparkVersion" : "3.5.4.4-4.3.0-2", "startTimeEpoch" : 1788169746344, "endTimeEpoch" : 1788169761897, "lastUpdatedEpoch" : 1788169762029 } ] } ]Если в браузере настроена поддержка SPNEGO, можно получить доступ к веб-интерфейсу Spark History Server по URL http://spark-history-server.ru-central1.internal:18080.