8000 Reset properties inherited from parent image · Issue #3465 · moby/moby · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Reset properties inherited from parent image #3465

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

Open
shykes opened this issue Jan 6, 2014 · 238 comments
Open

Reset properties inherited from parent image #3465

shykes opened this issue Jan 6, 2014 · 238 comments
Labels
area/builder kind/enhancement Enhancements are not bugs or new features but can improve usability or performance. status/needs-attention Calls for a collective discussion during a review session

Comments

@shykes
Copy link
Contributor
shykes commented Jan 6, 2014

When building an image I may want to reset some of its properties instead of inheriting them from the parent image. It makes sense to inherit all properties by default, but there should be a way to explicitly and selectively reset them when it makes sense.

This is a more generic solution to #2210 which only addresses expose.

@shykes
Copy link
Contributor Author
shykes commented Jan 6, 2014

Suggestions welcome for syntax.

@tianon
Copy link
Member
tianon commented Jan 6, 2014

The best I can come up with is corresponding commands like UNVOLUME or more generically -VOLUME (but that would add more confusion, and potentially even create the misconception that +VOLUME should work, and should work differently from just VOLUME).

I very definitely want such a thing (most especially for VOLUMEs). It's also a little disorienting that things like VOLUME apply to following RUN lines, but things like ENTRYPOINT don't. Sometimes that's very useful, and sometimes it's not, but a generic "disable previous X instruction" could solve the issues around that quite nicely.

@dergachev
Copy link

Is there a workaround for this in the meantime? I'm extending an image with an ENTRYPOINT (https://github.com/jagregory/pandoc-docker/blob/master/Dockerfile) and I need to unset the entrypoint. I tried using the following in my Dockerfile:

FROM jagregory/pandoc
ENTRYPOINT [] # this basically gets ignored (bug?)

FROM jagregory/pandoc
ENTRYPOINT [""] # this will make docker try to exec '' (the empty string)

FROM jagregory/pandoc
ENTRYPOINT ["/bin/sh", "-c"] 
# this will only work if docker run args are quoted:
#   docker run dergachev/pandoc "echo a b c"

Thanks!

@stormbeta
Copy link

I would definitely like to have some way of removing VOLUME points inherited from parent images.

For example, suppose I had a main image for an application that used an external mountpoint for persistent data, but I also wanted an image based on it that was pre-populated with test data instead. As-is, I can't do that if the parent image used VOLUME because any changes/additions to those directories, even if those changes are during a docker build, are lost on commit.

@tianon
Copy link
Member
tianon commented Jun 30, 2014

Just to update from @dergachev's comment, CMD [] and ENTRYPOINT [] were working last time I tested them recently, and should still be working (anything else would be ripe for bug filing).

@mmerickel
Copy link

You can reset all of the single-option commands via

ENTRYPOINT []
CMD []
USER 0
WORKDIR /

This should leave the remaining, un-resettable metadata as ENV, VOLUME, EXPOSE and maybe ONBUILD.

@codeon-nat
Copy link

(This is coming from #8709)

If I exposed sockets 9000-9002 in the parent, but needed to unexpose 9001 in the child, I'd then have to write in the style of "unsetting"

EXPOSE
EXPOSE 9000
EXPOSE 9002

which would work but

UNEXPOSE 9001

looks nicer.

An advantage being, that it doesn't affect any EXPOSEs from further up the inheritance chain, which I might want to add later.

@AshleyAitken
Copy link

+1 @codeon-nat

@icecrime
Copy link
Contributor

This has been discussed in #8177, we're closing this for a lack of real world use cases.

@mitar
Copy link
mitar commented Apr 16, 2015

Why is this being closed? There were 9 people commenting here. I think this would be a really useful thing to have. The real world use cases are being able to build upon existing images with ease. Sometimes you want to add property, sometimes you want to remove it. This is normal.

@kamermans
Copy link

I agree, for example, I'm extending the nginx image for an SSL offloader and I want to UNEXPOSE 80 but leave 443.

@seth-admittedly
Copy link

Being able to unexpose ports is pretty critical if you want to run multiple instances of, e.g., nginx. Without this feature, each image that inherits from nginx tries to expose 80 and 443, causing the error Bind for 0.0.0.0:80 failed: port is already allocated.

Nevermind, this was just poor configuration on my side.

@apatrida
Copy link

(April 15: "No real world use cases" I'm surprised you cannot imagine at least one and closed this)

I have a base image that exposes volumes or ports for optional software, then FROM that in another Dockerfile to make an image that should not expose anything it doesn't want to, or even things that it has uninstalled from the ancestor. Why would we NOT want to be able to remove these settings?

@download13
Copy link

I also have a use case for this. I want to be able to create an image containing a database snapshot, but all the mysql packages have VOLUME /var/lib/mysql set. It would nice to be able to turn off the volume the changes to the database made in my Dockerfile will stick with the image.

The only other option is to completely re-create a custom mysql image, but that somehow seems wasteful since plenty of other people have already put together better default mysql servers than I could.

@tomheinan
Copy link

Adding an additional use case - I'm inheriting from the official RabbitMQ image, but I only want to expose websocket ports (80 and 443) and not the default AMQP port (5672). Seems like this should be a pretty reasonable thing to want to do?

@thaJeztah thaJeztah mentioned this issue Sep 24, 2015
3 tasks
@praqma-thi
Copy link

Adding another use case. I want to build a git test environment using the gogs image but it's tedious to have the data persist since it's all stored in a volume. It'd be great if I'd be able to simply UNVOLUME the volume and build my image after setting up the environment.

@krasi-georgiev
Copy link
Contributor

+1

inheriting from the official php and want to use sockets instead of ports so need to remove the exposed 9000 port

@macropin
Copy link
macropin commented Dec 9, 2015

Anyone who has used Docker in a non-trivial capacity will have found these limitations with inherited containers.

@shykes @icecrime how is this now closed? Is it too hard to solve with the current syntax and need for backwards compatibility? Whats the plan?

@ianmiell
Copy link

+1 - real world use case for EXPOSE override here.

@felipecrs
Copy link

Oh God. That's depressing. No point to continue the discussion then.

@alexeyp0708
Copy link
alexeyp0708 commented Mar 27, 2024

@thaJeztah
A new topic has been opened in moby/buildkit
moby/buildkit#4802
Based on the comment #8177 (comment)
Please close and lock the topic.

@q0rban
Copy link
q0rban commented Mar 27, 2024

Please close and lock the topic.

Don't we still want this open for unsetting these values via docker run / docker container create?

@alexeyp0708
Copy link
alexeyp0708 commented Mar 27, 2024

#8177 (comment)

see admin's response #8177 (comment)
This issue is best discussed in mody/buildkit since in the legacy Dockerfile builder "moby/moby" the changes will only affect bugs.
Now I propose to take a consolidated approach to the problem in a new branch,
so that the buildkit developers pay attention to this

@alexeyp0708
Copy link
alexeyp0708 commented Mar 27, 2024

Please close and lock the topic.

Don't we still want this open for unsetting these values via docker run / docker container create?

Perhaps this will affect on docker run, but I think only when there is a solution in Buildkit.
But for this you can then create a new topic.
In any case, we need to unite in a new topic to affect changes in "moby/buildkit"

@lucasbasquerotto
Copy link

@alexeyp0708 I think it's best to discuss here actually, or in both places, at least for volumes, because I think removing volumes defined in images should be able to be done in docker run. This should not be restricted to buildkit or even Dockerfiles.

Even if an image was created with docker container commit (without a Dockerfile), I should be able to remove image volumes in docker run.

From what I see, image volumes create a mount somewhere when a container is created from the image. I think the best way to solve it is to just add an option in docker run to not create the mount in this case.

That said, creating a Dockerfile inheriting from a parent image with some instruction like UNVOLUME would solve it too, but a docker run approach would avoid the need to extend the original image, and could skip the build step entirely.

@alexeyp0708
Copy link
alexeyp0708 commented Mar 28, 2024

@lucasbasquerotto

I think it's best to discuss here actually, or in both places, at least for volumes, because I think removing volumes defined in images should be able to be done in docker run. This should not be restricted to buildkit or even Dockerfiles.

Perhaps I was hasty in jumping to the conclusion was to close the topic.
Today the bulk of the participants are in this thread.

Studying discussions the topic, I came to the conclusion that there were mainly proposals to improve the Dockerfile.

I did not see that the participants were able to professionally reproduce their difficulties so that the developers would pay due attention to this.

I also got the impression that the developers stopped paying attention to this.
At least I didn't see any questions from the developers.
Now this is a discussion platform where there are no constructive proposals and solutions.
The topic is already 10 years old.
New topics with constructive and detailed idea will interest developers much faster than a discussion of 500 or more messages. The very fact of studying such a long topic discourages interest in diving into details.
In most cases, this topic contains only wishes and meaningless discussions.

@alexeyp0708
Copy link
alexeyp0708 commented Mar 28, 2024

@lucasbasquerotto

Even if an image was created with docker container commit (without a Dockerfile), I should be able to remove image volumes in docker run.

I agree with you that we need a command that can disable the parent volume.I suggested this idea a little higher. run --mount type=none, dst=/dir/volume
#3465 (comment)
There were several other ideas for unmounting volumes VIA docker run.
But I think if they enter mount type=none it will be a better idea.
none indicates that the folder is protected from any volume mounting.
Arguments:

  • There is a new type none in the new command -- mount type = (volume|bind|tmpfs|none), which will be easier to implement. All them need to do in code is write a “dummy” driver that does nothing. But by specifying such a driver, the system will automatically override the default volume connections to this a driver.
  • when a new type =none appears, it can be legally specified for docker compose in compose.yml
volumes:
      - type: none
        target: /data

@alexeyp0708
Copy link
alexeyp0708 commented Mar 28, 2024

I think even a simple workaround is to write a plugin that implements a stub driver(simulates connection to volume).
https://docs.docker.com/engine/extend/plugins_volume/
https://docs.docker.com/engine/extend/plugin_api/

(updated)
I read a little about the plugin documentation.
Unfortunately, this path is unlikely to be implemented.
Plugins work over sockets and cannot affect the container in any way. This means that the volume will definitely be mounted inside the container.

@thorfi
Copy link
thorfi commented Jun 20, 2024

I have a workaround for this, as an example, the official postgres image. Originally posted by me here: https://stackoverflow.com/a/78645904/2545063

You can use COPY --from to copy the files from the image you want to work with but don't want its properties (like VOLUME) to an image based on the same base image. As an example, the postgres image and its source Debian image.

FROM postgres:15-bookworm as postgres-docker

FROM debian:bookworm-slim as postgres-build

# We do this because the postgres-docker container has a VOLUME on /var/lib/postgresql/data
# This copies the filesystem without bringing the VOLUME with it.
COPY --from=postgres-docker / /

# DO THE REST OF YOUR STUFF

# https://hub.docker.com/_/postgres - see 15-bookworm for the stuff we are setting here
# Note: We need to set these because we are using COPY --from=postgres-docker - see above
ENTRYPOINT ["docker-entrypoint.sh"]
ENV LANG en_US.utf8
ENV PG_MAJOR 15
ENV PATH $PATH:/usr/lib/postgresql/${PG_MAJOR}/bin
ENV PGDATA /var/lib/postgresql/data
ENV SLEEP_ON_EXIT=0
STOPSIGNAL SIGINT
CMD ["postgres"]

EXPOSE 5432

@thaJeztah
Copy link
Member

@thorfi is your intent to ship an image that contains data at /var/lib/postgresql/data or to run the image without a volume attached?

For the first part; if you're using BuildKit as builder, you already can do this, as BuildKit no longer applies volumes during build (at least for COPY and ADD, so you can copy and preserve data into that directory)

For "run the image without volume", I would not recommend running a database with it's data stored on overlayFS (or other CoW filesystems); it will severely impact performance, and may result in unexpected behavior.

@grossjohann
Copy link

@thorfi is your intent to ship an image that contains data at /var/lib/postgresql/data or to run the image without a volume attached?

Our use case is related to Solr, not Postgres, and we would like to move the data directory to a subdirectory of the regular one. More specifically, we want to run a DB and Solr and we want both of them to store their data in the same volume, so we want a volume with a subdirectory db where the DB puts its stuff and a second subdirectory solr where Solr puts its stuff.

I feel that's a valid use case, and it's not supported by the ecosystem.

Perhaps for us the way around this is to just have two volumes, one for the DB and one for Solr, and to write some tooling around it that treats the two volumes as a unit. (E.g. to back them up and to restore them. We already have a simple script that backs up / restores the one volume.) Then the containers can be happy thinking they “own” their respective volume.

@felipecrs
Copy link

@thaJeztah, I'm assuming users in this issue understand the implications of using a volume versus not using one, and are specifically asking for having the ability of not using one.

I just want to make sure "your suggestion" doesn't help this issue fall in staleness due to a "fake" impression of "users were not supposed to do that".

Nevertheless I support everything you said.

@thorfi
Copy link
thorfi commented Jun 20, 2024

@thorfi is your intent to ship an image that contains data at /var/lib/postgresql/data or to run the image without a volume attached?

For the first part; if you're using BuildKit as builder, you already can do this, as BuildKit no longer applies volumes during build (at least for COPY and ADD, so you can copy and preserve data into that directory)

For "run the image without volume", I would not recommend running a database with it's data stored on overlayFS (or other CoW filesystems); it will severely impact performance, and may result in unexpected behavior.

I need the image without VOLUME because I need to mount /var/lib/postgresql instead, and the VOLUME /var/lib/postgresql/data ends up wiping that on every container restart.

@thorfi
Copy link
thorfi commented Jun 20, 2024

@grossjohann wrote:

I feel that's a valid use case, and it's not supported by the ecosystem.

100% - I just wanted my VOLUME to go "up" one directory level, and a simple:

UNVOLUME /var/lib/postgresql/data
VOLUME /var/lib/postgresql

Would have been perfect, instead of having to do COPY --from and then manually reset all the other build instructions.

Someone wrote a script to do this sort of thing via image dump -> patch -> load https://stackoverflow.com/a/52030840/2545063 but frankly that's also a terrible workaround (it works, but ugh).

@macdjord
Copy link

I just want to be able to properly declare that my custom NGINX image, derived from the official standard NGINX image, exposes only port 443, not port 80, despite the official standard NGINX image including EXPOSE 80/tcp.

@alexeyp0708
Copy link
alexeyp0708 commented Jul 28, 2024

@macdjord
https://docs.docker.com/reference/dockerfile/#expose

The EXPOSE instruction doesn't 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 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.

To notify the user that port 80 is not in use, leave a comment in the dockerfile

@simaotwx
Copy link

For "run the image without volume", I would not recommend running a database with it's data stored on overlayFS (or other CoW filesystems); it will severely impact performance, and may result in unexpected behavior.

It's not recommended for databases but surely there are other images where this is desired.
Take WordPress as an example. You might want to just include the installation in /var/www/html in a reproducible way, having a pinned version and not allowing modification of the files in runtime. So you'd have to "UNVOLUME" /var/www/html, and mount a volume to /var/www/html/wp-content/uploads instead.

https://github.com/docker-library/wordpress/blob/master/latest/php8.3/apache/Dockerfile#L170

@allentc
Copy link
allentc commented Jul 29, 2024

For "run the image without volume", I would not recommend running a database with it's data stored on overlayFS (or other CoW filesystems); it will severely impact performance, and may result in unexpected behavior.

It's not recommended for databases but surely there are other images where this is desired.

@thaJeztah @simaotwx

This isn't about preventing simple minded mistakes such as storing database files in an overlay file system. This is about providing a means to correct otherwise useful images that have been saddled with naively specified VOLUME(s), EXPOSE(s) and other such damage.

There is no valid basis for thinking that by not providing the affordance of removing and/or changing the values of these directives in derived images some great good is being protected. Anyone with the necessary wit to understand why they might need to do this and wish that the means to do so existed can be presumed to understand the implications. For example, one might very well want to store database files within the overlay file system for transitory use cases, e.g. testing in a CI regime.

@nathanweeks
Copy link

Being able to reset any EXPOSE instruction(s) defined in the Dockerfile of a parent image would have a runtime effect for at least AWS Elastic Beanstalk and Cloud Foundry, which use it to determine which container port to route network traffic to.

@macdjord
Copy link
macdjord commented Jul 30, 2024

@alexey

To notify the user that port 80 is not in use, leave a comment in the dockerfile

I am aware of how dockerfiles work. Adding a comment would serve to document the change to someone looking at the dockerfile, but would do no good to someone looking at the generated image or a container created from it. For example, the 'Ports' column of docker ps lists EXPOSEd ports.

@alexeyp0708
Copy link
alexeyp0708 commented Oct 1, 2024

@macdjord

@alexey

To notify the user that port 80 is not in use, leave a comment in the dockerfile

I am aware of how dockerfiles work. Adding a comment would serve to document the change to someone looking at the dockerfile, but would do no good to someone looking at the generated image or a container created from it. For example, the 'Ports' column of docker ps lists EXPOSEd ports.

I think that this is part of the uncomfortable use and does not represent a problem for which you need to look for workarounds or make radical changes to the API or code.

But I repeat - this is my personal opinion!
I just pointed out what you can do now, without waiting for new solutions.

@trickert76
Copy link

I've a similar workaround like #3465 (comment) for other images, in this case from php:apache, where I wanted the apache process run as non-root on port 8080, but the original image is exposing port 80 too, which is always strange looking at docker ps with an exposed but unused privileged port (just for my personal Monk).

FROM php:apache AS build

# .. do all the things, I need for my custom image ...

FROM scratch

# ... define image environment vars and label ...

COPY --from=build / /
WORKDIR /var/www/html
USER www-data
STOPSIGNAL SIGWINCH
EXPOSE 8080
CMD ["apache2-foreground"]
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
HEALTHCHECK --interval=60s --timeout=5s --start-period=65s CMD /usr/local/bin/php -f /var/www/src/healthcheck.php

The problem with that is in general maybe it's dificult to track new default environment variables from the parent image that are needed with new versions (just think about changes of the MariaDB container coming from all the MYSQL environment vars).

It's necessary to keep an eye on that.

But one additional benefit is, that you also loose all the previous layers. My image was 290MB before, now its 110MB.

@thom-vend
Copy link
thom-vend commented Nov 7, 2024

Nice workaround @trickert76 I'll remember this one ❤

But one additional benefit is, that you also loose all the previous layers. My image was 290MB before, now its 110MB.

true at one image level, but on a registry level or on one machine level with many images built from the same source you might end-up with lot more custom layer than a few shared layer increasing globally the storage needs

@smlx
Copy link
smlx commented Nov 7, 2024

I think what this issue shows is that building off an "official" base image is great for quick hacky project, or if it happens to expose the ports you need.

But if you need customisation you're just better off using an alpine/debian/ubuntu base image an installing the distro package or building the upstream software yourself.

@trickert76
Copy link
trickert76 commented Nov 7, 2024

I would not say, that this is a hacky solution. This sounds a bit rude. It is an official way how to build your own docker images based on other images and setup. You can find the documentation at Multi stage. And as long as there is no other way based on this issue, this is a common posibility - a workaround.

Also I'm not sure, if this is really possible. From a metaphorical point of view a Dockerfile is a "Definition Build Up", so stage over stage, layer over layer. But subtracting properties or layers was never designed, you built something up, not stripping it down. There is an ADD or COPY, but no REMOVE or DELETE. All of that shows me, that the Dockerfile design was never meant to have roll-back function or a subtract layer etc.pp. Just as a little defense, that the approach is "valid".

According thom-vend comment, of course, it must be used very carefully. In my case, the new image based pn php:apache rootless is a base image for all other projects. So at the moment, any other project doesnt build it's own full stack image, but uses the rootless image as base. And when every developer image uses php:apache image as base and the image is stored in a private repo - my observation shows, that every image copies the original image into it's repository. But that is dangerous half-knowledge (on my side).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/builder kind/enhancement Enhancements are not bugs or new features but can improve usability or performance. status/needs-attention Calls for a collective discussion during a review session
Projects
None yet
Development

Successfully merging a pull request may close this issue.

0