Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pod controlled by a Job does not exit after after main container completes #1869

Closed
maorfr opened this issue Nov 22, 2018 · 27 comments
Closed

Comments

@maorfr
Copy link

maorfr commented Nov 22, 2018

Bug Report

What is the issue?

Pods that are controlled by Jobs are not terminating when the main container exits

How can it be reproduced?

Create a job with linkerd sidecar container

Logs, error output, etc

main container logs are as usual, sidecar container logs are as usual

linkerd check output

Status check results are [ok]

Environment

  • Kubernetes Version: 1.11.4
  • Cluster Environment: AWS (kops)
  • Host OS: Container Linux by CoreOS 1911.3.0 (Rhyolite)
  • Linkerd version: edge-18.11.2 (client and server)

Possible solution

I think that when a container within a pod controlled by a Job completes, the sidecar should exit as well.

Additional context

The sidecar was created using linkerd inject

@grampelberg
Copy link
Contributor

We need something from kubernetes/kubernetes#25908 to move forward with this.

@stale
Copy link

stale bot commented Mar 3, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Mar 3, 2019
@stale stale bot closed this as completed Mar 18, 2019
@christianhuening
Copy link
Contributor

whoop, reopen.
@grampelberg would it make sense to change the MutatingWebhookConfiguration for the time being to only inject Deployment's & Daemonset's pods? I am taking out StatefulSets since there's also this bug: #2266

@kivagant-ba
Copy link

Should this really be closed?

@christianhuening
Copy link
Contributor

I still deem this problematic, too

@kivagant-ba
Copy link

@christianhuening , by a chance, do you know any workarounds better than this one:
kubernetes/kubernetes#25908 (comment)
?

@christianhuening
Copy link
Contributor

christianhuening commented Aug 27, 2019

We just don't inject Jobs atm. This is not an issue right now, since we only use jobs for initialization when deploying environments.

@kivagant-ba
Copy link

Do you know if it's possible to blacklist jobs on the namespace level or somewhere in L5d configuration?

@christianhuening
Copy link
Contributor

provide the annotation and set it to disabled on the job's pod spec

@kivagant-ba
Copy link

This requires direct access to each Job specification (or a custom admission controller). Thank you for your feedback.

@alexklibisz
Copy link

alexklibisz commented Mar 5, 2020

I believe I found a solution to this that doesn't require waiting for a new k8s feature or significantly altering the main job process.

Pods have a shareProcessNamespace setting. This lets containers in a pod see and kill the processes running in other containers.

The solution: Assume you can identify the process id for the main workload in your job/cronjob. Then you can add your own sidecar container that checks to see if your job process is running, sleeps, and repeats until the job process exits. Once it exits, you kill the linkerd2-proxy process, which makes that container exit, and successfully ends the job/cronjob.

Here's an example which assumes your job process is called java. I assume it would work for any other process, you just have to be able to return the process id by running pgrep <name-of-my-process>.

apiVersion: batch/v1
kind: Job
metadata:
  name: my-java-job-that-uses-linkerd2-injection
spec:
  template:
    metadata:
      annotations:
        # Inject linkerd2 proxy sidecar.
        linkerd.io/inject: enabled
    spec:
      containers:
        # This is your main workload. In this case lets assume it's a java process.
        - name: job
          image: com.foo.bar/my-java-job:latest
          resources:
            limits:
              memory: ...
              cpu: ...
            requests:
              memory: ...
              cpu: ...
        # This sidecar monitors the java process that runs the main job and kills the linkerd-proxy once java exits.
        # Note that it's necessary to set `shareProcessNamespace: true` in `spec.template.spec` for this to work.
        - name: linkerd-terminator
          image: ubuntu:19.04
          command:
            - sh
            - "-c"
            - |
              /bin/bash <<'EOSCRIPT'
              set -e
              # Check for the java process and sleep 5 seconds until the java process exits.
              while true; do pgrep java || break; sleep 5; done
              # After the java process exits, 
              kill $(pgrep linkerd2-proxy)
              EOSCRIPT
          resources:
            limits:
              cpu: 10m
              memory: 20M
            requests:
              cpu: 10m
              memory: 20M
      shareProcessNamespace: true # Don't forget this part!

For context, we are running k8s version 1.15.7.

@Enrico2
Copy link

Enrico2 commented Mar 9, 2020

@alexklibisz I tried this approach with a deployment for a similar issue (#3751), and the kill command is not permitted:

/bin/bash: line 5: kill: (405) - Operation not permitted

The base image is ubuntu:bionic-20200112

did you encounter any permissions issues you had to work around?

@alexklibisz
Copy link

@alexklibisz I tried this approach with a deployment for a similar issue (#3751), and the kill command is not permitted:

/bin/bash: line 5: kill: (405) - Operation not permitted

The base image is ubuntu:bionic-20200112

did you encounter any permissions issues you had to work around?

IIRC, I saw some permission errors when I forgot to add the shareProcessNamespace setting.

@Enrico2
Copy link

Enrico2 commented Mar 9, 2020

I do have that setting, the termination process can see the pid of the other process. Afaict, the issue is that linkerd-proxy and the termination process are run by different users.

@alexklibisz
Copy link

I do have that setting, the termination process can see the pid of the other process. Afaict, the issue is that linkerd-proxy and the termination process are run by different users.

In my case, the java process was definitely owned by a non-root user (user id 1001 IIRC) and the kill process, definitely owned by the root user in the termination container, and I believe that linkerd2-proxy was owned by a non-root user as well. But I would have to double check on the last one and don't have my work computer right now.

@Enrico2
Copy link

Enrico2 commented Mar 10, 2020 via email

@alexklibisz
Copy link

Yeah I didn't set up the termination process to run as root.

Got it. So it's working now?

@Enrico2
Copy link

Enrico2 commented Mar 10, 2020 via email

@kumargauravin
Copy link

Any updates on this? I am new to using cron jobs and linkerd both. If you could spare a moment to share progress on this issue will be great.

@grampelberg
Copy link
Contributor

@kumargauravin the upstream Kubernetes issue is still open and there's not anything we can do on the Linkerd side.

@alexklibisz
Copy link

alexklibisz commented Jun 12, 2020

Can confirm the original solution I posted is still working fine after about three months.

We also have some some crons running on Argo Workflows with linkerd sidecars. shareProcessNamespace doesn't seem to be an available option in argo workflow specifications. We were able to get Argo to kill the sidecars only after setting the right annotations on the job template:

templates:
  - name: job
    metadata:
      annotations:
        linkerd.io/inject: enabled
        config.linkerd.io/skip-outbound-ports: 443
    container:
      image: ...

The key part is the skip-outbound-ports.. I set this up a while ago so I don't remember the precise reasoning. It was some sort of deadlock where the argo sidecar container couldn't kill the linkerd sidecar container because argo was trying to communicate over 443, which was proxied by linkerd, so linkerd refused to die because it still had open connections over 443, etc. Fun stuff!

@Esardes
Copy link

Esardes commented Aug 14, 2020

@alexklibisz thanks for the workaround!
I got it working on a k8s job, but couldn't figure out how to make it so in an Argo flow (shareProcessNamespace doesn't seem to fit anywhere). Any chance you'd have time to share a gist for it?

@alexklibisz
Copy link

@alexklibisz thanks for the workaround!
I got it working on a k8s job, but couldn't figure out how to make it so in an Argo flow (shareProcessNamespace doesn't seem to fit anywhere). Any chance you'd have time to share a gist for it?

I updated the comment above.

@electrical
Copy link

For future reference. A shutdown hook was added in linkerd/linkerd2-proxy#811

@laukaichung
Copy link

For future reference. A shutdown hook was added in linkerd/linkerd2-proxy#811

Is there an example or documentation for this feature?

@wmorgan
Copy link
Member

wmorgan commented May 13, 2021

@laukaichung Good catch, I don't think we documented this very well. Would you mind filing an issue to https://github.com/linkerd/website so that we can track this?

@rachelvwood
Copy link

@wmorgan @laukaichung I didn't find an existing one, so I created an issue about the missing documentation.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests