Gitlab CI runner 无法公开嵌套 Docker 容器的端口
Gitlab CI runner not able to expose ports of nested Docker containers
使用 GitLab CI 以及 gitlab-ci-multi-runner
时,我无法让内部启动的 Docker 容器将其端口暴露给 "host" ,这是构建为 运行.
的 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 运行器,但它似乎并没有真正暴露.它在我的本地机器上工作正常 - 是否有一些特殊的 workaround/tweak 我需要在 GitLab 上 inside 一个 Docker 容器 运行 中完成这项工作?
官方gitab-ci on gitlab.com documentation refers to the example of PostgreSQL
Its working CI does not try to connect to localhost, but rather to the service name
The services
keyword defines just another docker image that is run during your build and is linked to the docker image that the image keyword defines. This allows you to access the service image during build time.
The service container for MySQL will be accessible under the hostname mysql
.
So, in order to access your database service you have to connect to the host named mysql
instead of a socket or localhost
.
您可以检查这是否适用于您的情况,并尝试在 app:9143
而不是 localhost:9143
中访问您的应用程序服务。
通常 docker 机器不会 运行 在本地主机上,而是在具有其他 IP 地址的 docker 主机上。尝试使用 docker-machine ip
获取您的 docker 主机 ip。
你的docker-compose.yml
好像没问题。
但我认为您的 ip 或端口路由有误。
正如我从您的共享信息中看到的,您的应用程序 运行ning 在 port 9143 上 0.0.0.0 作为 0.0.0.0:9143.
并且您正在以 localhost:9143
的身份访问它,
可以解释为 127.0.0.1:9143
.
根据this。
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).
您能否尝试 运行 您的应用程序 127.0.0.1:9143
然后分享结果。
更新
或者您可以通过服务名称使用服务 运行
documentation 建议:
services 关键字只定义另一个 docker 图像,它在构建期间是 运行,并链接到 image 关键字定义的 docker 图像。这允许您在构建期间访问服务图像。
MySQL 的服务容器可以在 主机名 mysql
下访问。
因此,为了访问您的数据库服务,您必须连接到名为 mysql 的主机,而不是套接字或 localhost
.
当使用 docker:dind
时,会创建一个容器,并在其中设置您的 docker-compose 容器。它向 docker:dind
容器中的本地主机公开端口。您无法从执行代码的环境中以 localhost
的形式访问它。
已设置主机名 docker
供您引用此 docker:dind
容器。您可以使用 cat /etc/hosts
.
检查
您应该使用 docker:9143
.
而不是引用 localhost:9143
如果你 GitLab CI Runner 运行 与 Docker-executor via socket绑定使用 host.docker.internal
-host,因为您的应用程序 运行ning 在主机上而不是客户机上。
# 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>
...
使用 GitLab CI 以及 gitlab-ci-multi-runner
时,我无法让内部启动的 Docker 容器将其端口暴露给 "host" ,这是构建为 运行.
我的 .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 运行器,但它似乎并没有真正暴露.它在我的本地机器上工作正常 - 是否有一些特殊的 workaround/tweak 我需要在 GitLab 上 inside 一个 Docker 容器 运行 中完成这项工作?
官方gitab-ci on gitlab.com documentation refers to the example of PostgreSQL
Its working CI does not try to connect to localhost, but rather to the service name
The
services
keyword defines just another docker image that is run during your build and is linked to the docker image that the image keyword defines. This allows you to access the service image during build time.The service container for MySQL will be accessible under the hostname
mysql
.
So, in order to access your database service you have to connect to the host namedmysql
instead of a socket orlocalhost
.
您可以检查这是否适用于您的情况,并尝试在 app:9143
而不是 localhost:9143
中访问您的应用程序服务。
通常 docker 机器不会 运行 在本地主机上,而是在具有其他 IP 地址的 docker 主机上。尝试使用 docker-machine ip
获取您的 docker 主机 ip。
你的docker-compose.yml
好像没问题。
但我认为您的 ip 或端口路由有误。 正如我从您的共享信息中看到的,您的应用程序 运行ning 在 port 9143 上 0.0.0.0 作为 0.0.0.0:9143.
并且您正在以 localhost:9143
的身份访问它,
可以解释为 127.0.0.1:9143
.
根据this。
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).
您能否尝试 运行 您的应用程序 127.0.0.1:9143
然后分享结果。
更新
或者您可以通过服务名称使用服务 运行 documentation 建议:
services 关键字只定义另一个 docker 图像,它在构建期间是 运行,并链接到 image 关键字定义的 docker 图像。这允许您在构建期间访问服务图像。
MySQL 的服务容器可以在 主机名 mysql
下访问。
因此,为了访问您的数据库服务,您必须连接到名为 mysql 的主机,而不是套接字或 localhost
.
当使用 docker:dind
时,会创建一个容器,并在其中设置您的 docker-compose 容器。它向 docker:dind
容器中的本地主机公开端口。您无法从执行代码的环境中以 localhost
的形式访问它。
已设置主机名 docker
供您引用此 docker:dind
容器。您可以使用 cat /etc/hosts
.
您应该使用 docker:9143
.
localhost:9143
如果你 GitLab CI Runner 运行 与 Docker-executor via socket绑定使用 host.docker.internal
-host,因为您的应用程序 运行ning 在主机上而不是客户机上。
# 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>
...