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

Interpolate Variables set by environment or env_file #3435

Closed
darkn3rd opened this issue May 9, 2016 · 31 comments
Closed

Interpolate Variables set by environment or env_file #3435

darkn3rd opened this issue May 9, 2016 · 31 comments

Comments

@darkn3rd
Copy link

darkn3rd commented May 9, 2016

Summary

Enhancement request that environment variables set from within the docker-compose.yml file could be used elsewhere.

This would make docker-compose more dynamic instead of current static nature. Right now have to compose some wrapper script to compose docker-compose to compose containers.

Docker-Compose file examples

version: '2'
services:
  database:
    environment:
      - POSTGRES_VERSION="9.4"
    image: "postgres:${POSTGRES_VERSION}"
version: '2'
services:
  web:
    environment:
      - APP_ROOT="/app"
    build: .
    command: ${APP_ROOT}/wrapper.sh
    volumes:
      - ./logs/:${APP_ROOT}/logs
    ports:
      - "8080:8080"
@blankenhaus
Copy link

Would https://docs.docker.com/compose/env-file/ not do it ?

@darkn3rd
Copy link
Author

darkn3rd commented May 10, 2016

For this enhancement request, I would also like the env_file as described the docs (https://docs.docker.com/compose/compose-file/#env-file) to be supported as well, so that they are interpolated in the docker-compose.yml.

The default command-line supported for a static .env doesn't support having multiple types of env files, such as test.env and dev.env. In the interim solution would to have, ENV_FILE_PATH=${RAILS_ENV}.env docker-compose up, such as #3399.

Purposefully keeping examples simple (would use something more complex, e.g. local dev mount points, test assets, persistent store links, etc):

db.env

POSTGRES_VERSION="9.4"

docker-compose.yml

version: '2'
services:
  database:
    env_file: 
      - ./db.env
    image: "postgres:${POSTGRES_VERSION}"

Or another example

app.env

APP_ROOT="/app"

docker-compose.yml

version: '2'
services:
  web:
    env_file: 
      - ./app.env
    build: .
    command: ${APP_ROOT}/wrapper.sh
    volumes:
      - ./logs/:${APP_ROOT}/logs
    ports:
      - "8080:8080"

Currently, this outputs that following in 1.7.1:

WARNING: The POSTGRES_VERSION variable is not set. Defaulting to a blank string.

@blankenhaus
Copy link

blankenhaus commented May 11, 2016

Ok, now I understand what you want. That makes sense to me.
Another way to solve this is to have a default developer .env file inside each of your images. Then in production you map in a different file via the --volume option.

@darkn3rd
Copy link
Author

darkn3rd commented May 18, 2016

Not sure I understand, as I thought .env was pulled from $PWD and used to launch containers, not within the container image itself. My use case is to support dynamic environments without specifying numerous environment variables prefixed to docker-compose, or using an external tool like ansible or vagrant.

@blankenhaus
Copy link

Right, so you can get there by mapping those specific .env files into the container via the -v flag. Then inside your container your startup script always sources in .env.

@cecchisandrone
Copy link

+1 for this feature

@darkn3rd
Copy link
Author

darkn3rd commented Jul 8, 2016

I have been using .env heavily now. Given this understanding, I would recommend for compose variables that there's a section outside of services: where we can have an area to define variables. This would be the similar functionality of .env introduced in 1.7.0, but just within the docker-compose.yml. These variables would be inherited by any extends. External environment variables would override this behavior.

Thus given above, you'd have:

version: '2'
variables:
  - APP_ROOT="/app"
services:
  web:
    env_file: 
      - ./app.env
    build: .
    command: ${APP_ROOT}/wrapper.sh
    volumes:
      - ./logs/:${APP_ROOT}/logs
    ports:
      - "8080:8080"

I used variables: for this example, but could be whatever is appropriate, such as globals: or compose_env:, whatever makes sense.

@jpooler
Copy link

jpooler commented Jul 12, 2016

I support fixing the hardcoding of the env_file per: #3399

I did some digging and don't think it would take a ton of effort, but am not familiar enough(or maybe a lack of more complex coding skills) with the codebase to implement.

I was thinking of something along the lines of the logic of the process_service method in compose/config/config.py being called/passing the service_dict to compose/config/environment.py:from_env_file to replace:

env_file = os.path.join(base_dir, 'env')

with

env_file = os.path.join(base_dir, service_dict['env_file'])

Obviously there's a few steps between that,happy to offer help/collaborate with anyone else on this too.

I am also happy to open a new issue, but thought this issue made the most sense to add this to.

@aanand
Copy link

aanand commented Jul 12, 2016

While I understand the use cases for such a feature, I don't think it's a good idea to overload env_file with extra meaning. It's supposed to be simply analogous to the docker run --env-file parameter.

@jpooler
Copy link

jpooler commented Jul 13, 2016

Totally agree, but the behavior I'm currently seeing isn't inline with the docs (I am happy to open a separate issue if you would like). Basically I'm trying to specify a custom ENV file that's not "${PWD}/.env"

https://docs.docker.com/compose/compose-file/#/env-file
Doc example:

env_file:
  - ./common.env
  - ./apps/web.env
  - /opt/secrets.env

Leads me to believe the below should work

My compose file:

version: '2'
services:
  APP:
    env_file: './jarrod.env'
    build:
      args:
        NODE_ENV: ${NODE_ENV}
      context: ../../APP
    image: APP:${git_branch}
    ports:
     - "XX:XX"
    environment:
      - NODE_ENV=${NODE_ENV}

my jarrod.env file:

cat jarrod.env
#Note if you have this value specified in your terminal, it will take precedence over this file!!!
NODE_ENV=FAIL
git_branch=FAIL

When I try to build the image:

docker-compose build APP
WARNING: The NODE_ENV variable is not set. Defaulting to a blank string.
WARNING: The git_branch variable is not set. Defaulting to a blank string.
ERROR: Couldn't find env file: /Users/jpooler/Tools/docker_compose/.env
jpooler [~/Tools/docker_compose] (master)$ docker-compose version
docker-compose version 1.8.0-rc2, build c72c966
docker-py version: 1.9.0-rc2
CPython version: 2.7.9
OpenSSL version: OpenSSL 1.0.2h  3 May 2016

 jpooler :[~/Tools/docker_compose] (master)$ docker version
Client:
 Version:      1.12.0-rc2
 API version:  1.24
 Go version:   go1.6.2
 Git commit:   906eacd
 Built:        Fri Jun 17 20:35:33 2016
 OS/Arch:      darwin/amd64
 Experimental: true

Server:
 Version:      1.12.0-rc3
 API version:  1.24
 Go version:   go1.6.2
 Git commit:   91e29e8
 Built:        Sat Jul  2 00:17:11 2016
 OS/Arch:      linux/amd64

@aanand
Copy link

aanand commented Jul 13, 2016

@jpooler This is working normally. env_file is analogous to docker run --env-file: all variables defined in any of the specified files are passed through to the container. They are not made available for environment variable interpolation.

We should perhaps make the docs clearer, but this isn't a bug.

@lucaspottersky
Copy link

They are not made available for environment variable interpolation.

@aanand you mean you can't use ${XXX} on the docker-compose.yml for variables defined in "env_files"? If that's the case, indeed the docs need to be clearer about that.

@guycalledseven
Copy link

I hate wrapper scripts as well, but I don't think that compose yml file is good place to define vars. IMHO that would lead to completely unreadable mix of vars (who is setting or reading from where?).

I have been using .env file heavily and if compose would interpolate env_file.yml with .env/shell vars the same way it does in compose.yml I would be so happy. :) (#3934).

Now if ADD/COPY would be able to pipe through something like setenv (https://github.com/subfuzion/envtpl) I wouldn't need any post-scripts at all.

@darkn3rd
Copy link
Author

darkn3rd commented Sep 11, 2016

To clear the scope, this is not about docker variables for the Dockerfile, which are already handled. This is for having the .env inside the docker-compose.yml.

In any automation system, you want to have DRY (don't repeat yourself) and also a way to have defaults that can be overridden. Docker Compose added this in 1.7.0 with the .env file for docker-compose (not to be confused with .env files for Docker used by docker-compose). This is just to have only ONE file, so that the variables are at the top.

My initial confusion when writing this up was around the time the feature was released, and the documentation (still likely) was less than adequate. It was easy to confuse the .env file for docker-compose with .env files for Docker engine that Docker-Compose uses. My proposal would be to have a section above services called, compose_env: which can list vars or a file of your choosing.

So TL;DR, don't have two files, a .env and a docker-compose.yml, just have one file docker-compose.yml with docker compose's env incorporated in the same yaml file.

@jpswade
Copy link

jpswade commented Jan 15, 2017

Workaround solution: Put this in a docker-up.sh file:

#!/usr/bin/env bash
set -a
. db.env
set +a
docker-compose up -d --build

The set -a automatically exports all variables. The . db.env will load the variables. The set +a sets exports back to normal. Then simply docker-compose up as normal.

@egel
Copy link

egel commented Jun 13, 2017

Yeah, the workaround solution from @jpswade works perfectly but is there any progress with providing native reading variables from multiple files by env_files: (as @jpooler commented few post before)?

@jacobrask
Copy link

The workaround from @jpswade means you cannot override environment variables though. FOO=bar docker-up.sh will still use FOO from db.env.

Hubbitus added a commit to Hubbitus/docker-env-override-example that referenced this issue Nov 18, 2017
@Wirone
Copy link

Wirone commented Jun 18, 2018

I personally think that docker-compose.yml should NOT define any new env variables, but only read exported ones (system wide) and support env files. Then, with interpolation, it should use them and pass to services. With YAML anchors it's already possible to reuse whole groups of variables.

It's better to separate Docker infrastucture (which compose represents) from config values. It's, for example, much safer because you can copy/paste docker-compose.yml without thinking about clearing sensitive data because everything is outside of this file.

Interpolation itself should work better, but this is totally different story...

@dovry
Copy link

dovry commented May 24, 2019

A year of no activity on this issue :(

Would absolutely love for this to be a feature. (bump)

myedibleenso added a commit to arizona-linguistics/colrc-v2 that referenced this issue Jun 21, 2019
myedibleenso added a commit to arizona-linguistics/colrc-v2 that referenced this issue Jun 27, 2019
* Testing env_file for reuse of variables

See docker/compose#3435 (comment)

* Update to env setup

Rely on env_file for all environment variables.
@col-panic
Copy link

this feature would be really helpful! (bump)

@dlupu
Copy link

dlupu commented Oct 7, 2019

+1

@ndeloof
Copy link
Contributor

ndeloof commented Oct 7, 2019

As noted by @aanand #3435 (comment), there seem to be some confusion here.
env_file is used to declare the environment file used when creating container from, as a 1:1 mapping of the docker run CLI --env-file option. It isn't involved when parsing the compose file to do any variable substition, so can't be used to customize container definition.

variable substitution as requested here is well supported using an .env file.

@ndeloof ndeloof closed this as completed Oct 7, 2019
@clvLabs
Copy link

clvLabs commented Jun 29, 2020

Just got here following the rabbit hole 😅

I would also love to be able to have variables interpolated from an env_file, and I also hate wrapper scripts.

Seeing this issue is closed I'm following the path of @jpswade

Workaround solution: Put this in a docker-up.sh file:

#!/usr/bin/env bash
set -a
. db.env
set +a
docker-compose up -d --build

But, reading @jacobrask 's comment...

The workaround from @jpswade means you cannot override environment variables though. FOO=bar docker-up.sh will still use FOO from db.env.

Made an updated version of the docker-up.sh script and wanted to share it... maybe someone else will follow the rabbit hole and find it 😄

#!/bin/bash

# Need to manually export env variables
# See: https://github.com/docker/compose/issues/3435

set -a

for assignment in $(cut -s -d= -f1,2 docker.env)
do
  varname=$(echo "$assignment" | cut -s -d= -f1 -)
  dockerenvvalue=$(echo "$assignment" | cut -s -d= -f2 -)
  bashenvvalue=${!varname}
  eval "$varname=\${$varname-$dockerenvvalue}"
done

set +a

docker-compose up --detach

Differences from the original version:

  • My env file is named docker.env instead of db.env
  • Lines in docker.env not containing an = will be ignored (allow comments)
  • This script is a lot more verbose in writing (shorten it if you will, I'll keep it long for my script)
  • Default values from the spawning shell are preserved
  • Service is not rebuilt on startup (in my case, I'm using a private registry)

@guycalledseven
Copy link

Why is this closed?

@tyliggity
Copy link

As noted by @aanand #3435 (comment), there seem to be some confusion here. env_file is used to declare the environment file used when creating container from, as a 1:1 mapping of the docker run CLI --env-file option. It isn't involved when parsing the compose file to do any variable substition, so can't be used to customize container definition.

variable substitution as requested here is well supported using an .env file.

Obviously, but the request here is that we should be able to specify an alternative file name rather than .env for variables available for compose file interpolation. The relationship here is that the env_file mapping is available to do just that for container variables. So, the same type of mechanism should be available for the .env file with respect to the compose file.

@ndeloof
Copy link
Contributor

ndeloof commented Mar 9, 2022

we should be able to specify an alternative file name rather than .env for variables available for compose file interpolation

already the case: docker compose --env-file .my.custom.env.file up

@tyliggity
Copy link

we should be able to specify an alternative file name rather than .env for variables available for compose file interpolation

already the case: docker compose --env-file .my.custom.env.file up

Never tried this with compose! Thanks for the tip 👍

@johnnybenson
Copy link

johnnybenson commented Mar 11, 2022

It's pretty inexplicable for variables to interpolate implicitly from .env but not from the env_file: './jarrod.env' expressed within docker-compose.yml for the given service—especially in 2022 with monorepos coming back into style. Each application within a single repo will have its own .env in its subdirectory and Docker requires instrumentation from a place higher up in the repository because a Dockerfile cannot traverse outside of its context.

image
👀

@ndeloof
Copy link
Contributor

ndeloof commented Mar 12, 2022

env_file: './jarrod.env' set in your compose.yaml file is here to define container's environment, it has no impact on the variable interpolation. Just consider this a 1:1 mapping with docker run --env-file.

@murad-tech
Copy link

murad-tech commented Mar 31, 2024

Does anyone found a solution for this? Sorry but it is rude to close unresolved issue.
The whole point of specifying env_file in docker-compose.yml is to pull custom env vars.
What is a point of env_file: if we anyway should use --env-file .dev.env.

@ndeloof
Copy link
Contributor

ndeloof commented Mar 31, 2024

env_file: is used to set container's environment, not to interpolate variables in compose.yaml

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

No branches or pull requests