How to get infos about ourself in a compose cluster

I have a docker container called “node”, I want to scale.
That node needs to know which node of how many nodes it actually is.
The total could be an environment variable, but the current is more troubling.

$ docker-compose scale node=100

Starting projectdir_node_1 ... done
Creating and starting projectdir_node_2 ... done
Creating and starting projectdir_node_3 ... done
Creating and starting projectdir_node_4 ... done
Creating and starting projectdir_node_5 ... done
Creating and starting projectdir_node_6 ... done
Creating and starting projectdir_node_7 ... done
Creating and starting projectdir_node_8 ... done
Creating and starting projectdir_node_9 ... done
...
Creating and starting projectdir_node_99 ... done
Creating and starting projectdir_node_100 ... done

How can projectdir_node_100 now it is node 100?
I saw that $HOSTNAME is the container id (e.g. 2c73136347cd), but found no ENV variable for the hostname with number I need.

  • Docker URI documentation
  • Docker : Cannot remove dangling containers
  • Docker - Access linked Container
  • How to set a specific (fixed) IP address when I create a docker machine or container?
  • Start node app when running docker container from cli
  • docker service update: “image could not be accessed on a registry to record it's digest”
  • For reference, my docker-compose.yml:

    version: '2'
    services:
      node:
        build: ./node/
        volumes:
          - ./node/code/:/code:ro
        entrypoint: ["/bin/bash"]
    

    I found the unsolved How to reach additional containers by the hostname after docker-compose scale?, but I still don’t know which container I am.

  • Docker with one nginx and one uwsgi container that is sharing a UNIX socket
  • Pull docker images from private registry on remote host?
  • how to solve error in docker-compose?
  • Docker local registry : push fails
  • How to forward data from a host computer to a Docker container?
  • Minor change in ansible playbook does not get updated in target host
  • One Solution collect form web for “How to get infos about ourself in a compose cluster”

    The way I could solve this was by using the docker api.
    I used the docker-py package to access it.

    The api exposes a labels dictionary for each container, and the keys com.docker.compose.container-number, com.docker.compose.project and com.docker.compose.service did what was needed to build the hostname.

    The code below is a simplified for code I am now using.
    You can find my advanced code with caching and fancy stuff that at Github at luckydonald/pbft/dockerus.ServiceInfos (backup at gist.github.com).

    Lets tackle this in steps:

    0. Make the API available to the container.

    We need to make the socket file available to the volume, so in the volume section of your docker-compose.yml file add /var/run/docker.sock:/var/run/docker.sock:

    version: '2'
    services:
      node:
        build: .
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
    

    This maps the socket file into the docker container.
    Because we don’t expose any socket ports, we don’t have to worry about firewalls for the outside world.

    1. Connect to the API

    Now we can connect to it. As I am using python, I use docker-py for that.

    from docker import Client  # pip install docker-py
    
    cli = Client(base_url='unix://var/run/docker.sock')
    

    2. Getting all containers in the same scale group, by filtering the containers by our own project name and service name.

    Find ourself

    To know which container we are, we compare the $HOSTNAME environment variable with the container Id.

    import os
    HOSTNAME = os.environ.get("HOSTNAME")
    
    all_containers = cli.containers()
    
    # filter out ourself by HOSTNAME
    our_container = [c for c in all_containers if c['Id'][:12] == HOSTNAME[:12]][0]
    

    The hostname should be 12 characters of the Id, so we cut the id when comparing to be sure it will be equal.
    our_container now is the api representation of ourself. Yay.

    Next is to get the other containers.

    We will search for containers which have the same project and service names.
    That way we know they are instances of ourself.

    service_name = our_container.Labels['com.docker.compose.service']
    project_name = our_container.Labels['com.docker.compose.project']
    
    filters = [
      'com.docker.compose.project={}'.format(project_name),
      'com.docker.compose.service={}'.format(service_name)
    ]
    # The python wrapper has a filter function to do that work for us.
    containers = cli.containers(filters={'label': filters})
    

    We only want each container where the com.docker.compose.project and com.docker.compose.service label is the same as our own container’s.

    And finally build a list of hostnames

    hostname_list = list()
    for container in containers:
      project = container.Labels["com.docker.compose.project"]
      service = container.Labels["com.docker.compose.service"]
      number  = container.Labels["com.docker.compose.container-number"]
      hostname = "{project}_{service}_{i}".format(project=project, service=service, i=number)
      hostname_list.append(hostname)
    # end for
    

    So, we got our hostname_list.

    I am using that as a class, with caching the values for a minute:
    dockerus.ServiceInfos (backup at gist.github.com)

    Docker will be the best open platform for developers and sysadmins to build, ship, and run distributed applications.