在 gitlab ci 中查找在 docker-compose 中运行的容器的 url/ip

Posted

技术标签:

【中文标题】在 gitlab ci 中查找在 docker-compose 中运行的容器的 url/ip【英文标题】:Find url/ip of container running in docker-compose in gitlab ci 【发布时间】:2020-12-31 00:03:11 【问题描述】:

我有一个在 docker-compose 中运行的应用程序(用于验收测试)。验收测试在本地工作,但它们需要在 docker-compose 中运行的 web 服务容器的主机(或 ip)才能向其发送请求。这在本地工作正常,但是当它在 gitlab ci 服务器中运行时我找不到容器的 ip。我尝试了以下几个解决方案(所有这些在本地运行时都有效,但在 gitlab ci 中都不起作用)来查找在 gitlab ci 服务器中的 docker-compose 中运行的容器的 url:

    使用“docker”作为主机。这适用于在 docker 中运行的应用程序,但不适用于 docker-compose 使用 docker-inspect 查找容器的 ip (docker inspect -f 'range .NetworkSettings.Networks.IPAddressend' 阅读理解) 使用 docker-compose.yml 中的网络为容器分配静态 ip(最新尝试)。

gitlab ci 文件可以在这里找到: https://gitlab.com/connorbutch/reading-comprehension/-/blob/9-list-all-assessments/.gitlab-ci.yml

    image: connorbutch/gradle-and-java-11:alpha

variables:
  GRADLE_OPTS: "-Dorg.gradle.daemon=false"
  DOCKER_HOST: "tcp://docker:2375"
  DOCKER_DRIVER: "overlay2"

before_script:
  - export GRADLE_USER_HOME=`pwd`/.gradle

services:
  - docker:stable-dind

stages:
  - build
  - docker_build
  - acceptance_test

unit_test:
  stage: build
  script: ./gradlew check
  cache:
    key: "$CI_COMMIT_REF_NAME"
    policy: pull
    paths:
      - build
      - .gradle

build:
  stage: build
  script:
    - ./gradlew clean quarkusBuild
    - ./gradlew clean build -Dquarkus.package.type=native -Dquarkus.native.container-build=true
  cache:
    key: "$CI_COMMIT_REF_NAME"
    policy: push
    paths:
      - build
      - .gradle
  artifacts:
    paths:
      - reading-comprehension-server-quarkus-impl/build/

docker_build:
  stage: docker_build
  script:
    - cd reading-comprehension-server-quarkus-impl
    - docker build -f infrastructure/Dockerfile -t registry.gitlab.com/connorbutch/reading-comprehension:$CI_COMMIT_SHORT_SHA  .
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker push registry.gitlab.com/connorbutch/reading-comprehension:$CI_COMMIT_SHORT_SHA

acceptance_test:
  stage: acceptance_test
  only:
    - merge_requests
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - cd reading-comprehension-server-quarkus-impl/infrastructure
    - export IMAGE_TAG=$CI_COMMIT_SHORT_SHA
    - docker-compose up -d & ../../wait-for-it-2.sh
    - cd ../..
    - ./gradlew -DBASE_URL='192.168.0.8' acceptanceTest
  artifacts:
    paths:
      - reading-comprehension/reading-comprehension-server-quarkus-impl/build/

docker-compose 文件可以在这里找到: https://gitlab.com/connorbutch/reading-comprehension/-/blob/9-list-all-assessments/reading-comprehension-server-quarkus-impl/infrastructure/docker-compose.yml

在此处查找其中一项失败作业的输出: https://gitlab.com/connorbutch/reading-comprehension/-/jobs/734771859

#This file is NOT ever intended for use in production.  Docker-compose is a great tool for running
#database with our application for acceptance testing.
version: '3.3'

networks:
  network:
    ipam:
      driver: default
      config:
        - subnet: 192.168.0.0/24

services:
  db:
    image: mysql:5.7.10
    container_name: "db"
    restart: always
    environment:
       MYSQL_DATABASE: "rc"
       MYSQL_USER: "user"
       MYSQL_PASSWORD: "password"
       MYSQL_ROOT_PASSWORD: "password"
       MYSQL_ROOT_HOST: "%"
    networks:
      network:
        ipv4_address: 192.168.0.4
    ports:
      - '3306:3306'
    expose:
      - '3306'
    volumes:
      - db:/var/lib/mysql
  reading-comprehension-ws:
    image: "registry.gitlab.com/connorbutch/reading-comprehension:$IMAGE_TAG"
    container_name: "reading-comprehension"
    restart: on-failure
    environment:
      WAIT_HOSTS: "db:3306"
      DB_USER: "user"
      DB_PASSWORD: "password"
      DB_JDBC_URL: "jdbc:mysql://192.168.0.4:3306/rc"
    networks:
      network:
        ipv4_address: 192.168.0.8
    ports:
      - 8080:8080
    expose:
      - 8080
volumes:
  db:

有人知道如何访问在 gitlab ci 服务器上运行在 docker-compose 中的容器的 ip 吗?欢迎提出任何建议。

谢谢,

康纳

【问题讨论】:

或许,您可以在同一个 docker-compose 中添加验收测试? 我在您的错误消息中看到了这个 IP 地址:level=info msg="Default bridge (docker0) is assigned with an IP address 172.18.0.0/16 . 感谢您指出此日志退出 mdabdullah!我将继续并重新运行,尝试将我的静态 ip 分配到子网中。你碰巧知道(如果你不知道也没关系)这个范围对于在 gitlab-ci 上的 docker-compose 中运行的服务是否总是相同的?另外,你知道我如何在 gitlab ci 中使用 --bip 选项吗?再次感谢 我分配了与日志中列出的子网相同的子网(并收到一条似乎证实了这一点的日志消息),并尝试连接到此 IP,但是仍然不可用。我认为问题在于 docker-compose 服务完全在不同的主机上运行(例如,在 docker 中运行 docker 时,主机是“docker”,但这不适用于 docker compose)。您对如何找到此主机有任何想法吗?谢谢。 【参考方案1】:

这有点棘手,就在几天前,我遇到了类似的问题,但是从 CI 到客户端的 *** :)

编辑:本地 gitlab 实例的解决方案

为 gitlab 跑步者创建自定义网络:

docker network create --subnet=172.16.0.0/28 \
 --opt com.docker.network.bridge.name=gitlab-runners \
 --opt com.docker.network.bridge.enable_icc=true \
 --opt com.docker.network.bridge.enable_ip_masquerade=true \
 --opt com.docker.network.bridge.host_binding_ipv4=0.0.0.0 \
 --opt com.docker.network.driver.mtu=9001 gitlab-runners

将新网络附加到 gitlab-runners

# /etc/gitlab-runner/config.toml
[[runners]]
....
   [runners.docker]
   ....
   network_mode = "gitlab-runners"

重启跑步者。

最后是 gitlab-ci.yml

start-***:
    stage: prepare-deploy
    image: docker:stable
    cache: 
    variables:
        GIT_STRATEGY: none
    script:
        - >
            docker run -it -d --rm
            --name ***-branch-$CI_COMMIT_REF_NAME
            --privileged
            --net gitlab-runners
            -e ***ADDR=$***_SERVER
            -e ***USER=$***_USER
            -e ***PASS=$***_PASSWORD
            auchandirect/forticlient || true && sleep 2
        - > 
            docker inspect -f 'range .NetworkSettings.Networks.IPAddressend' 
            ***-branch-$CI_COMMIT_REF_NAME > ***_container_ip
    artifacts:
        paths:
        - ***_container_ip

在下一步你可以使用类似的东西:

before_script:
        - ip route add 10.230.163.0/24 via $(cat ***_container_ip) # prod/dev
        - ip route add 10.230.164.0/24 via $(cat ***_container_ip) # test

编辑:gitlab.com 的解决方案

基于gitlab issue answer DinD 中的端口映射与 nonDinD gitlab-runner 有点不同,对于暴露的端口,您应该使用主机名“docker”。

例子:

services:
  - docker:stable-dind

variables:
  DOCKER_HOST: "tcp://docker:2375"

stages:
  - test

test env:
  image: tmaier/docker-compose:latest
  stage: test
  script:
    # containous/whoami with exposed port 80:80
    - docker-compose up -d
    - apk --no-cache add curl
    - curl docker:80              # <------- 
    - docker-compose down

【讨论】:

非常感谢Facty!我正在使用 gitlab 社区,并且没有自己的跑步者。以上是否可以使用社区跑步者(我不相信我可以在那里使用 toml 文件)?仅供参考:我赞成答案 啊,我从来没有使用过“云”社区版本,总是使用本地实例。但我的猜测是,您可以使用 DinD 服务获得相同的结果,因为这些 DinD 容器与“主”容器共享相同的网络。并感谢您的支持:) 感谢 Facty 的持续帮助。正如您所说,我一直在 docker 服务中使用 docker,它运行良好(它允许我运行 docker 和 docker compose)。我什至可以使用主机'docker'在dind中运行该服务时调用该服务,但是,我找不到在docker-compose上运行应用程序的主机。关于如何找到这个的任何想法?我已经尝试过 localhost、docker 以及通过 docker-compose 中的网络分配静态 ip,但我似乎无法让其中任何一个工作。 在多次尝试失败后(多么痛苦:))为dind 找到了解决方案:PIPELINE 问题是在dind 中如何处理端口映射。您必须使用主机名 docker 而不是其他任何东西 感谢工厂。如前所述,我一直在使用 docker host,它一直适用于在“纯”docker 中运行的应用程序。但是,我已经为在 docker-compose 中运行的应用程序尝试了这个解决方案,但它看起来并不工作。让我再次确认一下,但我相当肯定主机名可能不同....(手指交叉,我打错字什么的)【参考方案2】:

我使用的是 docker 而不是 docker-compose,上面的解决方案对我不起作用/ 我正在使用我自己的基于我安装 docker 和 buildx 的节点的图像,如下所示:

ARG NODE_VER=lts-alpine

FROM node:$NODE_VER

ARG BUILDX_VERSION=0.5.1
ARG DOCKER_VERSION=20.10.6
ARG BUILDX_ARCH=linux-arm-v7

RUN apk --no-cache add curl

# install docker
RUN curl -SL "https://download.docker.com/linux/static/stable/armhf/docker-$DOCKER_VERSION.tgz" | \
        tar -xz --strip-components 1 --directory /usr/local/bin/
COPY docker/modprobe.sh /usr/local/bin/modprobe
# replace node entrypoint by docker one /!\
COPY docker/docker-entrypoint.sh /usr/local/bin/
ENV DOCKER_TLS_CERTDIR=/certs
RUN mkdir /certs /certs/client && chmod 1777 /certs /certs/client

# download buildx
RUN mkdir -p /usr/lib/docker/cli-plugins \
 && curl -L \
      --output /usr/lib/docker/cli-plugins/docker-buildx \
      "https://github.com/docker/buildx/releases/download/v$BUILDX_VERSION/buildx-v$BUILDX_VERSION.$BUILDX_ARCH"
RUN chmod a+x /usr/lib/docker/cli-plugins/docker-buildx
RUN mkdir -p /etc/docker && echo '"experimental": true' > /usr/lib/docker/config.json

我的 gitlab-ci.yml 包含:

image: myimageabove

variables:
  DOCKER_DRIVER: overlay2
  PLATFORMS: linux/arm/v7
  IMAGE_NAME: $CI_PROJECT_NAME
  TAG: $CI_COMMIT_BRANCH-latest
  REGISTRY: registry.gitlab.com
  REGISTRY_ROOT: mygroup
  WEBSOCKETD_VER: 0.4.1
#  DOCKER_GATEWAY_HOST: 172.17.0.1
  DOCKER_GATEWAY_HOST: docker

services:
  - docker:dind

before_script:
  - docker info

build:
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $REGISTRY
    - docker buildx create --use
    - docker buildx build --platform $PLATFORMS --tag "$REGISTRY/$REGISTRY_ROOT/$IMAGE_NAME:$TAG" --push .

test:
  stage: test
  variables:
    WSD_DIR: /tmp/websocketd
    WSD_FILE: /tmp/websocketd/websocketd
  cache:
    key: websocketd
    paths: 
      - $WSD_DIR
  before_script:
# download websocketd and put in cache if needed
    - if [ ! -f $WSD_FILE ]; then
        mkdir -p $WSD_DIR;
        curl -o $WSD_FILE.zip -L "https://github.com/joewalnes/websocketd/releases/download/v$WEBSOCKETD_VER/websocketd-$WEBSOCKETD_VER-linux_arm.zip";
        unzip -o $WSD_FILE.zip websocketd -d $WSD_DIR;
        chmod 755 $WSD_FILE;
      fi;
    - mkdir /home/pier
    - cp -R ./test/resources/* /home/pier
    # get websocketd from cache
    - cp $WSD_FILE /home/pier/Admin/websocketd
    # setup envt variables
    - JWT_KEY=$(cat /home/pier/Services/Secrets/WEBSOCKETD_KEY)
    # - DOCKER_GATEWAY_HOST=$(/sbin/ip route|awk '/default/  print $3 ')
    # - DOCKER_GATEWAY_HOST=$(hostname)
    - ENVT="-e BASE_URL=/ -e JWT_KEY=$JWT_KEY -e WEBSOCKETD_KEY=$JWT_KEY -e WEBSOCKET_URL=ws://$DOCKER_GATEWAY_HOST:-host.docker.internal:8088 -e SERVICES_DIR=/home/pier/Services"
    - VOLUMES='-v /tmp:/config -v /home/pier/Services:/services -v /etc/wireguard:/etc/wireguard'

  script:
    # start websocketd
    - /home/pier/start.sh &
    # start docker pier admin
    - docker run -p 4000:4000 $ENVT $VOLUMES $REGISTRY/$REGISTRY_ROOT/$IMAGE_NAME:$TAG
    # run postman tests
    - newman run https://api.getpostman.com/collections/$POSTMAN_COLLECTION_UID?apikey=$POSTMAN_API_KEY

deploy:
  stage: deploy
  script:
    # just push to docker hub
    - docker login -u "$DOCKERHUB_REGISTRY_USER" -p "$DOCKERHUB_REGISTRY_PASSWORD" $DOCKERHUB
    - docker buildx build --platform $PLATFORMS --tag "$DOCKERHUB/mygroup/$IMAGE:$TAG" --push .

当我运行它时,构建工作正常,然后测试“before_script”工作但当脚本启动时,我得到以下跟踪:

# <= this starts the websocketd server locally on port 8088 =>
$ /home/pier/start.sh &
# <= this starts the image I just built which should connect to the above websocketd server =>
$ docker run -p 4000:4000 $ENVT $VOLUMES $REGISTRY/$REGISTRY_ROOT/$IMAGE_NAME:$TAG     
# <= trace of the websocketd server start with url ws://runner-hbghjvzp-project-22314059-concurrent-0:8088/ =>
Tue, 11 May 2021 12:08:13 +0000 | INFO   | server     |  | Serving using application   : ./websocket-server.py 
Tue, 11 May 2021 12:08:13 +0000 | INFO   | server     |  | Starting WebSocket server   : ws://runner-hbghjvzp-project-22314059-concurrent-0:8088/
# <= trace of the image start saying it tires to conenct to the websocketd server
Websocket connecting to ws://docker:8088 ...
Listen on port 4000
# <= trace with ENOTFOUND on "docker" address =>
websocket connection failed: Error: getaddrinfo ENOTFOUND docker
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:67:26) 
  errno: -3008,
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'docker'

/pier/storage/websocket-client.js:52
            throw err;
            ^
Error: getaddrinfo ENOTFOUND docker
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:67:26) 
  errno: -3008,
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'docker'

Cleaning up file based variables 00:01
ERROR: Job failed: exit code 1
 

我尝试了其他方法,例如:

websocket connection failed: Error: getaddrinfo ENOTFOUND host.docker.internal
websocket connection failed: Error: connect ETIMEDOUT 172.17.0.1:8088 # <= same error when trying $(/sbin/ip route|awk '/default/  print $3 ') =>
websocket connection failed: Error: getaddrinfo ENOTFOUND runner-meuessxe-project-22314059-concurrent-0  # using $(hostname)

出于新的想法... 非常感谢您对此提供任何帮助。

【讨论】:

以上是关于在 gitlab ci 中查找在 docker-compose 中运行的容器的 url/ip的主要内容,如果未能解决你的问题,请参考以下文章

查找掩码 CI/CD 变量的值

关于gitlab ci在include中使用变量

来自 gitlab-ci 的状态不再显示在 gitlab 合并请求中

gitlab-ci实际中需要注意几点

CI 配置将托管在 GitLab 内的不同项目中

如何使用 gitlab-ci.yml 在 gitlab 中更新 JSON 文件的内容?