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

java.nio.file.AccessDeniedException: /opt/docker/RUNNING_PID #1458

Closed
christian-schlichtherle opened this issue Sep 6, 2021 · 6 comments
Closed

Comments

@christian-schlichtherle
Copy link

I'm using the DockerPlugin. In my build.sbt, I have the following settings:

dockerBaseImage := "openjdk:11",
dockerExposedPorts := Seq(9000),
dockerUpdateLatest := true,

Docker / daemonUserUid := None,
Docker / daemonUser := "daemon",
Docker / maintainer := "???",

This generates the following Dockerfile:

FROM openjdk:11 as stage0
LABEL snp-multi-stage="intermediate"
LABEL snp-multi-stage-id="5c0621ba-1ab5-4977-bf0f-e3c2f2cee7e4"
WORKDIR /opt/docker
COPY opt /opt
USER root
RUN ["chmod", "-R", "u=rX,g=rX", "/opt/docker"]
RUN ["chmod", "u+x,g+x", "/opt/docker/bin/server"]

FROM openjdk:11
LABEL MAINTAINER="???"
WORKDIR /opt/docker
COPY --from=stage0 --chown=daemon:root /opt/docker /opt/docker
EXPOSE 9000
USER daemon
ENTRYPOINT ["/opt/docker/bin/server"]
CMD []

When running this image, I get this:

$ docker run -it --rm -p "9000:9000" server
Oops, cannot start the server.
java.nio.file.AccessDeniedException: /opt/docker/RUNNING_PID
[...]

When taking a closer look at what's going on, it turns out the order of the commands in the Dockerfile is wrong:

[...]
WORKDIR /opt/docker
COPY --from=stage0 --chown=daemon:root /opt/docker /opt/docker
[...]

This sequence causes the directory /opt/docker to be created and owned by root:root. The subsequent copy command does not change that because the directory already exists. Swapping the commands fixes this issue.

However... the sequence of these commands is not optimal anyway. They should be rearranged as follows:

FROM openjdk:11 as stage0
LABEL snp-multi-stage="intermediate"
LABEL snp-multi-stage-id="5c0621ba-1ab5-4977-bf0f-e3c2f2cee7e4"
USER root
WORKDIR /opt/docker
COPY opt /opt
RUN ["chmod", "-R", "u=rX,g=rX", "/opt/docker"]
RUN ["chmod", "u+x,g+x", "/opt/docker/bin/server"]

FROM openjdk:11
LABEL MAINTAINER="info@schlichtherle.de"
USER daemon
WORKDIR /opt/docker
EXPOSE 9000
ENTRYPOINT ["/opt/docker/bin/server"]
CMD []
COPY --from=stage0 --chown=daemon:root /opt/docker /opt/docker

The point is that the USER command should be running as early as possible to make sure everything after is using this user. And the COPY command should be running as late as possible to take advantage of the docker build cache. Mind you that every command creates a layer that somebody has to download when running docker pull. All these EXPOSE etc commands effectively don't contain data, but they still add overhead to the image layers.

@christian-schlichtherle
Copy link
Author

Thanks, but this is an issue, not a feature request, please. The current image is unusable because of permission problems.

@muuki88
Copy link
Contributor

muuki88 commented Sep 6, 2021

Hi @christian-schlichtherle

Thanks for the detailed issue request. I just labelled it and hadn't had the time for a response ( currently on vacation ).

Your description contains two things

  1. Permission issues
  2. Layer optimization

Permission issues

There were a few discussions on this before. The result was

  • Nothing in the docker image should be writable. The same as it is for all other formats.
  • If you want to write somewhere, mount a volume

This comes up regularly with play ( were you are encouraged to disable the PID file creation as it serves no purpose ) or logging.

Why do you need a PID file in your docker image? From my view docker images are stateless and as such don't need to be writable.

Layer optimization

Moving the copy to the end may safe a few KB and network calls. Is it worth it? Some users fiddle around with the docker file, changing the ordering may break their build setup.

@christian-schlichtherle
Copy link
Author

As for why Play creates this PID file, you need to discuss this with the original authors. I'm just a user who wanted to use your plugin and found it to be unusable because of this issue.

As for the layer optimization: Yes, it does matter. It matters on Internet scale with millions of users. It matters for large corporations where clusters may have hundreds of nodes, even in the presence of container registry mirrors.

Why would a user want to mess with the generated Dockerfile if not for shortcomings like the issue I found? So it's totally in your control if you want to add more value to your plugin or not.

As for me, I decided to remove the plugin from my build because I have some more advanced use cases, e.g. cross platform builds.

@muuki88
Copy link
Contributor

muuki88 commented Sep 7, 2021

Do you are using the Playframework? Then sbt-native-packager is already enabled and you don't need to add the plugin yourself.

Regarding the PID file. See https://www.playframework.com/documentation/2.8.x/ProductionConfiguration

$ /path/to/bin/<project-name> -Dpidfile.path=/var/run/play.pid

And there's a section for play here too: https://sbt-native-packager.readthedocs.io/en/latest/recipes/play.html#build-configuration

Use

Universal / javaOptions += "-Dpid.file=/dev/null"

@muuki88
Copy link
Contributor

muuki88 commented Sep 7, 2021

Why would a user want to mess with the generated Dockerfile if not for shortcomings like the issue I found?

To name a few

  • property libraries that need messy workarounds
  • infrastructure requirements
  • docker constantly breaking their API
  • optimizations

So it's totally in your control if you want to add more value to your plugin or not.

I maintain this plugin in my free time. Changes that may cause a lot of users to ask for help for a performance optimization that probably very few will profit from ( I'm sure Google, Twitter, Facebook, Amazon, etc. don't use native-packager ) are not worth the effort.

As for me, I decided to remove the plugin from my build because I have some more advanced use cases, e.g. cross platform builds.

Can you elaborate? Still docker or other formats?

@muuki88 muuki88 closed this as completed Sep 7, 2021
@christian-schlichtherle
Copy link
Author

I need to use docker buildx ... for some cross platform building options and so I tweaked the Dockerfile to my liking. I'm also using pidfile.path=... now to overwrite the default location.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants