docker-compose evaluate expression in command array

7.2k views Asked by At

I have below docker-compose.yml file. In the command section I would like to evaluate the curl expression before the command is passed to docker engine i.e. my curl should be evaluated first and then my container should run with -ip 10.0.0.2 option.

version: '2'
services:
  registrator:
    image: gliderlabs/registrator:v7
    container_name: registrator
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock
    command: ['-ip', '$$(curl -X GET -s http://169.254.169.254/latest/meta-data/local-ipv4)']

This however is not being evaluated and my option is passed as -ip $(curl -X GET -s http://169.254.169.254/latest/meta-data/local-ipv4)

The respective docker run command however correctly evaluates the expression and my container is correctly starting with -ip 10.0.0.2 option:

docker run -v /var/run/docker.sock:/tmp/docker.sock gliderlabs/registrator:v7 -ip $(curl -X GET -s http://169.254.169.254/latest/meta-data/local-ipv4)
2

There are 2 answers

2
Ivonet On BEST ANSWER

The docker command on the command line will work as the command will be executed by the shell and not the docker image, so it will be resolved.

the docker-compose command will override the default command (CMD) (see https://docs.docker.com/compose/compose-file/#command) so it will not be executed before the container is started but as the primary command in the container...

you could do something like:

version: '2'
services:
  registrator:
    image: gliderlabs/registrator:v7
    container_name: registrator
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock
    command: ['-ip', '${IP}']

and run it with:

IP="$(curl -X GET -s http://169.254.169.254/latest/meta-data/local-ipv4)" docker-compose up

this will run it in the shell again and assign it to a variable called IP witch will be available during the docker-compose up command. You could put that command in a shell script to make it easier.

0
Rash On

After searching the internet for hours and answers posted here, I finally settled for below solution. For explanation of why this works, please refer to @Ivonet answer.

I modified the Dockerfile to run a script when the container starts.

FROM gliderlabs/registrator:v7

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh && \
    apk update && \
    apk add curl

ENTRYPOINT ["/entrypoint.sh"]

The script entrypoint.sh is also very simple. It first checks if it can call the endpoint. A success response would trigger my container to start with correct IP address, while an un-successful response (for local testing) would not set any value.

#!/bin/sh

LOCAL_IP=$(curl -s --connect-timeout 3 169.254.169.254/latest/meta-data/local-ipv4)
if [ $? -eq 0 ]; then
  /bin/registrator -ip $LOCAL_IP $@
else
  /bin/registrator $@
fi