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

ENV variables not available at build time for Dockerfile deploys #1860

Closed
craigbeck opened this issue Jan 12, 2016 · 36 comments
Closed

ENV variables not available at build time for Dockerfile deploys #1860

craigbeck opened this issue Jan 12, 2016 · 36 comments

Comments

@craigbeck
Copy link

The docs say "The variables are available both at run time and during the application build/compilation step." but I've not seen this actually happen at build time.

actual app config:

$ ssh dokku@test config adminapp                                                                                                                                                                
=====> adminapp config vars
API_BASE:              //adminapp-api.test.zipwhip.com
DOKKU_APP_RESTORE:     1
DOKKU_DOCKERFILE_PORT: 80
DOKKU_NGINX_PORT:      80
NODE_ENV:              production
PATH_PREFIX:           /admin

I'm logging from my build script, so at build time I see:

Step 1 : RUN NODE_ENV=production webpack -p
 ---> Running in 0826574bc4e0
===> Building with NODE_ENV 'production'
===> Building with PATH_PREFIX 'undefined'
===> Building with API_BASE 'undefined'
Hash: 54683fe2b93e4d330eed
Version: webpack 1.12.11
Time: 170802ms
...

The NODE_ENV var is only set because I prefixed the Dockerfile build step with NODE_ENV=production while the other vars I expect to be set (PATH_PREFIX and API_BASE) are still undefined.

This is with dokku version 0.4.7

$ ssh dokku@test version
0.4.7
@craigbeck
Copy link
Author

This is using a Dockerfile based build

@josegonzalez
Copy link
Member

We only support build-time env vars for buildpack deploys.

@michaelshobbs Was this a conscious decision? I know we implemented dockerfile deploys way after build-env, so it's possible we just missed it (given that dockerfile-deploys aren't in the forefront of our development). Seems like they could be useful.

@josegonzalez josegonzalez changed the title ENV variables not available at build time ENV variables not available at build time for Dockerfile deploys Jan 12, 2016
@craigbeck
Copy link
Author

I have a Dockerfile based deployment that runs nginx and serves a statically-built web app, so the standard env vars aren't available at run time because the app is static (i.e. no process at run time to modify the response). The documentation isn't clear on these not being available (honestly thought it was just a bug in the older version of Dokku we had been running, but it was still an issue after upgrading)

@josegonzalez
Copy link
Member

Yeah I agree the docs aren't clear. I'm just trying to figure out if we should support it, and if so, what the best way to do that is.

We'll get this issue sorted out soon enough (@michaelshobbs is probably at lunch) and figure out if the only thing we should do is update docs, or if we need to update docs/implement the functionality. IMO this is a bug and we need to implement it (though potentially for the upcoming 0.5.0 since it might break existing dockerfile apps).

I'm on our irc room as savant if you'd like to chat there :)

@craigbeck
Copy link
Author

I did some poking around in the Docker docs and repo. @Jaon-Grant's comment was useful: moby/moby#6822 in pointing me to the Docker --build-arg options and ARG command... which renders my Dockerfile onbuild a lot less elegant than it was but I'm not sure what to do about it right now.

I'm trying a combination of Dokku docker-options with build-args set on the build phase with changes to my Dockerfile.

@josegonzalez
Copy link
Member

Yeah, my thinking is that we would use our docker-options integration to make a small pluginhook that adds them as a build-arg for dockerfile deploys. I'm not sure how that would work, but it seems possible.

@michaelshobbs
Copy link
Member

See the discussion here: #1255 (comment)

@michaelshobbs
Copy link
Member

I'm not sure when --build-arg was introduced but perhaps that can now be used in the build-env plugin to provide build time env vars.

@josegonzalez
Copy link
Member

Looks like 1.9.0, so fairly recent... I wonder if we can optionally support this? I don't remember where we left off re: supported docker versions in 0.5.0.

@josegonzalez
Copy link
Member

Somewhat relevant: moby/moby#13490

@michaelshobbs
Copy link
Member

Specifically

Build-time environment variables (#9176, #15182). The build-time environment variables were not designed to handle secrets. By lack of other options, people are planning to use them for this. To prevent giving the impression that they are suitable for secrets, it's been decided to deliberately not encrypt those variables in the process.

@josegonzalez
Copy link
Member

If we're not going to support this for dockerfile deploys, we should definitely document that. We only do so for buildpack builds because we are following heroku on that path.

@michaelshobbs
Copy link
Member

Agreed

@craigbeck
Copy link
Author

After looking into this some more, the Dockerfile needs to be changed to accept the build args and any build args passed need to be used by the Dockerfile... so it's not feasible to just pass the app's environment variables to docker build because if the Dockerfile doesn't expect them the build fails.

The workaround is to use the docker-options on the build phase to pass the specific args required by the Dockerfile.

@josegonzalez
Copy link
Member

@craigbeck Other than stating that build-env only works for buildpacks deploys, what should I put in the documentation to help other users in your situation?

@craigbeck
Copy link
Author

@josegonzalez thinking about that right now to write something up

@josegonzalez
Copy link
Member

<3 :)

@craigbeck
Copy link
Author

I wrote something up about how I solved the problem of build args: http://craigbeck.io/blog/2016/01/13/dokku-plus-dockerfile-deployments/

  • dokku build-options:add myapp build '--build-arg "PATH_PREFIX=/myapp"'
  • modify your dockerfile
FROM baseimage

ARG PATH_PREFIX                            # declare PATH_PREFIX as build arg
RUN PATH_PREFIX=${PATH_PREFIX} ./dobuild   # use PATH_PREFIX (in this case via environment variable)

@ghost
Copy link

ghost commented Jan 20, 2016

For anyone running into issues passing NODE_ENV as a build-arg...try just passing it as NODE instead, such as:

docker build --build-arg NODE=development --rm -t some/name .

and in Dockerfile:

ARG NODE=production
ENV NODE_ENV ${NODE}
RUN npm start

@makenosound
Copy link

@josegonzalez This is also something I’d love to see for Dockerfile based deploys now that --build-args is supported in Docker.

@craigbeck Thanks for the post with your workaround so far!

@tobru
Copy link
Contributor

tobru commented Feb 16, 2016

@craigbeck thanks a lot for your post, it really helps me! But one thing is not yet clear to me: The build/release process I have in mind when having a static HTML5/JS app:

  1. Build docker image for building the static app, containing NodeJS, NPM and Grunt (using the file Dockerfile, which is also used for development). Here I pass the --build-arg "ENVIRONMENT=production" option to configure the static app
  2. Run build process (grunt build:production) in previously built Docker container, mapping the dist/ directory to the host to have access to the build artifacts
  3. Build production image with only Nginx and the static build artifacts with a different Dockerfile Dockerfile.nginx

How are you doing that with Dokku? Seems a bit complicated to me, but probably I have not yet find the correct way. How does your build process look like?

@craigbeck
Copy link
Author

@tobru I have a Docker image that has node + nginx setup to serve my statically built app from /app/dist. Dokku invokes the Dockerfile to build the app then runs the resulting image. Sounds like you are trying to use two images (build container/built app, and nginx)?

@tobru
Copy link
Contributor

tobru commented Feb 17, 2016

@craigbeck Yes, that's true. The idea was to only have the needed parts in the resulting Docker image, the statically built HTML5/JS app doesn't need NodeJS to run, only for building it. I want to have only the really needed things in the image: nginx + app. But probably this is not possible with Dokku without modification or plugin?

@josegonzalez
Copy link
Member

I don't think we can set alternative dockerfiles for the dokku run - @michaelshobbs correct me if I am wrong - but it should be possible for you to do this with one Dockerfile and a custom ENTRYPOINT that either runs nginx to serve your stuff or just bails out. I would personally always compress assets upon deployment, but thats just me.

@michaelshobbs
Copy link
Member

dokku run is definitely bound to the built app image.

@tobru If the concern is having node and other binaries necessary for the building of the app but not the running of the app, why not include some cleanup RUN directive towards the end of your dockerfile that remove the unnecessary bits?

@tobru
Copy link
Contributor

tobru commented Feb 17, 2016

@michaelshobbs yeah, this will be probably the way to go. (sorry for hijacking this thread for this particularly unrelated question)

@tobru
Copy link
Contributor

tobru commented Feb 24, 2016

Just for clarification: the correct command is dokku docker-options:add myapp build '--build-arg "PATH_PREFIX=/myapp"' (docker-options vs. build-options)

josegonzalez added a commit that referenced this issue Mar 18, 2016
Document when configuration variables are available. Closes #1860
@michael-px
Copy link

I tried doing a build with --build-arg VERSION="string" and docker 1.11.2 barfed.

The docs don't say it supported, so did this RFE die or it just hasn't shown up in the docker yet.

Modifying a config file inside a container with the Jenkins build and GIT small SHA1 becomes a major task without being able to pass environment variables to builds.

@josegonzalez
Copy link
Member

@michael-px can you open up a new issue and include all of the information we ask for in our issue template? It is helpful for debugging problems. Thanks.

@blocka
Copy link

blocka commented Oct 21, 2016

For anybody running into this problem:

dokku docker-options:add myapp build '--build-arg "PATH_PREFIX=/myapp"'

was creating a build arg "PATH_PREFIX instead of PATH_PREFIX. This took me a long time to realize.

@josegonzalez
Copy link
Member

@blocka do you mind making a pull request for our docker-options documentation to make that more clear?

@diogocaetano
Copy link

diogocaetano commented May 31, 2017

After hours trying to make it work...
Work for me in this way:

dokku docker-options:add myapp build '--build-arg NODE_ENV=production'

dockerfile

ARG NODE_ENV=production
ENV NODE_ENV ${NODE_ENV}
RUN echo $NODE_ENV

Use ARG for default value even you don't need.

Hopeful that helps someone. #2776

@templth
Copy link

templth commented Jun 6, 2017

@diogocaetano thanks very much for the hint! I tried your approach but it doesn't work for me :-( My dokku version is 0.9.4 and docker 17.05.0-ce. The default value I specified isn't replaced by the value configured using docker-options.

Do you know if it's possible to have the list of set variables? I try to find out a way to debug this problem... Thanks!

@anatoliyarkhipov
Copy link

Also, there might be a situation when you want to automatically propagate variable from config to the Docker arguments. For example, the PostgreSQL Dokku plugin sets DATABASE_URL in the app config, and it isn't available during the build stage when using Dockerfile.

One way to deal with that is to just manually copy its value and add as a Docker build argument:

dokku docker-options:add app build '--build-arg DATABASE_URL=postgres://a:b:c/database'

But I personally don't like it, because if the variable is changed in the config, I'd have to remember to update the Docker argument as well. So instead of the command above I used this one:

dokku docker-options:add app build '--build-arg DATABASE_URL=`dokku config:get app DATABASE_URL`'

The dokku config:get app DATABASE_URL part, wrapped with backticks (), returns current value of DATABASE_URL` on the fly, so if it's changed in the config, the new value will be used during the next build automatically.

Not sure how idiomatic is that, but it works.

@josegonzalez
Copy link
Member

If anyone wants to see this land in the core, you'll need to make a pull request for it. Note that I won't be default whitelisting all environment variables for use within the app, so you'll need to come up with a new interface for it, like dokku builder-docker:config-whitelist APP ENV_VAR.

@dokku dokku locked as resolved and limited conversation to collaborators Dec 5, 2019
@josegonzalez
Copy link
Member

Locking as this is otherwise resolved, and any new discussion on this should be done via a pull request.

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

No branches or pull requests

10 participants