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

Proposal - Build multiple images from a single repository #9198

Closed
icecrime opened this issue Nov 17, 2014 · 8 comments
Closed

Proposal - Build multiple images from a single repository #9198

icecrime opened this issue Nov 17, 2014 · 8 comments
Labels
area/builder kind/feature Functionality or other elements that the project doesn't currently have. Features are new and shiny
Milestone

Comments

@icecrime
Copy link
Contributor

Sorry for this not being a doc first proposal: I’d like to go through the design before proceeding with the documentation itself (it introduces a new magic file, hence probably a whole new documentation page).

Issue statement

Docker needs to provide a repeatable and well defined mechanism for repositories which builds into multiple image. Existing proposals:

These have been opened for some time, and have reached the point where tempers flaring and amount of noise overwhelms the signal. The thinking behind this new proposal was driven by the following remarks collected from previous debates:

  1. We want docker build to behave consistently, without repository-specific knowledge
  2. Through 1, we want to allow Docker Hub automated builds to use this new feature
  3. We do not want a repository from which n images are built to contain n Dockerfiles at its root
  4. We should provide an easy fix for this common problem, and it seems to me that new Dockerfile verbs are more difficult to introduce

Proposal

We introduce a new magic file at the root of the repository to act as the Dockerfile of all Dockerfiles:

  • It could be named DockerfileIndex (as I believe Dockerfiles is too error prone and confusing)
  • It has precedence over a regular Dockerfile, meaning that a docker build invoked in a directory containing both a Dockerfile and a DockerfileIndex interprets the DockerfileIndex only
  • Its content is a simple list of Dockerfiles' relative paths
Dockerfile                  # Build the default Dockerfile located at the root
./SubDirectoryA/Dockerfile  # Build SubDirectoryA
./SubDirectoryB/Dockerfile  # Build SubDirectoryB

With the above DockerfileIndex, the invocation of docker build -t basename:tag . at the root of the repository is equivalent to the following sequence of commands:

docker build -t basename:tag .
cd SubDirectoryA && docker build -t basename/SubDirectoryA:tag .
cd SubDirectoryB && docker build -t basename/SubDirectoryB:tag .

Notes:

  • The first command only exists because the default Dockerfile is itself listed on the first line of the DockerfileIndex (there is nothing specific to this Dockerfile nor to the root)
  • With the V2 registry, an image name is not restricted to a “two-components” path anymore, so “username/image/subimage” is a valid identifier (and in our case, this scoping sounds reasonable)
  • The sequence of commands is provided only as a mean to illustrate the behavior: this doesn't imply that DockerfileIndex interpretation would occur on the client side with multiple build API calls
  • As the sequence of commands implies, each build context is scoped to the location of the Dockerfile: this is Docker current behavior, and I also strongly believe it is the least astonishing one.

Different builds with a single context

To allow for multiple builds using a same context, we require multiple Dockerfile in a single directory: these different Dockerfile would be disambiguated using suffixes, such as Dockerfile.A and Dockerfile.B. Given DockerfileIndex:

Dockerfile.A
Dockerfile.B

Invocation of docker build -t basename:tag . would result in images basename/A:tag and basename/B:tag to be created. Image name is scoped by Dockerfile location first and filename suffix second, which means that SubDirectoryA/Dockerfile.Type1 build would produce image basename/SubDirectoryA/Type1.

Possible extensions

These probably doesn’t have to come in a first version:

  • Ability to trigger a specific sub-build from the DockerfileIndex location through the use of an additional docker build flag (--only was suggested).

History

  • 2014-17-11: add context specification, clarify cascading tag, promote "same context builds" to a first class use case
@erikh
Copy link
Contributor

erikh commented Nov 17, 2014

Arnaud, check out my comment here: #7284 (comment) #7284 (comment)

This itemizes a lot of things I’d like to see in this feature, specifically, the notion of a .dockerfiles directory and make-like targets. What do you think of this?

On Nov 17, 2014, at 9:30 AM, Arnaud Porterie notifications@github.com wrote:

Sorry for this not being a doc first proposal: I’d like to go through the design before proceeding with the documentation itself (it introduces a new magic file, hence probably a whole new documentation page).

Issue statement

Docker needs to provide a repeatable and well defined mechanism for repositories which builds into multiple image. Existing proposals:

#7284 #7284
#2112 #2112
These have been opened for some time, and have reached the point where tempers flaring and amount of noise overwhelms the signal. The thinking behind this new proposal was driven by the following remarks collected from previous debates:

We want docker build to behave consistently, without repository-specific knowledge #2112 (comment)
Through 1, we want to allow Docker Hub automated builds #2112 (comment) to use this new feature
We do not want a repository from which n images are built to contain n Dockerfiles at its root #2112 (comment)
We should provide an easy fix for this common problem, and it seems to me that new Dockerfile verbs are more difficult to introduce
Proposal

We introduce a new magic file at the root of the repository to act as the Dockerfile of all Dockerfiles:

It could be named DockerfileIndex (as I believe Dockerfiles is too error prone and confusing)
It has precedence over a regular Dockerfile, meaning that a docker build invoked in a directory containing both a Dockerfile and a DockerfileIndex interprets the DockerfileIndex only
Its content is a simple list of Dockerfiles' relative paths
Dockerfile # Build the default Dockerfile located at the root
./SubDirectoryA/Dockerfile # Build SubDirectoryA
./SubDirectoryB/Dockerfile # Build SubDirectoryB
With the above DockerfileIndex, the invocation of docker build -t basename . at the root of the repository is equivalent to the following sequence of commands:

docker build -t basename .
cd SubDirectoryA && docker build -t basename/SubDirectoryA .
cd SubDirectoryB && docker build -t basename/SubDirectoryB .
Notes:

The first command only exists because the default Dockerfile is itself listed on the first line of the DockerfileIndex (there is nothing specific to this Dockerfile nor to the root)
With the V2 registry, an image name is not restricted to a “two-components” path anymore, so “username/image/subimage” is a valid identifier (and in our case, this scoping sounds reasonable)
The sequence of commands is provided only as a mean to illustrate the behavior: this doesn't imply that DockerfileIndex interpretation would occur on the client side with multiple build API calls
Possible extensions

These probably doesn’t have to come in a first version:

Customizable image names: this could be achieved either by using the Dockerfile.suffix syntax already suggested in some comments (in such case, ./SubDirectoryA/Dockerfile.A would be built as basename/A), or with additional DockerfileIndex syntax
Ability to trigger a specific sub-build from the DockerfileIndex location through the use of an additional docker build flag (--only was suggested)
Ping @shykes https://github.com/shykes @proppy https://github.com/proppy @erikh https://github.com/erikh for an initial feedback.


Reply to this email directly or view it on GitHub #9198.

@thaJeztah
Copy link
Member

Thanks for collecting these in a single proposal. I largely can find myself in this (taking into account Eriks comment)

I do think, however, that having multiple Dockerfiles for the same context is a common use case. Because of this, consider including Dockerfile.suffix in the first implementation and not in a follow up.

@proppy
Copy link
Contributor

proppy commented Nov 17, 2014

With the above DockerfileIndex, the invocation of docker build -t basename . at the root of the repository is equivalent to the following sequence of commands:
docker build -t basename .
cd SubDirectoryA && docker build -t basename/SubDirectoryA .
cd SubDirectoryB && docker build -t basename/SubDirectoryB .

A Dockerfile currently can't directly control how an image is named (only docker build commit and tag can). Since this proposal change this, I think it's important to call it out and details if it is or not an issue to break the current separation.

Also did you consider making the context the same for the 3 builds so that SubDirectoryA and SubdirectorB can share files to ADD or COPY, like @jpetazzo suggested in #2112 (comment)

I'd also like to highlight @drewcrawford comments on #2112 (comment) about proper support for build targets.

I wonder if we could (or should?) take this proposal further into a proper docker make command, instead of stretching build to do more (path/to/Dockerfile, multiple images build orchestration).

It could uses another file like your proposal, but instead of inferring the name from the directory (or the file suffix), it would explicit require you to specify a set of target: path/to/Dockerfile that could be resolved by the docker make command, something like:

$ find .
frontend/Dockerfile
frontend/frontend.go
backend/Dockerfile
backend/backend.go
common/common.go
Dockerfile.rules
$ cat Dockerfile.rules
front: frontend/Dockerfile
back: backend/Dockerfile
$ docker make -t proppy/myapp
building proppy/myapp/front ... # context is . Dockerfile is frontend Dockerfile
building proppy/myapp/back ... # context is . Dockerfile is frontend Dockerfile
$ docker make -t proppy/myapp front
building proppy/myapp/front ...

@icecrime
Copy link
Contributor Author

@erikh The reason I favor "scattered" Dockerfiles instead of a specific directory holding them all is that I believe it makes assumptions on the context clearer. Here the build context is always scoped to the Dockerfile location, as expected today, and I'm for keeping this behavior.

@thaJeztah Noted, will update.

@proppy Only the Dockerfile relative location is part of the resulting image names (by being concatenated to the basename provided to docker build -t. Regarding context, I'm clearly in favor of "context is where the Dockerfile sits" because I think it's the least surprising behavior.

I'm updating the proposal, thank you all for your comments.

@proppy
Copy link
Contributor

proppy commented Nov 17, 2014

Regarding context, I'm clearly in favor of "context is where the Dockerfile sits" because I think it's the least surprising behavior.

true, and it would also create confusion w/ different contexts depending of you build a sub image from its own root, or from the parent.

But still I think that @jpetazzo has a point, often you want to share a piece of code from the same source directory between multiple images. And there is no easy way to do that today, even with separate docker build call.

Only the Dockerfile relative location is part of the resulting image names (by being concatenated to the basename provided to docker build -t.

I think it would be useful to give the user more control on the name, too.

@icecrime, maybe something like this would work, context is still the Dockerfile root directory, but you add support for label: in DockerfileIndex to:

  • (a) allow something different than the default naming against the directory name (something you have poor control over the layout of your sources if you're using scaffolding tools)
  • (b) root the dockerfile (and thus pinning the context) to a different directory.
$ find .
frontend/
frontend/frontend.go
backend/
backend/backend.go
proxy/proxy.go
proxy/Dockerfile
contrib/logroller/logroller.go
contrib/logroller/Dockerfile
common/common.go
DockerfileIndex
frontend.dockerfile
backend.dockerfile
$ cat DockerfileIndex
front: frontend.dockerfile
back: backend.dockerfile
proxy/Dockerfile
logroller: contrib/logroller/Dockerfile
$ docker make -t proppy/myapp
building proppy/myapp/front ... # context is ./, Dockerfile is frontend.dockerfile
building proppy/myapp/back ... # context is ./, Dockerfile is frontend.dockerfile
building proppy/myapp/proxy ... # context is proxy/, Dockerfile is proxy/Dockerfile
building proppy/myapp/logroller ... # context is contrib/logroller, Dockerfile is contrib/logroller/Dockerfile
$ docker make -t proppy/myapp front
building proppy/myapp/front ...

@phemmer
Copy link
Contributor

phemmer commented Dec 16, 2014

Just stumbled across this proposal, and it seems like there's a lot of overlap with #7115
Both proposals allow building multiple images from separate Dockerfiles. There are only 2 notable differences that I see:

  1. This proposal has the Dockerfiles as real separate files, where as Proposal: Nested builds #7115 has them embedded within the main docker file. I think Proposal: Nested builds #7115 could be easily modified to add syntax for reading an external Dockerfile in addition to embedding it.
  2. This proposal has tags being added to the images. This possibility was mentioned in Proposal: Nested builds #7115, but not followed up on.

I personally find #7115 more powerful, as it allows the builds to interact with each other (pass data), which opens up a lot of options. If it can be tweaked to support all the objectives of this proposal (and it sounds like it easily can), I would favor it.

@jessfraz jessfraz added kind/feature Functionality or other elements that the project doesn't currently have. Features are new and shiny and removed kind/feature Functionality or other elements that the project doesn't currently have. Features are new and shiny labels Feb 26, 2015
@jessfraz jessfraz added kind/feature Functionality or other elements that the project doesn't currently have. Features are new and shiny and removed kind/proposal kind/feature Functionality or other elements that the project doesn't currently have. Features are new and shiny labels Sep 8, 2015
@SimenB
Copy link

SimenB commented Oct 29, 2016

Any news here?

@thaJeztah
Copy link
Member

Yes, this was implemented in #9707, which is in Docker 1.5 and up, so this can be closed

@thaJeztah thaJeztah added this to the 1.5.0 milestone Oct 29, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/builder kind/feature Functionality or other elements that the project doesn't currently have. Features are new and shiny
Projects
None yet
Development

No branches or pull requests

7 participants