docker-composedocker-swarmtraefikdocker-swarm-mode

When using docker swarm stack, only Traefik does not see the env vars from the .env file


I'm trying to use env vars to define the host and credentials for the Traefik dashboard, but Traefik doesn't see them. All of the env vars are present when I verify them inside the docker container. Everything works well with hardcoded values. I attempted to use both approaches:

All the other services of the docker-compose can successfully use the vars from the .env file

What am I doing incorrectly?

docker-compose.yml

version: '3.6'

services:
  reverse-proxy:
    image: traefik:v2.6
    ports:
      - 80:80
      - 443:443
    env_file:
      - "./.env"
    deploy:
      placement:
        constraints: [node.role == manager]
      update_config:
        failure_action: rollback
      labels:
        # Enable traefik for the specific service
        - "traefik.enable=true"
        # global redirect to https
        - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
        - "traefik.http.routers.http-catchall.entrypoints=http"
        - "traefik.http.routers.http-catchall.middlewares=https-redirect"
        - "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
        - "traefik.http.middlewares.https-redirect.redirectscheme.permanent=true"
        # Make the Traefik use this domain in HTTPS
        - "traefik.http.routers.traefik-https.rule=Host(`${TRFK_HOST}`)"
        # Allow the connections to the traefik api for the dashboard support
        - "traefik.http.routers.traefik-https.service=api@internal"
        - "traefik.http.services.traefik-svc.loadbalancer.server.port=9999"
        # Use the Let's encrypt resolver
        - "traefik.http.routers.traefik-https.tls=true"
        - "traefik.http.routers.traefik-https.tls.certresolver=le"
        # Use the traefik_net network that is declared below
        - "traefik.docker.network=traefik_net"
        # Use the auth for traefik dashboard
        - "traefik.http.middlewares.traefik-auth.basicauth.users=${TRFK_USER}:${TRFK_PSWD}"
        - "traefik.http.routers.traefik-https.middlewares=traefik-auth"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - traefik-public-certificates:/certificates
    command:
      - --providers.docker
      - --providers.docker.swarmMode=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.http.address=:80
      - --entrypoints.https.address=:443
      - --certificatesresolvers.le.acme.email=ex@ex.com
      - --certificatesresolvers.le.acme.storage=/certificates/acme.json
      - --certificatesresolvers.le.acme.httpchallenge=true
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=http
      - --accesslog
      - --log
      - --api
    networks:
      - traefik_net

volumes:
  traefik-public-certificates:

networks:
  traefik_net:
    external: true

.env file

# traefik dashboard auth config
TRFK_USER=user
TRFK_PASSWD=$apr1$ZPapA6iQ$7OzhPqocYY.lotTdGgnoM.
TRFK_HOST=traefik.example.com

The only way that is currently working is:

env $(cat .env | grep ^[A-Z] | xargs)  docker stack deploy -c docker-stack.yml stack

Is there any other way to make it work ?


Solution

  • You seem to be doing it correctly.

    env_file: and environment: sections are used for injecting environment variables into the created container.

    In this case, however, the environment variables are being expanded directly in the labels of the stack yml, so are not being passed through to the container - they do need to be part of the environment of the docker stack deploy command.

    As long as you have the call to docker stack deploy wrapped up in a Makefile or bash script of some kind so preparing the environment is automated, this is the correct and necessary way.