Skip to content

Commit cf2432e

Browse files
committed
Update docs
1 parent ad51d1b commit cf2432e

1 file changed

Lines changed: 92 additions & 1 deletion

File tree

docs/modules/spark-k8s/pages/usage-guide/spark-connect.adoc

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,92 @@ spec:
9797
...
9898
```
9999

100+
== Kerberos
101+
102+
NOTE: Kerberos support for Spark Connect is not a first-class feature of the operator. The setup described here is a manual configuration that uses `podOverrides`, `configOverrides`, `envOverrides` and an init container.
103+
104+
A Spark Connect server can authenticate to a Kerberos-secured service, such as a Apache Hive metastore or Apache Hadoop HDFS.
105+
There is, however, an important caveat: the Spark Connect server runs in Spark's `client` deploy mode.
106+
Spark only performs the automatic keytab login (`UserGroupInformation.loginUserFromKeytab`) for YARN, local, Mesos and the Kubernetes _cluster_-mode driver -- *not* for the Kubernetes client mode that the Connect server uses.
107+
As a consequence, setting `spark.kerberos.keytab` and `spark.kerberos.principal` alone does not obtain a Kerberos ticket (TGT), and the SASL/GSSAPI handshake to the metastore fails with `GSS initiate failed` / `Failed to find any Kerberos tgt`.
108+
109+
The workaround is to obtain the ticket yourself with an *init container* that runs `kinit` before the Spark Connect server JVM starts.
110+
The init container reads the keytab and writes a Kerberos credential cache to an `emptyDir` volume that is shared with the `spark` container; the server JVM then picks the ticket up from that cache.
111+
An init container is required because nothing in the client-mode server process performs the login automatically, so the ticket must exist in the credential cache before the JVM opens the metastore connection.
112+
113+
The relevant parts of the `SparkConnectServer` are shown below.
114+
115+
[source,yaml]
116+
----
117+
spec:
118+
server:
119+
envOverrides:
120+
# The shared credential cache populated by the init container. Hadoop's
121+
# UserGroupInformation reads KRB5CCNAME when Kerberos auth is enabled.
122+
KRB5CCNAME: /stackable/krb5/ccache
123+
jvmArgumentOverrides:
124+
add:
125+
# The JVM does NOT read the KRB5_CONFIG environment variable (that is an
126+
# MIT C-library variable). It reads this system property (or /etc/krb5.conf).
127+
- -Djava.security.krb5.conf=/stackable/kerberos/krb5.conf
128+
# The Spark Connect execute thread does not carry the ticket in its
129+
# Subject, so JGSS must fall back to the ambient credential cache.
130+
- -Djavax.security.auth.useSubjectCredsOnly=false
131+
configOverrides:
132+
spark-defaults.conf:
133+
spark.hadoop.hadoop.security.authentication: "kerberos"
134+
spark.hadoop.hive.metastore.uris: "thrift://hive-metastore:9083"
135+
spark.hadoop.hive.metastore.sasl.enabled: "true"
136+
# Use the literal metastore principal, not _HOST (which would resolve to
137+
# the connection host instead of the metastore's service principal).
138+
spark.hadoop.hive.metastore.kerberos.principal: "hive/hive.example.svc.cluster.local@EXAMPLE.COM"
139+
podOverrides:
140+
spec:
141+
initContainers:
142+
- name: kinit
143+
image: oci.stackable.tech/sdp/spark-k8s:4.1.1-stackable0.0.0-dev
144+
command: ["/bin/bash", "-euo", "pipefail", "-c"]
145+
args:
146+
- kinit -kt /stackable/kerberos/keytab spark-connect/spark-connect.example.svc.cluster.local@EXAMPLE.COM
147+
env:
148+
- name: KRB5_CONFIG
149+
value: /stackable/kerberos/krb5.conf
150+
- name: KRB5CCNAME
151+
value: /stackable/krb5/ccache
152+
volumeMounts:
153+
- name: kerberos
154+
mountPath: /stackable/kerberos
155+
- name: krb5-ccache
156+
mountPath: /stackable/krb5
157+
containers:
158+
- name: spark
159+
volumeMounts:
160+
- name: kerberos
161+
mountPath: /stackable/kerberos
162+
- name: krb5-ccache
163+
mountPath: /stackable/krb5
164+
volumes:
165+
- name: krb5-ccache
166+
emptyDir: {}
167+
- name: kerberos
168+
ephemeral:
169+
volumeClaimTemplate:
170+
metadata:
171+
annotations:
172+
secrets.stackable.tech/class: kerberos
173+
secrets.stackable.tech/scope: service=spark-connect
174+
secrets.stackable.tech/kerberos.service.names: spark-connect
175+
spec:
176+
storageClassName: secrets.stackable.tech
177+
accessModes: ["ReadWriteOnce"]
178+
resources:
179+
requests:
180+
storage: "1"
181+
----
182+
183+
The keytab and `krb5.conf` are only required on the server, which is the Spark driver and the only component that talks to the metastore.
184+
Executors that merely read and write data files on (non-kerberized) S3 do not need Kerberos credentials.
185+
100186
== Spark History Server
101187

102188
Unfortunately integration with the Spark History Server is not supported yet.
@@ -112,4 +198,9 @@ The following features are not supported by the Stackable Spark operator yet
112198

113199
== Known Issues
114200

115-
* Dynamically provisioning the iceberg runtime leads to "iceberg.SparkWrite$WriterFactory" ClassNotfoundException when attempting to use it from clients.
201+
* Distributed operations on Apache Iceberg tables fail on the executors.
202+
PySpark calls that trigger a distributed job over an Iceberg table -- for example `DataFrame.collect()` or `DataFrame.count()` -- fail with `java.lang.ClassCastException: cannot assign instance of java.lang.invoke.SerializedLambda to field org.apache.spark.rdd.MapPartitionsRDD.f of type scala.Function3`.
203+
Driver-only operations still work: DDL (`CREATE`/`DROP`), `INSERT` of small data, `DataFrame.show()` of a small result, `SHOW TABLES` and `DESCRIBE`.
204+
The cause is upstream in Spark Connect: executor tasks run under a per-session class loader (which fetches session classes from the driver's artifact server) that cannot deserialize the Iceberg scan closures.
205+
It is independent of how the Iceberg runtime is provisioned -- it reproduces with `--packages`, with the jar placed on the system class path (`/stackable/spark/jars`), with `spark.addArtifact()`, and with combinations of these.
206+
See https://issues.apache.org/jira/browse/SPARK-46032[SPARK-46032] (open) and https://issues.apache.org/jira/browse/SPARK-51537[SPARK-51537] for details.

0 commit comments

Comments
 (0)