hashlash
hashlash

Reputation: 1015

Accessing GitLab CI Service from A Container running Inside DinD

I'm trying to run a continuous integration in GitLab CI consisting of:

Those are running inside one job. I can do it without any problem until come up some test that needs to communicate with database. My container can't communicate with Postgres services defined.

I've reproduce it in a public repository with simple ping script

image: docker:stable

services:
  - docker:dind
  - postgres:latest

job1:
  script:
    - ping postgres -c 5
    - docker run --rm --network="host" alpine:latest sh -c "ping postgres -c 5"

The first script could run without any problem, but the second one failed with error

ping: bad address 'postgres'

How can I access the service?

Or should I run the test in a different job?

Upvotes: 7

Views: 1758

Answers (2)

Serrano
Serrano

Reputation: 1517

You can simply use docker compose for this.

Create a Docker Compose file .gitlab/docker-compose.yml:

services:
  test-runner:
    image: alpine:latest
    depends_on:
      - postgres

  postgres:
    image: postgres:latest
    environment:
      POSTGRES_DB: "${POSTGRES_DB:?}"
      POSTGRES_USER: "${POSTGRES_USER:?}"
      POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:?}"

And your CI job can look like this:

test:
  stage: test
  image: docker
  services:
    - docker:dind
  variables:
    COMPOSE_FILE: .gitlab/docker-compose.yml
    POSTGRES_DB: postgres
    POSTGRES_USER: postgres
    POSTGRES_PASSWORD: postgres
  script:
    - docker compose run test-runner sh -c "ping postgres -c 5"

Upvotes: 0

Matheus Portillo
Matheus Portillo

Reputation: 307

The solution is to use --add-host=postgres:$POSTGRES_IP to pass over the ip address present in job container.

To find out postgres ip linked to the outer container you can use for example getent hosts postgres | awk '{ print $1 }'

So the yml would look like

image: docker:stable

services:
  - docker:dind
  - postgres:latest

job1:
  script:
    - ping postgres -c 5
    - docker run --rm --add-host=postgres:$(getent hosts postgres  | awk '{ print $1 }') alpine:latest sh -c "ping postgres -c 5"

To understand why the other more common ways to connect containers wont work in this case, we have to remember we are trying to link a nested container with a service linked to its "parent". Something like this:

gitlab ci runner --> docker       -> my-container (alpine)
                  -> docker:dind
                  -> postgres

So we are trying to connect a container with its "uncle". Or connecting nested containers

As noted by @tbo, using --network host will not work. This is probably because gitlab ci use --link (as explained here) to connect containers instead of the newer --network. The way --link works makes that the services containers are connected to the job container, but not connected with one another. So using host network wont make the nested container inherit postgres hostname.

One could also think that using --link postgres:postgres would work, but it also won't as in this environment postgres is only a hostname with the ip of the container outside. There is not container here to be linked with the nested container

So all we can do is manually add a host with the correct ip to the nested container using --add-host as explained above.

Upvotes: 5

Related Questions