dockerdevopsdocker-swarmdocker-swarm-mode

Where should ENV variables be defined when running app in a swarm mode?


There's an environment variable defined in frontend's Dockerfile:

ENV APP_BACKEND_URL=http://localhost/

and gets read when Docker builds a frontend image, and the same variable is defined in app.yml:

services:
  backend:
    [...]

  frontend:
    [...]
    environment:
      APP_BACKEND_URL: 'backend'

The config file above gets given as an argument to docker stack deploy -c app.yml appli.

I wonder which value gets eventually set up as the final one: the one from Dockerfile (built into the image), or the other one, from the app.yml file, that gets read last. In case of operating with Docker Compose, all variables present both in Dockerfile and docker-compose.yml were given values from Dockerfile; docker-compose.yml values were ignored. Does it work the same in case of Docker Swarm?

I ask the question because in the end my frontend doesn't read any value of the variable (console logs say about undefined value) and I'd like to know how to supply the value to be accessible/readable by the application.


Solution

  • If the variable is used in the Dockerfile, only the Dockerfile definition has any effect.

    FROM busybox
    ENV FOO=bar
    RUN echo "$FOO" > /a-file.txt
    CMD cat /a-file.txt
    
    docker build -t an-image .
    docker run -e FOO=quux --rm an-image
    # prints "bar" from the Dockerfile definition
    

    When the application runs, though, the Compose definition will take precedence.

    FROM busybox
    ENV FOO=bar
    CMD echo FOO is "$FOO"
    
    docker build -t another-image .
    docker run --rm -e FOO=quux another-image
    # prints "FOO is quux" from the runtime definition
    

    I would not expect this to work differently in Swarm.

    my frontend doesn't read any value of the variable (console logs say about undefined value)

    For many front-end applications, you can run a Node server in a container, but that actually serves up Javascript code to a browser to run, and the application actually runs in the browser. The browser isn't in Docker (and even isn't necessarily on the same host) and so it can't use Docker networking, environment variables defined only on the server, and so on.

    If you're building your application using webpack, its EnvironmentPlugin can cause process.env variables to be defined, but this is generally run when you're building the application's image and not when you're serving it.