Platform-Wide Deployment Defaults
On this page
This section explains how to set deployment and session cluster defaults for an entire Ververica Platform installation through Helm values, so that every deployment created afterwards inherits them without per-deployment configuration.
Namespace-level defaults, configured in the UI under Configurations and the Deployment Defaults tab, are described in Defaults. Use platform-wide defaults when a setting must apply to every namespace in the installation and must be part of the install manifest rather than applied after installation.
Available Values
All platform-wide default blocks are set under the vvp-appmanager key in values.yaml. Each block is a YAML string, so it is written with the |- block scalar.
systemDeploymentDefaults and systemSessionClusterDefaults are also exposed as values, but they carry platform-managed content such as the log, temporary, and credential volume mounts and the pod security context. Overriding either value replaces the whole block, which removes that content. Do not set them unless you intend to reproduce the shipped content in full.
Restate the Platform Volume Mounts When You Set volumeMounts
systemDeploymentDefaults mounts three directories that Flink requires at runtime:
kubernetes.pods.volumeMounts replaces this list rather than merging with it. Setting volumeMounts in globalDeploymentDefaults therefore removes all three mounts from every Flink pod unless you restate them.
On OpenShift, removing the flink-logs mount prevents Flink from starting at all. The restricted and restricted-v2 security context constraints assign an arbitrary user ID, which cannot write to /opt/flink/log inside the container image. The JVM fails before Flink initializes with Error opening log file '/opt/flink/log/jobmanager-gc.log': Permission denied, and the JobManager enters CrashLoopBackOff. On other Kubernetes distributions the same configuration usually appears to work, because the container runs as the image's own user, which owns that directory. Restate the mounts on every distribution so the configuration behaves identically.
Every volumeMounts list on this page therefore includes the three platform mounts alongside the mount being added. Reuse this block whenever you set volumeMounts:
1- name: flink-logs
2 volume:
3 name: flink-logs
4 emptyDir: {}
5 volumeMount:
6 name: flink-logs
7 mountPath: /opt/flink/log
8- name: flink-tmp-dir
9 volume:
10 name: flink-tmp-dir
11 emptyDir: {}
12 volumeMount:
13 name: flink-tmp-dir
14 mountPath: /opt/flink/flink-tmp-dir
15- name: flink-sts-dir
16 volume:
17 name: flink-sts-dir
18 emptyDir: {}
19 volumeMount:
20 name: flink-sts-dir
21 mountPath: /flink/sts-secrets/sts-credentialTo confirm the mounts survived, read them back from a running Flink pod rather than from the values file:
1kubectl get pod <JOBMANAGER_POD> -n <FLINK_NAMESPACE> \
2 -o jsonpath='{range .spec.containers[0].volumeMounts[*]}{.mountPath}{"\n"}{end}'/opt/flink/log, /opt/flink/flink-tmp-dir, and /flink/sts-secrets/sts-credential must all appear.
Streaming and Batch Halves
globalDeploymentDefaults has two top-level keys:
specapplies to streaming deployments.batchSpecapplies to deployments that setbatchMode: true.
The shipped default contains spec only. Batch deployments inherit nothing from this block until batchSpec is added. If batch workloads require the same resources, Flink configuration, or volume mounts as streaming workloads, define both keys.
The spec key is required. A block that contains only batchSpec is rejected at startup, and AppManager reports that vvp.globalDeploymentDefaults.spec must not be null.
1vvp-appmanager:
2 globalDeploymentDefaults: |-
3 spec: # streaming deployments
4 template:
5 spec:
6 resources:
7 jobmanager:
8 cpu: 1
9 memory: 1Gi
10 taskmanager:
11 cpu: 1
12 memory: 2Gi
13 upgradeStrategy:
14 kind: STATELESS
15 batchSpec: # batch deployments
16 template:
17 spec:
18 resources:
19 jobmanager:
20 cpu: 1
21 memory: 1Gi
22 taskmanager:
23 cpu: 1
24 memory: 2GiPlace upgradeStrategy at the spec level, as a sibling of template. Nesting it under spec.template.spec fails validation and prevents AppManager from starting.
Example: Trust a Private Certificate Authority
This example delivers a private certificate authority trust store to every JobManager and TaskManager in the installation. It is the recommended way to reach services that present certificates signed by an internal authority, such as object storage over HTTPS, Kafka over SASL_SSL, or a schema registry.
Two things are required, and both are set in the same block:
kubernetes.pods.volumeMountsmounts the trust store into the pod.flinkConfigurationtells the JVM to use it.
Mounting the file without setting the JVM options leaves the pod with a trust store it never reads, and connections fail with a PKIX path validation error.
Step 1: Create the Trust Store Secret
Create a Java trust store containing the certificate authority, and store it in a Secret in the namespace where Flink pods run. The platform references this Secret; it does not create it.
1keytool -importcert -noprompt -trustcacerts \
2 -alias internal-ca \
3 -file internal-ca.pem \
4 -keystore truststore.jks \
5 -storepass changeit
6
7kubectl create secret generic flink-truststore \
8 --from-file=truststore.jks=truststore.jks \
9 --namespace <FLINK_NAMESPACE>The trust store must contain every certificate authority the jobs need to trust. If object storage and Kafka are signed by different authorities, import both into the same trust store. A trust store holding only one of them succeeds against that service and fails against the other.
Step 2: Reference It in the Deployment Defaults
1vvp-appmanager:
2 globalDeploymentDefaults: |-
3 spec:
4 template:
5 spec:
6 flinkConfiguration:
7 env.java.opts.jobmanager: "-Djavax.net.ssl.trustStore=/certs/truststore.jks -Djavax.net.ssl.trustStorePassword=changeit"
8 env.java.opts.taskmanager: "-Djavax.net.ssl.trustStore=/certs/truststore.jks -Djavax.net.ssl.trustStorePassword=changeit"
9 kubernetes:
10 pods:
11 volumeMounts:
12 - name: flink-ca
13 volume:
14 name: flink-ca
15 secret:
16 secretName: flink-truststore
17 volumeMount:
18 name: flink-ca
19 mountPath: /certs
20 readOnly: true
21 - name: flink-logs
22 volume:
23 name: flink-logs
24 emptyDir: {}
25 volumeMount:
26 name: flink-logs
27 mountPath: /opt/flink/log
28 - name: flink-tmp-dir
29 volume:
30 name: flink-tmp-dir
31 emptyDir: {}
32 volumeMount:
33 name: flink-tmp-dir
34 mountPath: /opt/flink/flink-tmp-dir
35 - name: flink-sts-dir
36 volume:
37 name: flink-sts-dir
38 emptyDir: {}
39 volumeMount:
40 name: flink-sts-dir
41 mountPath: /flink/sts-secrets/sts-credential
42 upgradeStrategy:
43 kind: STATELESS
44 batchSpec:
45 template:
46 spec:
47 flinkConfiguration:
48 env.java.opts.jobmanager: "-Djavax.net.ssl.trustStore=/certs/truststore.jks -Djavax.net.ssl.trustStorePassword=changeit"
49 env.java.opts.taskmanager: "-Djavax.net.ssl.trustStore=/certs/truststore.jks -Djavax.net.ssl.trustStorePassword=changeit"
50 kubernetes:
51 pods:
52 volumeMounts:
53 - name: flink-ca
54 volume:
55 name: flink-ca
56 secret:
57 secretName: flink-truststore
58 volumeMount:
59 name: flink-ca
60 mountPath: /certs
61 readOnly: true
62 - name: flink-logs
63 volume:
64 name: flink-logs
65 emptyDir: {}
66 volumeMount:
67 name: flink-logs
68 mountPath: /opt/flink/log
69 - name: flink-tmp-dir
70 volume:
71 name: flink-tmp-dir
72 emptyDir: {}
73 volumeMount:
74 name: flink-tmp-dir
75 mountPath: /opt/flink/flink-tmp-dir
76 - name: flink-sts-dir
77 volume:
78 name: flink-sts-dir
79 emptyDir: {}
80 volumeMount:
81 name: flink-sts-dir
82 mountPath: /flink/sts-secrets/sts-credentialStep 3: Apply and Restart AppManager
1helm upgrade --install <RELEASE_NAME> \
2 oci://registry.ververica.cloud/platform-charts/ververica-platform \
3 --version 3.1.2 \
4 --namespace vvp-system \
5 --values values.yamlThe value is read when AppManager starts and applies to deployments created afterwards. Existing deployments keep the configuration they were created with.
Step 4: Verify
Create a deployment that sets no flinkConfiguration and no kubernetes block of its own, so that anything present in the pod must have been inherited. Then confirm the trust store is present inside the container:
1kubectl exec -n <FLINK_NAMESPACE> <JOBMANAGER_POD> -c flink-main-container -- ls -l /certsConfirm the JVM options reached the effective configuration:
1kubectl exec -n <FLINK_NAMESPACE> <JOBMANAGER_POD> -c flink-main-container -- \
2 grep trustStore /opt/flink/conf/flink-conf.yamlIf the mount is present and the JVM options are set, the JobManager log contains no PKIX path building failed entries.
Example: Kafka over SASL_SSL
With the trust store from the previous example in place, a Flink SQL table reaches Kafka over SASL_SSL by referencing the mounted path.
1CREATE TABLE orders (
2 id INT,
3 amount INT
4) WITH (
5 'connector' = 'kafka',
6 'topic' = 'orders',
7 'format' = 'json',
8 'properties.bootstrap.servers' = 'kafka.example.internal:9094',
9 'properties.security.protocol' = 'SASL_SSL',
10 'properties.sasl.mechanism' = 'PLAIN',
11 'properties.sasl.jaas.config' = 'org.apache.flink.kafka.shaded.org.apache.kafka.common.security.plain.PlainLoginModule required username="flinkuser" password="<PASSWORD>";',
12 'properties.ssl.truststore.location' = '/certs/truststore.jks',
13 'properties.ssl.truststore.password' = 'changeit',
14 'properties.ssl.endpoint.identification.algorithm' = 'HTTPS'
15);The Kafka connector is shaded. properties.sasl.jaas.config must reference org.apache.flink.kafka.shaded.org.apache.kafka.common.security.plain.PlainLoginModule. Using the unshaded class name fails with No LoginModule found for org.apache.kafka.common.security.plain.PlainLoginModule.
Session Cluster Defaults
globalSessionClusterDefaults applies to session clusters. Unlike the deployment block, it has a single spec key and no batch half.
1vvp-appmanager:
2 globalSessionClusterDefaults: |-
3 spec:
4 flinkConfiguration:
5 env.java.opts.jobmanager: "-Djavax.net.ssl.trustStore=/certs/truststore.jks -Djavax.net.ssl.trustStorePassword=changeit"
6 kubernetes:
7 pods:
8 volumeMounts:
9 - name: flink-ca
10 volume:
11 name: flink-ca
12 secret:
13 secretName: flink-truststore
14 volumeMount:
15 name: flink-ca
16 mountPath: /certs
17 readOnly: true
18 - name: flink-logs
19 volume:
20 name: flink-logs
21 emptyDir: {}
22 volumeMount:
23 name: flink-logs
24 mountPath: /opt/flink/log
25 - name: flink-tmp-dir
26 volume:
27 name: flink-tmp-dir
28 emptyDir: {}
29 volumeMount:
30 name: flink-tmp-dir
31 mountPath: /opt/flink/flink-tmp-dir
32 - name: flink-sts-dir
33 volume:
34 name: flink-sts-dir
35 emptyDir: {}
36 volumeMount:
37 name: flink-sts-dir
38 mountPath: /flink/sts-secrets/sts-credentialSession cluster defaults are applied when the session cluster is created. Changing the value affects session clusters created afterwards, and existing session clusters keep the configuration they were created with. To apply a changed default to a running session cluster, recreate it.
Precedence
Settings are resolved from the broadest scope to the most specific. A more specific layer overrides a less specific one:
globalDeploymentDefaults(specorbatchSpec), from Helm valuesflinkConfigurationStreamandflinkConfigurationBatch, from Helm values- Namespace-level defaults, set through the UI or the API
- The deployment's own specification
Two behaviors are worth noting when the same setting is defined at more than one layer:
flinkConfigurationmerges across layers. Keys from a broader layer that the narrower layer does not set are retained.kubernetes.pods.volumeMountsandresourcesreplace. The narrower layer's value is used in full, and the broader layer's value is discarded.
Because volumeMounts replaces rather than merges, a namespace-level default containing an empty volumeMounts list removes a volume mount defined in the platform-wide defaults. The deployment starts normally and the failure appears later, when a connection that needs the trust store cannot validate the certificate. When namespace-level defaults are used alongside platform-wide volume mounts, either omit kubernetes from the namespace-level object entirely or repeat the required mounts in it.
Which Value to Use for Flink Configuration
Flink configuration keys can be set either in globalDeploymentDefaults.spec.template.spec.flinkConfiguration or in flinkConfigurationStream and flinkConfigurationBatch. The blocks differ in two ways:
globalDeploymentDefaultsalso acceptskubernetes.pods,resources, andupgradeStrategy. TheflinkConfiguration*blocks accept Flink configuration keys only.- The
flinkConfiguration*blocks ship with platform-tuned content, including the checkpointing interval, high availability, the metrics reporters and their factory classes, and leader election timings. Overriding either block replaces all of it.
Because overriding a value replaces the whole block, setting Flink configuration in globalDeploymentDefaults is the safer option: the shipped content of that block is limited to resources and upgradeStrategy, which are straightforward to restate. Overriding flinkConfigurationStream requires reproducing every shipped key that is still needed, and omitting the metrics reporter keys stops metrics from being served.
Verifying the Effective Defaults
Read the effective platform-wide defaults back from the API rather than inspecting the values file, so that the running configuration is confirmed:
1curl -s \
2 -H "Authorization: Bearer <API_TOKEN>" \
3 -H "workspace: <WORKSPACE>" \
4 https://<PLATFORM_HOST>/api/v1/global-deployment-defaultsTo read the namespace-level defaults for a deployment type:
1curl -s \
2 -H "Authorization: Bearer <API_TOKEN>" \
3 -H "workspace: <WORKSPACE>" \
4 https://<PLATFORM_HOST>/api/v1/namespaces/<NAMESPACE>/deployment-defaults/STREAMAPI requests require both an Authorization header and a workspace header. A request without the workspace header is rejected with 403.