0
votes

I have a non-critical Docker Compose project where the Traefik rules vary acceptably between dev and production (I need Lets Encrypt on prod, but not on dev). I am using the [file] config provider.

Currently I am creating separate builds for dev and prod, thus:

# This is fetched from the Compose config
ARG BUILD_NAME

RUN if [ "$BUILD_NAME" == "prod" ]; then \
    echo Compiling prod config... ; \
    sh /root/compile/prod.sh > /etc/traefik/traefik.toml ; \
else \
    echo Compiling dev config... ; \
    sh /root/compile/dev.sh > /etc/traefik/traefik.toml ; \
fi

While this project is not enormously important, per-env builds is a bit hacky, and I'd rather go with the standard container approach of one image for all environments.

To do that, I was thinking of doing something like this:

FROM traefik:1.7

# This is set in the Docker Compose config
ENV ENV_NAME

# Let's have a sig handler
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_amd64
RUN chmod +x /usr/local/bin/dumb-init

COPY docker/traefik/start.sh /root/start.sh

ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]
CMD ["/root/start.sh"]

The start.sh would have something that would run my "compile" shell command at run time (this selects pieces of config based on the environment). However, the official Traefik images do not run a shell - there are a compiled blob from Go source - so this won't work. Is there a env var by which /etc/traefik/traefik.toml can be changed, or an industry standard way of doing this in Docker?

I did think of using volumes, but that means the container won't "plug-n-play" without additional set up - I like that it is currently self-contained. However, I may use that if there is no alternative. I could run the config "compiler" on the host.

Another approach is to install Traefik in an image that has a shell - maybe it would work with Alpine. I am not sure how I feel about that - removing the shell is a good security feature, so I am hesitant to add it back in, even if I don't think it can be easily exploited.

1

1 Answers

1
votes

I didn't find a way to modify the Traefik config file path using environment variables. However, I hit on a volume-based solution that seems to be quite self-contained.

  1. I set up another image called shell in my Docker Compose file:

    shell:
      build:
        context: docker/shell
      volumes:
        # On-host volume for generating config
        - "./docker/traefik/compiled:/root/compiled-host"
    

    This features a bind-mount volume to catch generated config files.

  2. Next, I created a Dockerfile for the new service:

    FROM alpine:3.10
    
    COPY compile /root/compile
    COPY config /root/config
    
    # Compile different versions of the config, ready to copy into an on-host volume
    RUN mkdir /root/compiled && \
        sh /root/compile/dev.sh > /root/compiled/traefik-dev.toml && \
        sh /root/compile/prod.sh > /root/compiled/traefik-prod.toml
    

    This will create config files for both environments as part of the built image.

  3. When Docker Compose is started up, this service will briefly start, but it will soon exit gracefully and harmlessly. It is intended to be run on an ad-hoc basis anyway.

  4. I already had environment-specific YAML config files, docker-compose-dev.yml and docker-compose-prod.yml, which are explicitly specified in the Compose command with -f. I then used this file to expose the generated on-host file to Traefik. Here's the dev:

      traefik:
        volumes:
          # On-host volume for config
          - "./docker/traefik/compiled/traefik-dev.toml:/etc/traefik/traefik.toml"
    

    Much the same was done for traefik-prod.toml

  5. Then, I created per-env commands to copy the config from the shell image into the on-host volume:

    #!/bin/sh
    
    docker-compose -f docker-compose.yml -f docker-compose-prod.yml run shell cp /root/compiled/traefik-prod.toml /root/compiled-host/traefik-prod.toml
    
  6. Finally, when Traefik starts as part of the Compose application, it will find its configuration file in its usual place, /etc/traefik/traefik.toml, but this is in fact a file volume to the generated copy on the host.