Gitlab CI runner无法公开嵌套Docker容器的端口

时间:2017-01-10 01:11:26

标签: docker gitlab docker-compose gitlab-ci

当使用GitLab CI以及gitlab-ci-multi-runner时,我无法让内部启动的Docker容器将其端口暴露给" host&#34 ;,这就是Docker构建正在运行的图像。

我的.gitlab-ci.yml文件:

test:
  image: docker
  stage: test
  services:
    - docker:dind
  script:
    - APP_CONTAINER_ID=`docker run -d --privileged -p "9143:9143" appropriate/nc nc -l 9143`
    - netstat -a
    - docker exec $APP_CONTAINER_ID netstat -a
    - nc -v localhost 9143

我的命令:

gitlab-ci-multi-runner exec docker --docker-privileged test

输出:

$ netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 runner--project-1-concurrent-0:54664 docker:2375             TIME_WAIT
tcp        0      0 runner--project-1-concurrent-0:54666 docker:2375             TIME_WAIT
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node Path

$ docker exec $APP_CONTAINER_ID netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:9143            0.0.0.0:*               LISTEN
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node Path

$ nc -v localhost 9143
ERROR: Build failed: exit code 1
FATAL: exit code 1

我在这里做错了什么?

原始问题关注 - 上面是一个更短,更容易测试的例子

我有一个侦听端口9143的应用程序映像。它的启动和配置是通过docker-compose.yml进行管理的,并且在docker-compose up的本地计算机上运行良好 - 我可以毫无问题地访问localhost:9143

但是,当通过共享运行程序在GitLab CI(gitlab.com版本)上运行时,端口似乎没有暴露。

.gitlab-ci.yml的相关部分:

test:
  image: craigotis/buildtools:v1
  stage: test
  script:
    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com/craigotis/myapp
    - docker-compose up -d
    - sleep 60 # a temporary hack to get the logs
    - docker-compose logs
    - docker-machine env
    - docker-compose port app 9143
    - netstat -a
    - docker-compose ps
    - /usr/local/bin/wait-for-it.sh -h localhost -p 9143 -t 60
    - cd mocha
    - npm i
    - npm test
    - docker-compose down

输出结果为:

$ docker-compose logs
...
app_1  | [Thread-1] INFO spark.webserver.SparkServer - == Spark has ignited ...
app_1  | [Thread-1] INFO spark.webserver.SparkServer - >> Listening on 0.0.0.0:9143
app_1  | [Thread-1] INFO org.eclipse.jetty.server.Server - jetty-9.0.z-SNAPSHOT
app_1  | [Thread-1] INFO org.eclipse.jetty.server.ServerConnector - Started ServerConnector@6919dc5{HTTP/1.1}{0.0.0.0:9143}
...

$ docker-compose port app 9143
0.0.0.0:9143

$ netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       
tcp        0      0 runner-e11ae361-project-1925166-concurrent-0:53646 docker:2375             TIME_WAIT   
tcp        0      0 runner-e11ae361-project-1925166-concurrent-0:53644 docker:2375             TIME_WAIT   
tcp        0      0 runner-e11ae361-project-1925166-concurrent-0:53642 docker:2375             TIME_WAIT   
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node Path

$ docker-compose ps
stty: standard input: Not a tty
    Name                  Command               State                Ports               
----------------------------------------------------------------------------------------
my_app_1   wait-for-it.sh mysql_serve ...   Up      8080/tcp, 0.0.0.0:9143->9143/tcp 
mysql_server   docker-entrypoint.sh --cha ...   Up      3306/tcp     

$ /usr/local/bin/wait-for-it.sh -h localhost -p 9143 -t 60
wait-for-it.sh: waiting 60 seconds for localhost:9143
wait-for-it.sh: timeout occurred after waiting 60 seconds for localhost:9143

我的docker-compose.yml

的内容
version: '2'

networks:
    app_net:
        driver: bridge

services:
    app:
        image: registry.gitlab.com/craigotis/myapp:latest
        depends_on:
        - "db"
        networks:
        - app_net
        command: wait-for-it.sh mysql_server:3306 -t 60 -- java -jar /opt/app*.jar
        ports:
        - "9143:9143"

    db:
        image: mysql:latest
        networks:
        - app_net
        container_name: mysql_server
        environment:
        - MYSQL_ALLOW_EMPTY_PASSWORD=true

似乎就像我的应用程序容器正在监听9143一样,并且它正确地暴露给共享的GitLab运行程序,但它似乎并不是真的如此裸露。它在我的本地机器上工作正常 - 是否有一些特殊的解决方法/调整我需要在里面运行在GitLab上运行的Docker容器?

5 个答案:

答案 0 :(得分:6)

官方gitab-ci on gitlab.com documentation是指example of PostgreSQL

Its working CI不会尝试连接到localhost,而是尝试连接到service name

  

services关键字定义了另一个在构建期间运行的docker镜像,并链接到image关键字定义的docker镜像。这允许您在构建期间访问服务映像。

     

可以使用主机名mysql访问MySQL的服务容器   因此,要访问您的数据库服务,您必须连接到名为mysql的主机,而不是套接字或localhost

您可以检查这是否适用于您的情况,并尝试使用app:9143而不是localhost:9143访问您的应用服务。

答案 1 :(得分:4)

使用docker:dind时,会创建一个容器,并在其中设置docker-compose容器。它将端口公开给docker:dind容器中的localhost。您无法从正在执行代码的环境中以localhost访问它。

设置了docker的主机名,供您引用此docker:dind容器。您可以使用cat /etc/hosts进行检查。

您应该使用localhost:9143

,而不是引用docker:9143

答案 2 :(得分:2)

您的db.content.aggregate([ { $project: { _id: 1, contentId: 1, contentMetaData: 1 tempMetaData: "$contentMetaData" } }, { $unwind: "$contentMetaData" }, { $match: { "contentMetaData.name": "content_flag" } }, { $project: { _id: 1, contentId: 1, contentMetaData: "$tempMetaData", content_flag_value: "$contentMetaData.value" } }, { $project: { _id: 1, contentId: 1, contentMetaData: 1, tempMetaData: "$contentMetaData", content_flag_value: 1 } }, { $unwind: "$contentMetaData" }, { $match: { "contentMetaData.name": "text_content" } }, { $project: { _id: 1, contentId: 1, contentMetaData: 1, tempMetaData: "$contentMetaData", content_flag_value: 1, text_content : "$contentMetaData.children", temp_text_content: "$text_content" } }, { $unwind: "$text_content" }, { $group:{ _id:"$_id", contentId:{$first:"$contentId"}, text_content: {$max: {$cond: [ {$eq: ["$content_flag_value", "true"]}, {$cond: [{$or:[ {$eq: ["$text_content.name","wk_link_url"]}, {$eq: ["$text_content.name","wk_link_description"]} ]}, "$text_content", null] }, null ] } }, contentMetaData:{$first:"$contentMetaData"} } }, { $group:{ _id:"$_id", contentId:{$first:"$contentId"}, contentMetaData:{$push:{"text_content":"$text_content"}} } }, { $project: { _id: 0, contentId: 1, contentMetaData: 1 } }]).pretty() 似乎没问题。

但我认为您的IP或端口路由存在错误。 正如我从您的共享信息中看到的那样,您的应用在 0.0.0.0 上以 0.0.0.0 端口 9143 上运行 0.0.0.0:9143

您正在以docker-compose.yml的身份访问它, 可以解释为localhost:9143

根据this

127.0.0.1:9143

您可以尝试在127.0.0.1 is the loopback address (also known as localhost). 0.0.0.0 is a non-routable meta-address used to designate an invalid, unknown, or non-applicable target (a ‘no particular address’ place holder). 上运行您的应用,然后分享结果。

<强>更新

或者您可以使用服务按服务名称运行它 如documentation建议:

services关键字仅定义在构建期间运行的另一个docker镜像,并链接到image关键字定义的docker镜像。这允许您在构建期间访问服务映像。

可以在主机名 127.0.0.1:9143下访问MySQL的服务容器。 因此,为了访问您的数据库服务,您必须连接到名为mysql的主机而不是套接字或mysql

答案 3 :(得分:1)

通常,docker机器不会在localhost上运行,但在具有其他ip地址的docker主机上运行。尝试使用docker-machine ip来获取docker host ip。

答案 4 :(得分:0)

如果您 GitLab CI Runner 通过套接字绑定使用 Docker-executor 运行,请使用 host.docker.internal-host,因为您的应用程序在主机上运行,​​但是不是在客人身上。

# Run and ssh into dind-container
docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock docker:20.10-dind /bin/sh
# Next commands run in dind-container

docker run --rm -d -p 8888:80 nginx:alpine
...

wget -qO- "http://localhost:8888/"
wget: can't connect to remote host (127.0.0.1): Connection refused

wget -qO- "http://127.0.0.1:8888/"
wget: can't connect to remote host (127.0.0.1): Connection refused

wget -qO- "http://docker:8888/"
wget: bad address 'docker:8888'

wget -qO- "http://host.docker.internal:8888/"
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...