dockergitlabgitlab-cidocker-in-docker

GitLab Docker-in-Docker: how does Docker client in job container discover Docker daemon in `dind` service container?


I have a GitLab CI/CD pipeline that is being run on GKE.

One of the jobs in the pipeline uses a Docker-in-Docker service container so that Docker commands can be run inside the job container:

my_job:
  image: docker:20.10.7
  services:
    - docker:dind
  script:
    - docker login -u $USER -p $PASSWORD $REGISTRY
    - docker pull ${REGISTRY}:$TAG
    # ...more Docker commands

It all works fine, but I would like to know why. How does the Docker client in the my_job container know that it needs to communicate with the Docker daemon running inside the Docker-in-Docker service container, and how does it know the host and port of this daemon?


Solution

  • There is no 'discovery' process, really. The docker client must be told about the daemon host through configuration (e.g., DOCKER_HOST). Otherwise, the client will assume a default configuration:

    1. if the DOCKER_HOST configuration is present, this is used. Otherwise:
    2. if the default socket (e.g., unix:///var/run/docker.sock) is present, the default socket is used.
    3. if the default socket is NOT present AND a TLS configuration is NOT detected, tcp://docker:2375 is used
    4. If the socket is NOT present AND a TLS configuration is present, tcp://docker:2376 is used

    You can see this logic explicitly in the docker dockerfile entrypoint.

    The docker client can be configured a couple ways, but the most common way in GitLab CI and with the official docker image is through the DOCKER_HOST environment variable. If you don't see this variable in your YAML, it may be set as a project or group setting or may be set on the runner configuration, or is relying on default behavior described above.

    It's also possible, depending on your runner configuration (config.toml), that your job is not using the docker:dind service daemon at all. For example, if your runner has a volumes specification mounting the docker socket (/var/run/docker.sock) into the job container and there is no DOCKER_HOST (or equivalent) configuration, then your job is probably not even using the service because it would use the mounted socket (per the configuration logic above). You can run docker info in your job to be sure of this one way or the other.

    Additional references: