0

I have a docker-compose file which invokes an existing image and modifies it - the base image is from a parent project and not under my control. That base image has an EXPOSE 8080, but one of the primary ways I am modifying it is to change the port the service uses.

How can I negate/cancel that EXPOSE from the docker-compose.yaml?

(Note: Future versions of the parent project are likely to update the base image and our local project will modify those future versions, so the obvious solution of "make a fork which changes the Dockerfile" is not an option. Solutions that need some other local files to override the parent are fine, as long as it's all local and not going to require resolving merge conflicts every time the base image updates.)

jkmartin
  • 153
  • 1
  • 7

4 Answers4

3

As per the docs, the EXPOSE statement mostly functions as documentation and doesn't do anything more

The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.

So while I agree that it's annoying that there's an incorrect EXPOSE statement in your image, I wouldn't worry about it.

Full documentation here: https://docs.docker.com/engine/reference/builder/#expose

Hans Kilian
  • 18,948
  • 1
  • 26
  • 35
  • I'm aware it's basically just documentation, but I disagree that it means I shouldn't worry. Incorrect documentation is not an *emergency*, but it *is* a high priority. – jkmartin Apr 26 '22 at 23:46
2

You're not the first one searching for this (see https://forums.docker.com/t/how-do-i-unexpose-ports/67863); the answer on Docker's forum suggests that you can't override the EXPOSE statement of a parent image, without as you already considered yourself forking the repo and changing it.

It seems unlikely that this will be possible in the future either, looking at the Github issues https://github.com/moby/moby/issues/2210 and https://github.com/moby/moby/issues/3465; both from 2014 and neither with a relevant solution.

  • A plague on the houses of everyone who looks at a dozen people requesting a feature and says "closing this for a lack of real world use cases". – jkmartin Apr 27 '22 at 00:00
  • There's a hacky solution linked there - https://stackoverflow.com/questions/42316614/how-can-i-edit-an-existing-docker-image-metadata but I'm not sure how safe it is or whether it can handle changes in the base image gracefully – jkmartin Apr 27 '22 at 00:04
  • Maybe an option to create a repo with build pipeline that does nothing but clone the source repo, perform `sed` on the Dockerfile and then build/upload the fixed image? I've done it with quite a few images that aren't secure enough and needed some `apt upgrade` (and the original maintainer doesn't respond to issues). – Danny Bessems Apr 27 '22 at 05:32
2

I've thought some more about this and I've come up with a way to do it. It removes the history of the base image completely, so maybe it's a bit excessive.

The idea is to copy everything from the original image into a scratch image. That way you'll get rid of any EXPOSE statements in the original. You also lose all ENV, CMD, ENTRYPOINT etc., so you have to put those into the new image yourself.

Here's an example with Nginx. The original Nginx EXPOSEs port 80. The new one doesn't.

FROM nginx AS original
FROM scratch
COPY --from=original / /
CMD ["nginx", "-g", "daemon off;"]
Hans Kilian
  • 18,948
  • 1
  • 26
  • 35
1

Several options:

  1. Ignore it, since EXPOSE is documentation it doesn't impact your running containers. Not ideal, but it's what 99% of people do when faced with this.
  2. Build your own image. You can fork the upstream repository with the Dockerfile, add your change to delete the EXPOSE line, and maintain your own build. The downside is you're maintaining the build, so you'll need to periodically rebase your changes on whatever happens upstream.
  3. Modify the image config.

I've been working on the latter. Here's an example of pulling the image locally and then modifying it:

$ regctl image copy nginx:latest localhost:5000/library/nginx:latest

$ regctl image config localhost:5000/library/nginx:latest --format '{{jsonPretty .Config.ExposedPorts}}'
{
  "80/tcp": {}
}

$ regctl image mod --expose-rm "80/tcp" localhost:5000/library/nginx:latest --create no-expose
localhost:5000/library/nginx:no-expose

$ regctl image config localhost:5000/library/nginx:no-expose --format '{{jsonPretty .Config.ExposedPorts}}'
null

Note that the above functionality is very new/experimental for regclient, to the point that I was just fixing a bug with the above example today, So the above needs an edge release or build off of main until 0.4.3 is released.

Similar tools to regclient's regctl include RedHat's skopeo and Gooogle's crane, but I don't believe either allow this exact functionality yet.

BMitch
  • 231,797
  • 42
  • 475
  • 450