-
Notifications
You must be signed in to change notification settings - Fork 407
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
[FIXED JENKINS-41316] Switch 'inside' back to CMD, detect if entrypoint was badly designed #116
Conversation
…for WithContainerStep." This reverts commit 5b0586d.
…d is well executed and warn user if this is not the case Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
* @return The container ID. | ||
*/ | ||
public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNull String args, @CheckForNull String workdir, @Nonnull Map<String, String> volumes, @Nonnull Collection<String> volumesFromContainers, @Nonnull EnvVars containerEnv, @Nonnull String user, @Nonnull String entrypoint) throws IOException, InterruptedException { | ||
public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNull String args, @CheckForNull String workdir, @Nonnull Map<String, String> volumes, @Nonnull Collection<String> volumesFromContainers, @Nonnull EnvVars containerEnv, @Nonnull String user, @CheckForNull String... command) throws IOException, InterruptedException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CheckForNull
on varargs?! Please no…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
side effect from git revert
@@ -139,6 +146,30 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu | |||
} | |||
} | |||
|
|||
public List<String> listProcess(@Nonnull EnvVars launchEnv, @Nonnull String containerId) throws IOException, InterruptedException { | |||
LaunchResult result = launch(launchEnv, false, "top", containerId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
top
is even less likely to be there. What about ps ax
? Or pgrep
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is docker top command
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actual implementation for docker top
(here) is to run ps
on host and filter result to restrict to container's processes.
assumeDocker(); | ||
WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); | ||
p.setDefinition(new CpsFlowDefinition( | ||
"docker.image('maven:latest').inside {\n" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, what is the behavior of maven:latest
today? Simply breaking it does not seem like a viable option, as this image is widely used. Is there an updated version which works well? Or an option which can be passed to image
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maven just works, official docker image validation process do include check for this recommendation for entrypoint to accept an alternative command.
(https://github.com/carlossg/docker-maven/blob/master/jdk-8/mvn-entrypoint.sh#L39)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maven just works
Then why do you need to delete this test case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this test case was removed as I reverted commit 95df0ee. It can be re-introduced.
final List<String> ps = dockerClient.listProcess(env, container); | ||
if (!ps.contains("cat")) { | ||
listener.error("The container started but didn't ran the expected command. Please double check your Entrypoint does execute the command passed as docker run argument. See https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#entrypoint for entrypoint best practices."); | ||
throw new IOException("Failed to run container with CMD `cat`"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably better to print the warning but let it continue, in case the user knows something we do not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was not sure about this, good point
@@ -177,6 +177,12 @@ private static void destroy(String container, Launcher launcher, Node node, EnvV | |||
} | |||
|
|||
container = dockerClient.run(env, step.image, step.args, ws, volumes, volumesFromContainers, envReduced, dockerClient.whoAmI(), /* expected to hang until killed */ "cat"); | |||
final List<String> ps = dockerClient.listProcess(env, container); | |||
if (!ps.contains("cat")) { | |||
listener.error("The container started but didn't ran the expected command. Please double check your Entrypoint does execute the command passed as docker run argument. See https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#entrypoint for entrypoint best practices."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/ran/run
I'm not sure about this build failure, test fail on my workstation with |
I'm not sure what initially caused JENKINS-37987. |
Asked Alvaro about the initial error in JENKINS-37987 but can't get info to reproduce and investigate further |
@@ -177,6 +177,11 @@ private static void destroy(String container, Launcher launcher, Node node, EnvV | |||
} | |||
|
|||
container = dockerClient.run(env, step.image, step.args, ws, volumes, volumesFromContainers, envReduced, dockerClient.whoAmI(), /* expected to hang until killed */ "cat"); | |||
final List<String> ps = dockerClient.listProcess(env, container); | |||
if (!ps.contains("cat")) { | |||
listener.error("The container started but didn't run the expected command. Please double check your ENETRYPOINT does execute the command passed as docker run argument. See https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#entrypoint for entrypoint best practices."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small typo here: ENETRYPOINT should be ENTRYPOINT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, this needs to be fixed. =)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo fix needed, otherwise looks good to me.
@@ -177,6 +177,11 @@ private static void destroy(String container, Launcher launcher, Node node, EnvV | |||
} | |||
|
|||
container = dockerClient.run(env, step.image, step.args, ws, volumes, volumesFromContainers, envReduced, dockerClient.whoAmI(), /* expected to hang until killed */ "cat"); | |||
final List<String> ps = dockerClient.listProcess(env, container); | |||
if (!ps.contains("cat")) { | |||
listener.error("The container started but didn't run the expected command. Please double check your ENETRYPOINT does execute the command passed as docker run argument. See https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#entrypoint for entrypoint best practices."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, this needs to be fixed. =)
@cyrille-leclerc yes indeed. |
@jglick - are you still a -1 on this? |
@@ -129,7 +134,9 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu | |||
argb.add("-e"); | |||
argb.addMasked(variable.getKey()+"="+variable.getValue()); | |||
} | |||
argb.add("--entrypoint").add(entrypoint).add(image); | |||
if (command != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
command
should be @Nonnull
. If you wish to permit no specified commands (which I do not recommend, since AFAIK there is only one caller of this method, and it passes a command), then you would check command.length > 0
, which would anyway be gratuitous since add(String...)
would just be a no-op in that case.
assumeDocker(); | ||
WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p"); | ||
p.setDefinition(new CpsFlowDefinition( | ||
"docker.image('maven:latest').inside {\n" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maven just works
Then why do you need to delete this test case?
Can i point out that forcing "cat" in entrypoint, or in cmd (and check processes if "cat" is running) breaks this example in the doc, as we have no ways to start services: https://jenkins.io/doc/book/pipeline/docker/#running-sidecar-containers |
@nervo as long as you can run entrypoint you can start services. Just need to follow docker best practice to eventually execute the command passed as |
@ndeloof thanks for your answer :) You are also right, i did'nt realize that th sidecar pattern use "withRun" and not "inside"... Sorry for the polution, and thanks for your hard work. |
Do you have any idea when this fix might be released? For some reason we are starting to see this problem after a recent upgrade of jenkins (without any plugin upgrades) and its causing us some issues. |
Help me out here @ndeloof ... where do you get the idea that a cmd must be executed by the entrypoint? In fact, the docker docs linked from the new error message say just the opposite! i.e.
The example given is |
FWIW, I'm not doing anything crazy here... just using a pipeline that looks roughly like this:
The image in question here is the same one developers use in our org. So, allowing the ENTRYPOINT to run as if the image were the command (like the What am I missing? |
read the doc further 👍
Actually, all official docker images are REQUIRED by Docker review to allow passing an alternate command, typically you can run Please also note bypassing entrypoint was a major regressions. Many images do rely on entrypoint script to run some initial setup, or start background services (typically, selenium image to bootstrap a X11 server). |
Where do you see this?
Seems hard to justify calling it “best practice” based on linked documentation that starts with “The best use for ENTRYPOINT is...” and then proceeds with an example that conflicts with your expected usage. Yes, the other pattern is there too. But in no way does that negate the first example which is identified as the “best use”. |
I'm not sure it's documented, but I have the experience to maintain official |
Fair enough. And I respect your experience. But to force a behavior that directly conflicts with public documentation for Docker based on non-public internal guidelines somewhere seems like a bug to me. How can you reasonably expect image authors to follow practices that aren’t documented clearly and which are in direct conflict with part of what is documented clearly? Either Docker docs need fixing or this plugin does. But insisting on undocumented “standards” isn’t a solution. It is trading one regression for another. |
Then maybe https://github.com/docker-library/official-images#consistency would be a better link. |
I think using that link and referring to it as "plugin requirements" or "plugin expectations" would be more correct than "best practices" given the public Docker docs. Maybe something like this:
However, it is worth mentioning that your requirements are actually more robust than just a specific ENTRYPOINT behavior. If I'm not mistaken, you also require a shell available in the image (probably a specific one? bash maybe?). Perhaps you have other requirements too. It would be ideal if you would document those somewhere and then link THAT doc from the error message (instead of Docker's docs). In that documentation, given that you require a shell, it should also be trivial to recommend a workaround for image authors that, for whatever reason, cannot or will not make their entrypoints behave as you expect. Particularly, you could specify that if your ENTRYPOINT does not follow that convention, you will need to override it with a The combination of better documentation around this behavior, clear expectations, and simple workarounds for when your expectations cannot be met directly would setup users for success in a much greater way than relying on a failure to happen first, and then the user to read and interpret this cryptic, misleading, and incorrect message: "ERROR: The container started but didn't run the expected command. Please double check your ENTRYPOINT does execute the command passed as docker run argument. See https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#entrypoint for entrypoint best practices." |
no, if the entrypoint does not follow this recommendation we should not override it, or the image will run in some unexpected state both by the plugin and image author. |
I'm not suggesting that you automatically override it. I'm suggesting that you could document for users how they can easily override their non-conformant ENTRYPOINT if they want to.
I thought I remembered reading that in one of the JIRA threads or PR threads related to this issue and/or preceding ones. But I can't find it now, so I don't recall where I thought I saw it. But in any case, you have to run steps inside the container with something right? I assumed it is a shell. In any case, that isn't super relevant. I was just speculating as to possible other expectations that the plugin might have. Whatever they are, it would be helpful to have them documented. I've filed a JIRA for the documentation issues and linked back to this thread for background. As you'll see in my JIRA, it turns out there is an easier workaround than the shell based snippet I pasted above. Docker allows simply unsetting the ENTRYPOINT via a run arg of |
plugin indeed run |
Our environment rebuilds are broken due to this. They use the terraform container and no longer work. |
|
This seems to break a whole bunch of scripted |
This is pretty annoying. |
@chrono I'm not in a position to test extensively at the moment, but if you can add a docker arg of |
@@ -177,6 +177,11 @@ private static void destroy(String container, Launcher launcher, Node node, EnvV | |||
} | |||
|
|||
container = dockerClient.run(env, step.image, step.args, ws, volumes, volumesFromContainers, envReduced, dockerClient.whoAmI(), /* expected to hang until killed */ "cat"); | |||
final List<String> ps = dockerClient.listProcess(env, container); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hesco on #jenkins reports that this line can itself fail, breaking the entire step for the sake of a diagnostic. Root cause unknown.
Based on this comment I am assuming that the issue is not fixed? Also I am running into this issue now? Can anyone point me to some useful documentation regarding this? |
So this was merged, but Jenkins is back to overriding the docker entrypoint again somehow. I can't find where the issue is in the source. |
See discussion on #85