1

I want to get the IP address of a container so that I can set that IP address as an environmental variable.

docker-compose.yml

django:
  build: .
  command: python /app/project/manage.py test --liveserver=172.18.0.4:8081  //hard coded - trying to avoid this
  ports:
    - "8000:8000"
    - "8081:8081"

selenium:
  container_name: selenium
  image: selenium/standalone-firefox-debug:2.52.0
  ports:
    - "4444:4444"
    - "5900:5900"

The problem is that in order to run correctly django needs either:

A. set --liveserver

python /app/manage.py test --liveserver=django-appnet-ip:port

B. or I set environmental variable:

  DJANGO_LIVE_TEST_SERVER_ADDRESS=django-appnet-ip:port

Problem is that the ip address for the docker container isn't set until the container is created. So how can I pass the IP address to django?

What I have tried so far...

A. Creating a django management command that calls the script that then calls a management command:

class Command(BaseCommand):
    def add_arguments(self, parser):
        // I would have to redefine all the arguments because
        //I can't call super on django/core/management/commands/test.py
    ...

B. Referring to the app itself in DJANGO_LIVE_TEST_SERVER_ADDRESS 'django:8081' only works if in docker-compose with this configuration:

django:
  build: .
  net: appnet
  command: python /app/project/manage.py test
  ports:
    - "8000:8000"
    - "8081:8081"
  environment:
    - DJANGO_LIVE_TEST_SERVER_ADDRESS=django:8081  # where django is the name of the app

If I set the command to blank, then from the command line run: docker-compose run django python /app/project/manage.py test I get

======================================================================
ERROR: setUpClass (django_behave.runner.DjangoBehaveTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/django/test/testcases.py", line 1354, in setUpClass
    raise cls.server_thread.error
error: [Errno 99] Cannot assign requested address

----------------------------------------------------------------------

The Question

How can I pass a container's ip address it a network to the container so that the command the container runs gets the IP address?

Or maybe there is a completely different approach to this problem?

lukeaus
  • 11,465
  • 7
  • 50
  • 60
  • What about creating a shell script wrapper that would run in container. It would have 2 steps. Step 1: get container ip address (something like ip addr or ifconfig and parse the ip from output) Step2: run django (with ip address as parameter). Then when starting container just run that shell wrapper.. – calvix Apr 13 '16 at 08:45
  • @calvix success! - I will write it up. Thanks :) – lukeaus Apr 14 '16 at 13:13

2 Answers2

4

I made a bash script to get the docker container id, then use that id to get the ip address for that container id from the container's /etc/hosts.

Solution

In django Dockerfile

ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh

#!/bin/bash
set -e
# Now we need to get the ip address of this container so we can supply it as an environmental
# variable for django so that selenium knows what url the test server is on

# only add if 'manage.py test' in the args
if [[ "'$*'" == *"manage.py test"* ]]
then
  # get the container id
  THIS_CONTAINER_ID_LONG=`cat /proc/self/cgroup | grep 'docker' | sed 's/^.*\///' | tail -n1`
  # take the first 12 characters - that is the format used in /etc/hosts
  THIS_CONTAINER_ID_SHORT=${THIS_CONTAINER_ID_LONG:0:12}
  # search /etc/hosts for the line with the ip address which will look like this:
  #     172.18.0.4    8886629d38e6
  THIS_DOCKER_CONTAINER_IP_LINE=`cat /etc/hosts | grep $THIS_CONTAINER_ID_SHORT`
  # take the ip address from this
  THIS_DOCKER_CONTAINER_IP=`(echo $THIS_DOCKER_CONTAINER_IP_LINE | grep -o '[0-9]\+[.][0-9]\+[.][0-9]\+[.][0-9]\+')`
  # add the port you want on the end
  # Issues here include: django changing port if in use (I think)
  # and parallel tests needing multiple ports etc.
  THIS_DOCKER_CONTAINER_TEST_SERVER="$THIS_DOCKER_CONTAINER_IP:8081"
  export DJANGO_LIVE_TEST_SERVER_ADDRESS=$THIS_DOCKER_CONTAINER_TEST_SERVER
fi

eval "$@"

alternatively you could have used something like

 "$@ --liveserver=$THIS_DOCKER_CONTAINER_TEST_SERVER"

Probably better to set the environmental variable so you can use it in other places.

Community
  • 1
  • 1
lukeaus
  • 11,465
  • 7
  • 50
  • 60
0

Is this a container dependency issue? Are you running selenium in a container? docker-compose suggests 2 or more docker containers, but you only referred to Django container. If this is a container dependency issue, then sadly it's not possible at the moment to use docker-compose to start one container first before another. You could however use the...

docker wait

...command within a bash script and then use...

docker inspect containerName

...to get the IP address and pass that IP to docker compose.

docker-compose DOES support use of variables.

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
danday74
  • 52,471
  • 49
  • 232
  • 283
  • apologies for the confusion. Its got nothing to do with multiple containers in docker-compose. I am just talking about one container being dependent on itself to provide its own IP address as a command line argument to its own command for its own container (or environmental variable to it its own container) – lukeaus Apr 13 '16 at 11:10
  • I understand docker-compose does support the use of variables, I am just having difficulty getting the IP address of itself in there as a variable – lukeaus Apr 13 '16 at 11:11
  • 1
    dependent on self - craziness :) - is the command being executed in the container or on the host? when is the command executed, before or after docker run? can you not use port forwarding - set the domain as localhost:your_containers_port (instead of using ip) ? and then use the -p flag in your docker run statement to expose the port to the host OS? – danday74 Apr 13 '16 at 11:21
  • I updated my question with an updated docker-compose.yml file. Does that answer your first 2 questions? – lukeaus Apr 13 '16 at 11:36
  • I tried setting this in docker-compose.yml for django: ```domainname: localhost:8081 command: python /app/project/manage.py test --testrunner=testing.runner.BehaveTestRunner --liveserver=localhost:8081``` but then selenium can't connect - see this question: http://stackoverflow.com/questions/35143927/docker-django-and-selenium-selenium-unable-to-connect – lukeaus Apr 13 '16 at 11:38
  • docker philosophy suggests 1 server per container - can you not run the test server in a different container. spin the django server up first in the django container - then u have an ip - then spin up the test server in different container – danday74 Apr 13 '16 at 13:03
  • On closer inspection there is only one server ```PID 1 python /app/project/manage.py test --testrunner=testing.runner.BehaveTestRunner``` – lukeaus Apr 13 '16 at 13:10
  • @dandy74 your line about craziness helped me look at the situation from a more simplistic angle - thanks! – lukeaus Apr 13 '16 at 13:11