Dennis-Mircea Ciupitu created FLINK-41375:
---------------------------------------------

             Summary: JobManager crash loops are detected only in the back-off 
phase and reported without the termination reason
                 Key: FLINK-41375
                 URL: https://issues.apache.org/jira/browse/FLINK-41375
             Project: Flink
          Issue Type: Bug
          Components: Kubernetes Operator
            Reporter: Dennis-Mircea Ciupitu


h1. Problem

When the JobManager container keeps dying (for example, OOMKilled reason), what 
the operator reports depends on the moment it happens to look at the pod, and 
it never says why the container died.

The observer only recognises a crash loop while the kubelet is backing off 
({{{}state.waiting.reason=CrashLoopBackOff{}}}). Between 2 kills, while the 
container is {{running}} again, it reports {{DEPLOYING}} as if everything were 
fine, even though the pod already says 
{{{}lastState.terminated.reason=OOMKilled{}}}, {{exitCode=137}} and counts the 
restarts.

The actual problem is that the {{OOMKilled}} entry in 
{{CONTAINER_ERROR_REASONS}} never matches on the current observation logic. 
Kubernetes puts that reason under {{{}terminated{}}}, not under 
{{{}waiting{}}}. The longer the JobManager runs before each kill, the more 
often the operator says {{{}DEPLOYING{}}}.

When it does detect the loop, the error and the event are a copy of the 
kubelet's back-off sentence with the pod name. The reason and the exit code are 
nowhere in the resource. And because that sentence changes with every back-off 
step and every pod, each detection produces a new event instead of counting up 
the existing one.

On a deployment that was already stable, the {{DEPLOYING}} sample also wipes 
{{{}status.error{}}}, so the resource alternates between an error and no error 
at all.
h1. Reproduction

{{examples/basic.yaml}} with the below extra line + "1024m" as JM spec resource 
memory:
{code:yaml}
flinkConfiguration:

  env.java.opts.jobmanager: "-Xms1200m -Xmx1200m -XX:+AlwaysPreTouch"
{code}
{code:java}
kubectl get pods
NAME                                         READY   STATUS      RESTARTS   AGE
basic-example-65774988d7-tzv74               0/1     OOMKilled   0          3s

kubectl get pods
NAME                                         READY   STATUS             
RESTARTS     AGE
basic-example-65774988d7-tzv74               0/1     CrashLoopBackOff   2 (3s 
ago)   20s
{code}
Operator log:
{code}
2026-11-07 09:59:52,330 INFO  ecutor-flinkdeploymentcontroller-350 
.r.d.AbstractFlinkResourceReconciler Deploying for the first time
2026-11-07 09:59:52,335 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.operator.listener.AuditUtils >>> Status[Job]      | Info    | UPGRADING 
      | The resource is being upgraded 
2026-11-07 09:59:52,336 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.o.r.d.ApplicationReconciler Assigning JobId override to 
5efdcfec84cb50f1fca3c5aecd224f0b
2026-11-07 09:59:52,343 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.operator.listener.AuditUtils >>> Event[Job]       | Info    | SUBMIT    
      | Starting deployment
2026-11-07 09:59:52,343 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.o.s.AbstractFlinkService Deploying application cluster
2026-11-07 09:59:52,343 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.o.service.NativeFlinkService Deploying application cluster
2026-11-07 09:59:52,343 INFO  ecutor-flinkdeploymentcontroller-350 
f.c.d.a.c.ApplicationClusterDeployer Submitting application in 'Application 
Mode'.
2026-11-07 09:59:52,346 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.r.u.c.m.ProcessMemoryUtils The derived from fraction jvm overhead memory 
(102.400mb (107374184 bytes)) is less than its min value 192.000mb (201326592 
bytes), min value will be used instead
2026-11-07 09:59:52,392 INFO  ecutor-flinkdeploymentcontroller-350 
.a.DefaultKubernetesArtifactUploader Local artifact uploading is disabled. Set 
'kubernetes.artifacts.local-upload-enabled' to enable.
2026-11-07 09:59:52,392 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.utils.KubernetesUtils Kubernetes deployment requires a fixed port. 
Configuration blob.server.port will be set to 6124
2026-11-07 09:59:52,393 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.utils.KubernetesUtils Kubernetes deployment requires a fixed port. 
Configuration taskmanager.rpc.port will be set to 6122
2026-11-07 09:59:52,401 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.configuration.Configuration Config uses fallback configuration key 
'kubernetes.service-account' instead of key 
'kubernetes.jobmanager.service-account'
2026-11-07 09:59:52,479 WARN  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.KubernetesClusterDescriptor Please note that Flink client 
operations(e.g. cancel, list, stop, savepoint, etc.) won't work from outside 
the Kubernetes cluster since 'kubernetes.rest-service.exposed.type' has been 
set to ClusterIP.
2026-11-07 09:59:52,480 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.KubernetesClusterDescriptor Create flink application cluster 
basic-example successfully, JobManager Web Interface: 
http://basic-example-rest.default:8081
2026-11-07 09:59:52,480 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.o.service.NativeFlinkService Application cluster successfully deployed
2026-11-07 09:59:52,486 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.operator.listener.AuditUtils >>> Status[Job]      | Info    | DEPLOYED  
      | The resource is deployed/submitted to Kubernetes, but it’s not yet 
considered to be stable and might be rolled back in the future 
2026-11-07 09:59:52,486 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.o.o.d.ApplicationObserver Observing JobManager deployment. Previous 
status: DEPLOYING
2026-11-07 09:59:52,489 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.o.o.d.ApplicationObserver JobManager is being deployed
2026-11-07 09:59:52,491 INFO  ecutor-flinkdeploymentcontroller-350 
o.a.f.k.o.a.state.ConfigMapView Creating ConfigMap autoscaler-basic-example
2026-11-07 09:59:52,492 INFO  ecutor-flinkdeploymentcontroller-350 
.r.d.AbstractFlinkResourceReconciler Resource fully reconciled, nothing to do...
2026-11-07 10:00:02,495 INFO  ecutor-flinkdeploymentcontroller-369 
o.a.f.k.o.o.d.ApplicationObserver Observing JobManager deployment. Previous 
status: DEPLOYING
2026-11-07 10:00:02,508 INFO  ecutor-flinkdeploymentcontroller-369 
o.a.f.k.operator.listener.AuditUtils >>> Event[Job]       | Warning | 
CRASHLOOPBACKOFF | [flink-main-container] back-off 10s restarting failed 
container=flink-main-container 
pod=basic-example-65774988d7-tzv74_default(b57eb99c-a3cf-4fad-8db0-d7b144669a0d)
{code}
This is the error the resource keeps reporting. Nothing in it says why the 
container died:
{code:java}
kubectl get flinkdep basic-example -o jsonpath='{.status.error}'
{"type":"org.apache.flink.kubernetes.operator.exception.DeploymentFailedException","message":"[flink-main-container]
 back-off 10s restarting failed container=flink-main-container 
pod=basic-example-65774988d7-q8x7d_default(deccff18-576e-4a16-aeb4-6efaf894eb9a)","stackTrace":"org.apache.flink.kubernetes.operator.exception.DeploymentFailedException:
 [flink-main-container] back-off 10s restarting failed 
container=flink-main-container 
pod=basic-example-65774988d7-q8x7d_default(deccff18-576e-4a16-aeb4-6efaf894eb9a)\n\tat
 
org.apache.flink.kubernetes.operator.exception.DeploymentFailedException.forContainerStatus(DeploymentFailedException.java:74)\n\tat
 
org.apache.flink.kubernetes.operator.observer.deployment.AbstractFlinkDeploymentObserver.checkContainerError(AbstractFlinkDeploymentObserver.java:251)\n\tat
 java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown 
Source)\n\tat 
java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Unknown 
Source)\n\tat java.base/java.util.stream.ReferencePipeline$Head.forEach(Unknown 
Source)\n\tat 
org.apache.flink.kubernetes.operator.observer.deployment.AbstractFlinkDeploymentObserver.checkContainerErrors(AbstractFlinkDeploymentObserver.java:238)\n\tat
 
org.apache.flink.kubernetes.operator.observer.deployment.AbstractFlinkDeploymentObserver.observeJmDeployment(AbstractFlinkDeploymentObserver.java:193)\n\tat
 
org.apache.flink.kubernetes.operator.observer.deployment.AbstractFlinkDeploymentObserver.observeInternal(AbstractFlinkDeploymentObserver.java:89)\n\tat
 
org.apache.flink.kubernetes.operator.observer.AbstractFlinkResourceObserver.observe(AbstractFlinkResourceObserver.java:49)\n\tat
 
org.apache.flink.kubernetes.operator.controller.FlinkDeploymentController.reconcile(FlinkDeploymentController.java:145)\n\tat
 
org.apache.flink.kubernetes.operator.controller.FlinkDeploymentController.reconcile(FlinkDeploymentController.java:59)\n\tat
 
io.javaoperatorsdk.operator.processing.Controller$1.execute(Controller.java:191)\n\tat
 
io.javaoperatorsdk.operator.processing.Controller$1.execute(Controller.java:147)\n\tat
 
org.apache.flink.kubernetes.operator.metrics.OperatorJosdkMetrics.timeControllerExecution(OperatorJosdkMetrics.java:82)\n\tat
 
io.javaoperatorsdk.operator.processing.Controller.reconcile(Controller.java:146)\n\tat
 
io.javaoperatorsdk.operator.processing.event.Rec","additionalMetadata":{"reason":"CrashLoopBackOff"},"throwableList":[]}
{code}
Sampled every 5 s over two runs (first deployment, and a stable deployment 
whose JobManager starts crash-looping): every observe that lands in the 
{{running}} window reports {{DEPLOYING}} with 
{{{}lastState.terminated.reason=OOMKilled{}}}; on the stable deployment it also 
wipes {{status.error}} for one progress-check interval; two 
{{CrashLoopBackOff}} events in six minutes per run, one per back-off step.
h1. Expected
 * A JobManager container that has already died with a non-zero exit code and 
been restarted is reported as crash-looping whenever the operator looks at it, 
whether the kubelet is currently backing off or the container is up again 
between two kills.
 * {{status.error}} and the event name the termination reason and exit code, 
and the text does not change with the back-off timer or the pod name, so one 
event is counted up instead of a new one per step.
 * The error is not cleared until the JobManager is actually {{{}READY{}}}.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to