Shōgun8
Shōgun8

Reputation: 562

How can I pass the variables I have placed in the .env file to the containers in my docker swarm?

I am trying to use the same docker-compose.yml and .env files for both docker-compose and swarm. The variables from the .env file should get parsed, via sed, into a config file by running a run.sh script at boot. This setup works fine when using the docker-compose up command, but they're not getting passed when I use the docker stack deploy command.

How can I pass the variables into the container so that the run.sh script will parse them at boot?

Upvotes: 6

Views: 8574

Answers (5)

Valentine Shi
Valentine Shi

Reputation: 7802

In 2024 due to ongoing Compose and Swarm development the other answers age, unfortunately. If you need the variables interpolation in your Swarm compose files here is what works to date.

Summary: docker compose -f file.yml config... does not produce the compose file required for Swarm. Neither docker stack deploy --compose-file... would interpolate env_file variables. Use docker stack config (docs) first instead, then forward its outcome to docker stack deploy....

Here is the example.

# file: a-service.swarm.yml

services:
  a-service:
    image: "image:tag"
    env_file:
      # Provide container (!) with environment variables at runtime
      # Will not provide variables interpolation at Swarm build time with 
      # `docker stack deploy --compose-file a-service.swarm.yml my-stack` 
      - ./some.env
    environment:
      # This is required to override the uninterpolated 'env_file' variables
      # that require interpolation
      - REQUIRES_INTERPOLATION=${A_VALUE:-default_constant_value}
# file: some.env
A_VALUE=a-value
DOES_NOT_REQUIRE_INTERPOLATION=another-value
# A_VALUE not going to be interpolated with `env_file`
# But it is with `docker stack config...`
REQUIRES_INTERPOLATION=${A_VALUE:-default_constant_value}
docker stack config --compose-file a-service.swarm.yml > processed.swarm.yml
docker stack deploy --compose-file processed.swarm.yml my-service

Look up the interpolated values in processed.swarm.yml when you debug the thing.

Upvotes: 1

BMitch
BMitch

Reputation: 263469

Loading the .env file is a feature of docker-compose that is not yet supported in docker stack commands. You can manually load the contents of this file in your shell before performing the deploy:

set -a; . ./.env; set +a
docker stack deploy -c docker-compose.yml stack_name

Other options include using docker-compose to pre process the compose file:

docker compose config >docker-compose.processed.yml

Or you could use envsubst to replace the variables to make a compose file with the variables already expanded:

set -a; . ./.env; set +a
envsubst <docker-compose.yml >docker-compose.processed.yml

Note that the .env file is different from an env_file section of a compose file. The .env file is used to expand variables in the compose file itself. The env_file declaration for a service injects environment variables into the container.

Upvotes: 12

Jakob Guldberg Aaes
Jakob Guldberg Aaes

Reputation: 844

As mentioned the native env_file is limited to docker compose BUT there proper way to do it in swarm is to user docker stack config

say we have a .env file

foo=bar

and a compose file

version: "3.9"
services:
  myservice:
    env_file:
    - .env

Then calling config yields the following

❯ docker stack config -c docker-compose.yml
version: "3.9"
services:
  myservice:
    environment:
      foo: "bar"

putting it together with deploy we get

docker stack config -c docker-compose.yml | docker stack deploy -c - mystack

docker stack deploy -c <(docker stack config -c docker-compose.yml mystack) mystack


If you want to have a variable docker-compose.yml where you need to interpolate the docker-compose with variables from the .env file you can do this crazy hack

export $(grep -v '^#' .env-test | xargs) && docker stack config -c docker-test.yml

the compose file:

---

version: "3.9"

services:
  myservice:
    image: ${THE_IMAGE_NAME}
    env_file: .env

the .env file:

a=1
THE_IMAGE_NAME=owner/image

the output:

❯ export $(grep -v '^#' .env | xargs) && docker stack config -c docker-compose.yml
version: "3.9"
services:
  myservice:
    environment:
      THE_IMAGE_NAME: owner/image
      a: "1"
    env_file:
    - .env
    image: owner/image

Upvotes: 5

rokpoto.com
rokpoto.com

Reputation: 10720

To pass shell environment variables through to containers use env_file syntax:

web:
  env_file:
    - web-variables.env

As docs state:

You can pass multiple environment variables from an external file through to a service’s containers with the ‘env_file’ option

However, using .env as external filename may cause unexpected results and is semantically problematic.

Placing .env in the folder where the docker-compose command serves different purpose:

As Docs, Docs2, Docs3 state:

The environment variables you define here are used for variable substitution in your Compose file

You can set default values for environment variables using a .env file, which Compose automatically looks for

So if compose file contains:

db:
  image: "postgres:${POSTGRES_VERSION}"

You .env would contain:

POSTGRES_VERSION=4.0

This feature indeed works only in compose:

The .env file feature only works when you use the docker-compose up command and does not work with docker stack deploy

Upvotes: 1

Shōgun8
Shōgun8

Reputation: 562

Actually I found the best/easiest way is to just add this argument to the docker-compose.yml file:

env_file:
  - .env 

Upvotes: -3

Related Questions