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

Dockerfile with variable interpolation (template) #2022

Closed
noteed opened this issue Sep 27, 2013 · 9 comments
Closed

Dockerfile with variable interpolation (template) #2022

noteed opened this issue Sep 27, 2013 · 9 comments

Comments

@noteed
Copy link

noteed commented Sep 27, 2013

I have started a Dockerfile for a mail server based on Postfix. It appears various hard-coded values (e.g. hostname) are present in the Dockerfile, making it harder for someone else to use it.

It would be nice to have the possibility to use variables in the Dockerfile that would be defined through flags, or through some configuration file when using the docker build command.

(The Postfix Dockerfile is at https://github.com/noteed/docker-postfix)

@gurjeet
Copy link
Contributor

gurjeet commented Oct 20, 2013

@noteed Do you think this requirement of yours can be satisfied via the ENV command in Dockerfile? See http://docs.docker.io/en/latest/use/builder/#env

@noteed
Copy link
Author

noteed commented Oct 20, 2013

@gurjeet ENV can be set from the command-line only with the run instruction, not the build one. Anyway I'm not sure it would be very practical.

@tianon
Copy link
Member

tianon commented Oct 20, 2013

If you supply -e to docker run, it will overwrite ENV lines from the original Dockerfile, so as long as the ENTRYPOINT or CMD are where the configuration gets generated (which is where they ought to be, since every time you docker run you effectively have a new machine and thus usually new configuration required).

@noteed
Copy link
Author

noteed commented Oct 20, 2013

@tianon I was discussing this problem with a specific example, namely a Postfix-based mail server (althoug I believe this could apply to other situations). This involves a few configuration files, possibly the generation of database schema, users, ... Do you suggest that those configuration files be rewritten each time docker run is called, possibly with enough machinery to re-create everything that depends on those configuration files ? That machinery is exactly what a Dockerfile is supposed to do.

Obviously one possibility is to create an image, that when run can create a configured image (the final mail server), and the "generator" image would be given a configuration (possibly with -e). This looks precisely as what I'm asking: a simple way to generate images from a fixed configuration. Sure I can do it manually or craft some script to do it for me. But I think this is a general, common enough usecase for Docker.

@tianon
Copy link
Member

tianon commented Oct 20, 2013

Well, because docker run creates a brand new container every time, you're either looking at one-configuration-fits-all, modifying the configuration at run-time, outright generating the configuration at run-time, or completely recreating the image every time (which with Dockerfile caching isn't too bad, as long as your configuration lines are far enough down in the file).

I'm not saying that variables in the Dockerfile are a bad idea, I just want to make sure the use-case is understood properly. I honestly like the idea myself. :)

@noteed
Copy link
Author

noteed commented Oct 20, 2013

I'm pretty sure we understand each other. Just to add to the conversation:

The "every time" you mention is really "once for each static configuration". I.e. your mail server is configured differently than mine (you have a different domain, different users), but you don't re-configure it each time you re-run it.

There is a blurred line between what could be considered static (provided at docker build time) vs. dynamic (provided at docker run time) configuration but I think having also the former possibility would nice. And it is not just "nice" in my opinion it is quite natural with what a Dockerfile already is: let say you have two very similar images, one with run apt-get install -q -y vim and the other with run apt-get install -q -y emacs. Flame war aside, this is clearly a "static" configuration: you don't want to run apt-get install each time you use the image; instead you want that part be baked in the image already.

@shykes
Copy link
Contributor

shykes commented Nov 27, 2013

This is a common question on usage pattern, which deserves its own thread on the user mailing list. I will summarize it as "how to containerize an application in such a way that it allows the end user to customize configuration files?".

My short answer is that there are several ways to go about this:

  • Method 1: wrapper + entrypoint. Wrap your application with a script which generates a configuration file based on other forms of user input (environment variables, command arguments or stdin) then passes control to the original application. Make this transparent to the user by making your wrapper the ENTRYPOINT of your container.
  • Method 1b: wrapper + path. Same as wrapper+entrypoint, except you use the ENV build directive to change the $PATH environment variable, so that typing my_app executes your wrapper instead of the actual my_app. I recommend against this method - use wrapper+entrypoint instead.
  • Method 2: base image. If your container requires the user to add more files before it's fully usable, then it's not yet in its fully built form. Rather, it's an intermediary base image which you are distributing to the end user so that they can complete their own custom build. In other words, the end user should create a Dockerfile of their own, use your image as a base with the FROM build directive, then ADD the required files from their own source repo to complete the build. In your example, they might maintain a custom postfix configuration in a git repository, alongside the Dockerfile. You have the choice of making these user-provided config files mandatory or optional. If they are mandatory, the image should fail to run on its own, ideally with an helpful error message pointing to documentation for using it as a base image instead. If they are optional, presumably your image ships with a decent default configuration and can be run on its own - in that case you can add an "advanced usage" section to your documentation which explains how to build your own image with yours as a base.

I hope this helps!

@shykes shykes closed this as completed Nov 27, 2013
@shykes
Copy link
Contributor

shykes commented Nov 27, 2013

FYI I shared my answer in a new thread on the user mailing list

@saidimu
Copy link

saidimu commented Feb 10, 2014

The new ONBUILD directive is another solution.

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

No branches or pull requests

5 participants