feat: support multiple operator in single namespace

This commit is contained in:
2026-07-23 13:51:33 +03:30
parent 494d32c565
commit 7fb18cd45f
12 changed files with 60 additions and 24 deletions

View File

@@ -2,9 +2,9 @@
apiVersion: apiextensions.k8s.io/v1 apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition kind: CustomResourceDefinition
metadata: metadata:
name: flink-jobs.flink.logicamp.tech name: flink-jobs.flink.logicamp.dev
spec: spec:
group: flink.logicamp.tech group: flink.logicamp.dev
names: names:
kind: FlinkJob kind: FlinkJob
plural: flink-jobs plural: flink-jobs
@@ -30,6 +30,9 @@ spec:
type: string type: string
name: name:
type: string type: string
flinkCluster:
type: string
description: "Identifier of the Flink cluster that manages this job. Defaults to the OPERATOR_ID (usually the Helm release name) if not set."
entryClass: entryClass:
type: string type: string
parallelism: parallelism:

View File

@@ -1,5 +1,5 @@
# flink-job-instance.yaml # flink-job-instance.yaml
apiVersion: flink.logicamp.tech/v1alpha1 apiVersion: flink.logicamp.dev/v1alpha1
kind: FlinkJob kind: FlinkJob
metadata: metadata:
name: my-flink-job name: my-flink-job

View File

@@ -27,7 +27,7 @@
{{- if eq .Values.flink.state.checkpoint.storageType "filesystem" }} {{- if eq .Values.flink.state.checkpoint.storageType "filesystem" }}
state.checkpoints.dir: file:///opt/flink/checkpoints/ state.checkpoints.dir: file:///opt/flink/checkpoints/
{{- else if eq .Values.flink.state.checkpoint.storageType "s3" }} {{- else if eq .Values.flink.state.checkpoint.storageType "s3" }}
state.checkpoints.dir: s3://flink/checkpoints/ state.checkpoints.dir: s3://{{ .Release.Name }}-flink/checkpoints/
{{- end }} {{- end }}
{{- if semverCompare ">=2.0.0" .Values.flink.version }} {{- if semverCompare ">=2.0.0" .Values.flink.version }}
state.backend.rocksdb.local-dir: /opt/flink/rocksdb state.backend.rocksdb.local-dir: /opt/flink/rocksdb
@@ -38,7 +38,7 @@
{{- if eq .Values.flink.state.savepoint.storageType "filesystem" }} {{- if eq .Values.flink.state.savepoint.storageType "filesystem" }}
state.savepoints.dir: file:///opt/flink/savepoints/ state.savepoints.dir: file:///opt/flink/savepoints/
{{- else if eq .Values.flink.state.savepoint.storageType "s3" }} {{- else if eq .Values.flink.state.savepoint.storageType "s3" }}
state.savepoints.dir: s3://flink/savepoints/ state.savepoints.dir: s3://{{ .Release.Name }}-flink/savepoints/
{{- end }} {{- end }}
state.backend.incremental: {{ .Values.flink.state.incremental }} state.backend.incremental: {{ .Values.flink.state.incremental }}
rest.profiling.enabled: true rest.profiling.enabled: true

View File

@@ -24,7 +24,8 @@ spec:
initContainers: initContainers:
- name: volume-mount-hack - name: volume-mount-hack
image: {{ .Values.flink.image.repository }}:{{ .Values.flink.image.tag }} image: {{ .Values.flink.image.repository }}:{{ .Values.flink.image.tag }}
runAsUser: 0 securityContext:
runAsUser: 0
command: ["sh", "-c", "chown -R flink {{ .Values.flink.state.ha.dir }}"] command: ["sh", "-c", "chown -R flink {{ .Values.flink.state.ha.dir }}"]
volumeMounts: volumeMounts:
- name: flink-ha - name: flink-ha
@@ -51,17 +52,17 @@ spec:
fieldPath: status.podIP fieldPath: status.podIP
{{- if or (eq .Values.flink.state.checkpoint.storageType "s3") (eq .Values.flink.state.savepoint.storageType "s3") }} {{- if or (eq .Values.flink.state.checkpoint.storageType "s3") (eq .Values.flink.state.savepoint.storageType "s3") }}
- name: S3_ENDPOINT - name: S3_ENDPOINT
value: "http://minio-service:9000" value: "http://{{ .Release.Name }}-minio:9000"
- name: AWS_ACCESS_KEY_ID - name: AWS_ACCESS_KEY_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: {{ .Release.Name }}-flink-secrets name: {{ .Release.Name }}-minio
key: minio_access_key key: root-user
- name: AWS_SECRET_ACCESS_KEY - name: AWS_SECRET_ACCESS_KEY
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: {{ .Release.Name }}-flink-secrets name: {{ .Release.Name }}-minio
key: minio_secret_key key: root-password
{{- end }} {{- end }}
volumeMounts: volumeMounts:
- name: flink-ha - name: flink-ha

View File

@@ -33,17 +33,17 @@ spec:
fieldPath: status.podIP fieldPath: status.podIP
{{- if or (eq .Values.flink.state.checkpoint.storageType "s3") (eq .Values.flink.state.savepoint.storageType "s3") }} {{- if or (eq .Values.flink.state.checkpoint.storageType "s3") (eq .Values.flink.state.savepoint.storageType "s3") }}
- name: S3_ENDPOINT - name: S3_ENDPOINT
value: "http://minio-service:9000" value: "http://{{ .Release.Name }}-minio:9000"
- name: AWS_ACCESS_KEY_ID - name: AWS_ACCESS_KEY_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: {{ .Release.Name }}-flink-secrets name: {{ .Release.Name }}-minio
key: minio_access_key key: root-user
- name: AWS_SECRET_ACCESS_KEY - name: AWS_SECRET_ACCESS_KEY
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: {{ .Release.Name }}-flink-secrets name: {{ .Release.Name }}-minio
key: minio_secret_key key: root-password
{{- end }} {{- end }}
volumeMounts: volumeMounts:
- name: rocksdb-storage - name: rocksdb-storage

View File

@@ -8,8 +8,8 @@ metadata:
spec: spec:
scaleTargetRef: scaleTargetRef:
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: StatefulSet
name: {{ include "flink-kube-operator.fullname" . }} name: {{ .Release.Name }}-flink-operator
minReplicas: {{ .Values.autoscaling.minReplicas }} minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }} maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics: metrics:

View File

@@ -6,7 +6,7 @@ metadata:
{{- include "flink-kube-operator.labels" . | nindent 4 }} {{- include "flink-kube-operator.labels" . | nindent 4 }}
rules: rules:
- apiGroups: - apiGroups:
- flink.logicamp.tech # API group of the FlinkJob CRD - flink.logicamp.dev # API group of the FlinkJob CRD
resources: resources:
- flink-jobs # The plural name of your custom resource - flink-jobs # The plural name of your custom resource
verbs: verbs:

View File

@@ -44,13 +44,15 @@ spec:
containerPort: {{ .Values.service.port }} containerPort: {{ .Values.service.port }}
protocol: TCP protocol: TCP
env: env:
- name: OPERATOR_ID
value: {{ .Values.operatorId | default .Release.Name }}
- name: FLINK_API_URL - name: FLINK_API_URL
value: {{ .Release.Name }}-flink-job-manager:8081 value: {{ .Release.Name }}-flink-job-manager:8081
- name: NAMESPACE - name: NAMESPACE
value: "{{ .Release.Namespace }}" value: "{{ .Release.Namespace }}"
{{- if eq .Values.flink.state.savepoint.storageType "s3" }} {{- if eq .Values.flink.state.savepoint.storageType "s3" }}
- name: SAVEPOINT_PATH - name: SAVEPOINT_PATH
value: s3://flink/savepoints/ value: s3://{{ .Release.Name }}-flink/savepoints/
- name: S3_ENDPOINT - name: S3_ENDPOINT
value: "http://{{ .Release.Name }}-minio:9000" value: "http://{{ .Release.Name }}-minio:9000"
- name: AWS_ACCESS_KEY_ID - name: AWS_ACCESS_KEY_ID

View File

@@ -7,11 +7,11 @@ replicaCount: 1
# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ # This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/
image: image:
repository: lcr.logicamp.tech/library/flink-kube-operator repository: logicampdev/flink-kube-operator
# This sets the pull policy for images. # This sets the pull policy for images.
pullPolicy: Always pullPolicy: Always
# Overrides the image tag whose default is the chart appVersion. # Overrides the image tag whose default is the chart appVersion.
tag: latest tag: v1.3.0
# This is for the secretes for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ # This is for the secretes for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
imagePullSecrets: [] imagePullSecrets: []
@@ -105,6 +105,11 @@ autoscaling:
config: config:
flinkApiUrl: flink:8081 flinkApiUrl: flink:8081
# Identifier for this operator instance. Used to partition FlinkJob CRs via
# label selector. Defaults to the Helm release name if left empty.
# Set explicitly when you need stable names across upgrades.
operatorId: ""
nodeSelector: {} nodeSelector: {}
tolerations: [] tolerations: []
@@ -118,7 +123,7 @@ flink:
# Override to "1.20" for backward compatibility with Flink 1.20.x. # Override to "1.20" for backward compatibility with Flink 1.20.x.
version: "2.3" version: "2.3"
image: image:
repository: pcr.pishgaman.top/library/flink-kube-operator/flink repository: logicampdev/flink-kube-operator-flink
tag: 2.3.0-java21-v1.3.0 tag: 2.3.0-java21-v1.3.0
parallelism: parallelism:

View File

@@ -12,6 +12,7 @@ import (
type FlinkJobSpec struct { type FlinkJobSpec struct {
Key string `json:"key"` Key string `json:"key"`
Name string `json:"name"` Name string `json:"name"`
FlinkCluster string `json:"flinkCluster"`
Parallelism int `json:"parallelism"` Parallelism int `json:"parallelism"`
JarURI string `json:"jarUri"` JarURI string `json:"jarUri"`
JarURIBasicAuthUsername *string `json:"jarURIBasicAuthUsername"` JarURIBasicAuthUsername *string `json:"jarURIBasicAuthUsername"`

View File

@@ -6,7 +6,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
) )
const GroupName = "flink.logicamp.tech" const GroupName = "flink.logicamp.dev"
const GroupVersion = "v1alpha1" const GroupVersion = "v1alpha1"
const ResourceName = "flink-jobs" const ResourceName = "flink-jobs"

View File

@@ -3,6 +3,7 @@ package managed_job
import ( import (
"flink-kube-operator/internal/crd" "flink-kube-operator/internal/crd"
"flink-kube-operator/internal/crd/v1alpha1" "flink-kube-operator/internal/crd/v1alpha1"
"os"
"time" "time"
"flink-kube-operator/pkg" "flink-kube-operator/pkg"
@@ -73,6 +74,8 @@ func (mgr *Manager) cycle(client *api.Client, crdInstance *crd.Crd) {
} }
pkg.Logger.Debug("[manager] [cycle] overviews", zap.Any("overviews", jobManagerJobOverviews)) pkg.Logger.Debug("[manager] [cycle] overviews", zap.Any("overviews", jobManagerJobOverviews))
operatorId := os.Getenv("OPERATOR_ID")
// Loop over job definitions as Kubernetes CRD // Loop over job definitions as Kubernetes CRD
for _, uid := range crd.GetAllJobKeys() { for _, uid := range crd.GetAllJobKeys() {
if lo.Contains(mgr.processingJobsIds, uid) { if lo.Contains(mgr.processingJobsIds, uid) {
@@ -82,6 +85,27 @@ func (mgr *Manager) cycle(client *api.Client, crdInstance *crd.Crd) {
// Get job definition from Kubernetes CRD // Get job definition from Kubernetes CRD
def := crd.GetJob(uid) def := crd.GetJob(uid)
// Auto-claim: if flinkCluster is empty, set it to this operator's ID
if def.Spec.FlinkCluster == "" {
pkg.Logger.Info("[manager] auto-claiming unowned job", zap.String("name", def.GetName()))
crdInstance.Patch(def.GetUID(), map[string]interface{}{
"spec": map[string]interface{}{
"flinkCluster": operatorId,
},
})
def.Spec.FlinkCluster = operatorId
}
// Skip CRs that belong to another operator
if def.Spec.FlinkCluster != operatorId {
pkg.Logger.Debug("[manager] skipping job owned by another operator",
zap.String("name", def.GetName()),
zap.String("flinkCluster", def.Spec.FlinkCluster),
zap.String("operatorId", operatorId),
)
continue
}
mgr.processingJobsIds = append(mgr.processingJobsIds, uid) mgr.processingJobsIds = append(mgr.processingJobsIds, uid)
// Check if job exists in manager managed jobs // Check if job exists in manager managed jobs