148

Is it possible to re-use environment variables that are shared among multiple containers?

The idea is to avoid duplication, as illustrated in this example:

version: '2'

services:

  db:
    image: example/db
    ports:
      - "8443:8443" 
    container_name: db
    hostname: db
    environment:
      - USER_NAME = admin 
      - USER_PASSWORD = admin 

svc:
  image: example/svc
  depends_on:
    - db
  ports:
    - "9443:9443"
  container_name: svc
  hostname: svc
  environment:
    - DB_URL = https://db:8443
    - DB_USER_NAME = admin
    - DB_USER_PASSWORD = admin 
janw
  • 8,758
  • 11
  • 40
  • 62
Sergei Rodionov
  • 4,079
  • 6
  • 27
  • 44

3 Answers3

242

The extends option can be nice but it's not supported in 3.x compose files. Other ways to go are:

  1. Extension fields (compose file 3.4+)

    If you can use 3.4+ compose files, extension fields are probably the best option:

    docker-compose.yml

     version: '3.4'
    
     x-common-variables: &common-variables
       VARIABLE: some_value
       ANOTHER_VARIABLE: another_value
    
     services:
       some_service:
         image: someimage
         environment: *common-variables
    
       another_service:
         image: anotherimage
         environment:
           <<: *common-variables
           NON_COMMON_VARIABLE: 'non_common_value'
    
  2. env_file directive

    docker-compose.yml

     version: '3.2'
    
     services:
       some_service:
         image: someimage
         env_file:
           - 'variables.env'
    
       another_service:
         image: anotherimage
         env_file:
           - 'variables.env'
    

    variables.env

     VARIABLE=some_value
     ANOTHER_VARIABLE=another_value
    
  3. .env file in project root (or variables at actual compose environment)

    Variables from .env file can be referenced in service configuration:

    docker-compose.yml

     version: '3.2'
    
     services:
       some_service:
         image: someimage
         environment:
           - VARIABLE
    
       another_service:
         image: anotherimage
         environment:
           - VARIABLE
           - ANOTHER_VARIABLE
    

    .env

     VARIABLE=some_value
     ANOTHER_VARIABLE=another_value
    
Yi Ou
  • 3,242
  • 1
  • 11
  • 12
Lumi Akimova
  • 2,547
  • 1
  • 11
  • 14
  • 6
    For those not too familiar with YAML: see "Merge key language" in YAML as to the reason for the notation==> environment: <<: *common-variables. Basically &foo means "foo will be a reused variable", *foo denotes the reuse of a vars, and <<: inserts the variable mapping that follows into the current key. I'd edit but So says edit queue is full for some reason. – logicOnAbstractions Sep 24 '20 at 17:03
  • @logicOnAbstractions My link to extension fields documentation can be enough, the YAML feature is explained there – Lumi Akimova Sep 28 '20 at 16:31
  • 1
    Is it possible to reuse extension fields for substitution in `docker-compose.yml`? – Andrius Oct 05 '21 at 18:00
  • The extension fields work really well for reusing mappings, but unfortunately the merge key isn't supported for arrays. Does anyone know of a work around to use extension fields for arrays? – colelemonz Oct 05 '22 at 21:39
  • 1
    @colelemonz The best we can have is reusing values of specific keys: https://stackoverflow.com/a/27022292/4655476 – Lumi Akimova Oct 06 '22 at 22:23
  • 1
    @Wolphin is right! This is misleading and lead to more time than I would like wasting!!!! – the_real_one Jan 21 '23 at 20:34
45

You can use the extends directive (available in compose 1.x and 2.x) to have multiple containers inherit the environment configuration from an underlying service description. For example, put the following in a file named base.yml:

version: '2'

services:
  base:
    environment:
      DB_URL: https://db:8443
      DB_USER_NAME: admin
      DB_USER_PASSWORD: admin 

Then in your docker-compose.yml:

version: '2'

services:
  container1:
    image: alpine
    command: sh -c "env; sleep 900"
    extends:
      file: base.yml
      service: base

  container2:
    image: alpine
    command: sh -c "env; sleep 900"
    extends:
      file: base.yml
      service: base
    environment:
      ANOTHERVAR: this is a test

Then inside of container1, you will see:

DB_URL=https://db:8443
DB_USER_NAME=admin
DB_USER_PASSWORD=admin

And inside of container2 you will see:

DB_URL=https://db:8443
DB_USER_NAME=admin
DB_USER_PASSWORD=admin
ANOTHERVAR=this is a test

You can obviously use extends for things other than the environment directive; it's a great way to avoid duplication when using docker-compose.

tbobm
  • 113
  • 1
  • 9
larsks
  • 277,717
  • 41
  • 399
  • 399
  • `extends` works well for my use case. It's preferable over local variables because it removes dependency on particular user. Another thing I can do with `extends` is to specify common container labels. – Sergei Rodionov Mar 29 '16 at 13:59
  • can I `extends` more than one service? or from more than one file per service? – Philipp Kyeck Feb 28 '18 at 15:48
  • For anyone else that is getting a FileNotFoundError when calling things from a subdirectory, you can use the relative path of the file instead: "./base.yml" – Adverbly Oct 19 '18 at 17:39
7

You can reference local environment variables from within a docker-compose file. Assuming what you're wanting to do is make USER_NAME the same as DB_USER_NAME:

docker-compose.yml

version: '2'

services:
  db:
    image: example/db
    ports:
      - "8443:8443" 
    container_name: db
    hostname: db
    environment:
      - USER_NAME = ${USERNAME}
      - USER_PASSWORD = ${PASSWORD}

svc:
  image: example/svc
  depends_on:
    - db
  ports:
    - "9443:9443"
  container_name: svc
  hostname: svc
  environment:
    - DB_URL = https://db:8443
    - DB_USER_NAME = ${USERNAME}
    - DB_USER_PASSWORD = ${PASSWORD}

Then, run docker-compose like:

$ USERNAME="admin" PASSWORD="admin" docker-compose up

Alternately, for something more permanent, and easier to type on a recurring basis:

$ printf '%s\n%s\n' 'export USERNAME="admin"' 'export PASSWORD="admin"' >> ~/.bash_profile
$ source ~/.bash_profile
$ docker-compose up
ThatsNinja
  • 374
  • 1
  • 9
  • 4
    i think ```$ USERNAME="admin" PASSWORD="admin" docker-compose up``` is not good. hacker like ```$ history``` and get password with history cmd – Changwoo Rhee Jul 30 '20 at 19:36
  • 2
    @ChangwooRhee if you're using sensitive credentials for docker-compose locally you've got problems that are not technology-related – ThatsNinja Aug 03 '20 at 19:07
  • nothing wrong with local sensitive creds, in a non versioned file etc. But passing them as you do is worse, and an argument about something else being bad doesn't negate it's bad advice. – James Dec 19 '21 at 20:32
  • 1
    @James Perhaps I should have been more explicit: One should never have sensitive credentials locally. In fact, ideally, one should never have a human knowing the password to a production database. – ThatsNinja Dec 30 '21 at 14:59