17

I was wondering if there is a way to use environment variables taken from the host where the container is deployed, instead of the ones taken from where the docker stack deploy command is executed. For example imagine the following docker-compose.yml launched on three node Docker Swarm cluster:

version: '3.2'
services:
  kafka:
    image: wurstmeister/kafka
    ports:
      - target: 9094
        published: 9094
        protocol: tcp
        mode: host
    deploy:
      mode: global
    environment:
      KAFKA_JMX_OPTS: "-Djava.rmi.server.hostname=${JMX_HOSTNAME} -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.rmi.port=1099"

The JMX_HOSTNAME should be taken from the host where the container is actually deployed and should not be the same value for every container. Is there a correct way to do this?

Alessandro Dionisi
  • 2,494
  • 4
  • 33
  • 37

3 Answers3

31

Yes, this works when you combine two concepts:

  1. Swarm node labels, of which Hostname is one of the built-in ones.
  2. Swarm service go templates, which also work in stack files.

This would pull in the hostname to the ENV value of DUDE for each container to be the host that it's running on:

version: '3.4'

services:
  nginx:
    image: nginx
    environment:
      DUDE: "{{.Node.Hostname}}"
    deploy:
      replicas: 3
Bret Fisher
  • 8,164
  • 2
  • 31
  • 36
  • Your solution actually works but it doesn't answer completely to my answer. Suppose I have a non-built-in variable that I want to read? Is that possible? – Alessandro Dionisi Mar 02 '18 at 08:46
  • Sure, you should learn about Swarm node labels or host labels. Host labels are set in /etc/docker/daemon.json but not used often in a Swarm. Swarm labels are set via `docker node update` with `--label-add` and `--label-rm` and set any key/value you want :) – Bret Fisher Mar 02 '18 at 15:59
  • 2
    Then you can access it in the same way but with "labels" in the middle `.Node.Labels.LabelName` – Bret Fisher Mar 02 '18 at 16:00
  • 5
    I tried this method but it doesn't work. This is what i did: sudo docker node update --label-add ip='192.168.121.59' q687wox1uet33k4ubfvfa6p74. I then used this label in my compose file in environment section: environment: - KAFKA_HOST_IP: "{{.Node.Labels.ip}}". Started stack: sudo -E docker stack deploy -c docker-compose.yml service. Got error-> desc = expanding env failed: expanding env "KAFKA_HOST_IP={{.Node.Labels.ip}}": template: expansion:1:7: executing "expansion" at <.Node.Labels.ip>: can't evaluate field Labels in type struct { ID string; Hostname string; Platform template.Platform } – scorpio Mar 16 '18 at 03:51
  • if I use "KAFKA_HOST_IP={{.Node.Hostname}}" instead, it works. So, any custom label is not working. It seems that the "Labels" child is not present in the document. Seems like an issue of what first "." resolves to. – scorpio Mar 16 '18 at 04:33
6

It works if you run the docker command through env.

env JMX_HOSTNAME="${JMX_HOSTNAME}" docker stack deploy -c docker-compose.yml mystack

Credit to GitHub issue that pointed me in the right direction.

Tim
  • 1,585
  • 1
  • 18
  • 23
  • 1
    This is the correct answer for substituting variables in a stack yml file. It is a different problem then adding to container environment – U2ros Nov 19 '20 at 08:53
  • How in the world does this work? `env JMX_HOSTNAME="${JMX_HOSTNAME}"` would be interpolated by a shell prior to docker seeing it. So, docker would see `env JMX_HOSTNAME=master_host_env_value docker ...`. Am I missing something here? – Dima Korobskiy Feb 26 '21 at 21:26
4

I found another way for when you have many environment variables. The same method also works with docker-compose up

sudo -E docker stack deploy -c docker-compose.yml mystack

instead of

env foo="${foo}" bar="${bar}" docker stack deploy -c docker-compose.yml mystack

sudo -E man description;

   -E, --preserve-env
               Indicates to the security policy that the user wishes to
               preserve their existing environment variables.  The
               security policy may return an error if the user does not
               have permission to preserve the environment.
B. Bilgin
  • 774
  • 12
  • 22