Search code examples
dockerdocker-composegitlabdocker-volume

docker-compose : Scaling containers with distinct host volume map


  1. Here, I deployed 2 containers with --scale flag
docker-compose up -d --scale gitlab-runner=2

2.Two containers are being deployed with names scalecontainer_gitlab-runner_1 and scalecontainer_gitlab-runner_2 resp.

  1. I want to map different volume for each container.
/srv/gitlab-runner/config_${DOCKER_SCALE_NUM}:/etc/gitlab-runner
  1. Getting this error:
WARNING: The DOCKER_SCALE_NUM variable is not set. Defaulting to a blank string.
  1. Is there any way, I can map different volume for separate container .
services:
  gitlab-runner:
    image: "gitlab/gitlab-runner:latest"
    restart: unless-stopped
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
      - /srv/gitlab-runner/config_${DOCKER_SCALE_NUM}:/etc/gitlab-runner
version: "3.5"

Solution

  • I don't think you can, there's an open request on this here. Here I will try to describe an alternative method for getting what you want.

    Try creating a symbolic link from within the container that links to the directory you want. You can determine the "number" of the container after it's constructed by reading the container name from docker API and taking the final segment. To do this you have to mount the docker socket into the container, which has big security implications.

    Setup

    Here is a simple script to get the number of the container (Credit Tony Guo).

    get-name.sh

    DOCKERINFO=$(curl -s --unix-socket /run/docker.sock http://docker/containers/$HOSTNAME/json)
    ID=$(python3 -c "import sys, json; print(json.loads(sys.argv[1])[\"Name\"].split(\"_\")[-1])" "$DOCKERINFO")
    echo "$ID"
    

    Then we have a simple entrypoint file which gets the container number, creates the specific config directory if it doesn't exist, and links its specific config directory to a known location (/etc/config in this example).

    entrypoint.sh

    #!/bin/sh
    
    # Get the number of this container
    NAME=$(get-name)
    CONFIG_DIR="/config/config_${NAME}"
    
    # Create a config dir for this container if none exists
    mkdir -p "$CONFIG_DIR"
    # Create a sym link from a well known location to our individual config dir
    ln -s "$CONFIG_DIR" /etc/config
    
    exec "$@"
    

    Next we have a Dockerfile to build our image, we need to set the entrypoint and install curl and python for it to work. Also copy in our get-name.sh script.

    Dockerfile

    FROM alpine
    
    COPY entrypoint.sh entrypoint.sh
    COPY get-name.sh /usr/bin/get-name
    
    RUN apk update && \
        apk add \
            curl \
            python3 \
            && \
        chmod +x entrypoint.sh /usr/bin/get-name
    
    ENTRYPOINT ["/entrypoint.sh"]
    

    Last, a simple compose file that specifies our service. Note that the docker socket is mounted, as well as ./config which is where our different config directories go.

    docker-compose.yml

    version: '3'
    
    services:
      app:
        build: .
        command: tail -f
        volumes:
          - /run/docker.sock:/run/docker.sock:ro
          - ./config:/config
    

    Example

    # Start the stack
    $ docker-compose up -d --scale app=3
    Starting volume-per-scaled-container_app_1 ... done
    Starting volume-per-scaled-container_app_2 ... done
    Creating volume-per-scaled-container_app_3 ... done
    
    # Check config directory on our host, 3 new directories were created.
    $ ls config/
    config_1  config_2  config_3
    
    # Check the /etc/config directory in container 1, see that it links to the config_1 directory
    $ docker exec volume-per-scaled-container_app_1 ls -l /etc/config
    lrwxrwxrwx    1 root     root            16 Jan 13 00:01 /etc/config -> /config/config_1
    
    # Container 2
    $ docker exec volume-per-scaled-container_app_2 ls -l /etc/config
    lrwxrwxrwx    1 root     root            16 Jan 13 00:01 /etc/config -> /config/config_2
    
    # Container 3
    $ docker exec volume-per-scaled-container_app_3 ls -l /etc/config
    lrwxrwxrwx    1 root     root            16 Jan 13 00:01 /etc/config -> /config/config_3
    

    Notes

    • I think gitlab/gitlab-runner has its own entrypoint file so you may need to chain them.
    • You'll need to adapt this example to your specific setup/locations.