feat: support multiple operator in single namespace
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ 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 }}
|
||||||
|
securityContext:
|
||||||
runAsUser: 0
|
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:
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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"`
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user