[英]Gitlab CI runner not able to expose ports of nested Docker containers
When using GitLab CI, as well as the gitlab-ci-multi-runner
, I'm unable to get internally-started Docker containers to expose their ports to the "host", which is the Docker image in which the build is running.使用 GitLab CI 以及
gitlab-ci-multi-runner
,我无法让内部启动的 Docker 容器将其端口公开给“主机”,即运行构建的 Docker 映像。
My .gitlab-ci.yml
file:我的
.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
My command:我的命令:
gitlab-ci-multi-runner exec docker --docker-privileged test
The output:输出:
$ 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
What am I doing wrong here?我在这里做错了什么?
Original Question Follows - above is a shorter, easier-to-test example原始问题如下 - 以上是一个更短、更易于测试的示例
I have an application image that listens on port 9143
.我有一个侦听端口
9143
的应用程序映像。 Its startup and config is managed via docker-compose.yml
, and works great on my local machine with docker-compose up
- I can access localhost:9143
without issue.它的启动和配置是通过
docker-compose.yml
管理的,并且在我的本地机器上使用docker-compose up
- 我可以localhost:9143
访问localhost:9143
。
However, when running on GitLab CI (the gitlab.com
version) via a shared runner, the port doesn't seem to be exposed.但是,当通过共享运行程序在 GitLab CI(
gitlab.com
版本)上运行时,端口似乎没有暴露。
The relevant portion of my .gitlab-ci.yml
:我的
.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
The output is:输出是:
$ 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
The contents of my docker-compose.yml
:我
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
It seems like my application container is listening on 9143
, and it's properly exposed to the shared GitLab runner, but it doesn't seem to actually be exposed.似乎我的应用程序容器正在侦听
9143
,并且它已正确公开给共享的 GitLab 运行程序,但实际上似乎并未公开。 It works fine on my local machine - is there some special workaround/tweak I need to make this work inside a Docker container running on GitLab?它的工作原理我的本地机器上的罚款-有一些特殊的解决方法/调整,我需要做出GitLab运行的泊坞容器内工作的呢?
When using docker:dind
a container is created and your docker-compose containers get setup within it.使用
docker:dind
会创建一个容器,并在其中设置您的docker:dind
-compose 容器。 It exposes the ports to localhost within the docker:dind
container.它在
docker:dind
容器中向本地主机公开端口。 You cannot access this as localhost
from the environment that your code is executing in.您无法从执行代码的环境中以
localhost
身份访问它。
A hostname of docker
is setup for you to reference this docker:dind
container.的主机名
docker
是设置供你参考这个docker:dind
容器。 You can check by using cat /etc/hosts
.您可以使用
cat /etc/hosts
。
Instead of referencing localhost:9143
you should use docker:9143
.您应该使用
docker:9143
localhost:9143
而不是引用localhost:9143
docker:9143
。
The offical gitab-ci on gitlab.com documentation refers to the example of PostgreSQL gitlab.com 文档中的官方gitab-ci是指PostgreSQL的例子
Its working CI does not try to connect to localhost, but rather to the service name 它的工作 CI不会尝试连接到本地主机,而是连接到服务名称
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.services
关键字仅定义在构建期间运行的另一个 docker 映像,并链接到 image 关键字定义的 docker 映像。 This allows you to access the service image during build time.这允许您在构建期间访问服务映像。
The service container for MySQL will be accessible under the hostname
mysql
.MySQL 的服务容器可以在主机名
mysql
下访问。
So, in order to access your database service you have to connect to the host namedmysql
instead of a socket orlocalhost
.因此,为了访问您的数据库服务,您必须连接到名为
mysql
的主机而不是套接字或localhost
。
You could check if this applies in your case, and try accessing your application service in app:9143
instead of localhost:9143
.您可以检查这是否适用于您的情况,并尝试在
app:9143
而不是localhost:9143
访问您的应用程序服务。
Your docker-compose.yml
seems to be ok.你
docker-compose.yml
似乎没问题。
But I think there is error with your ip or port routing.但我认为您的 ip 或端口路由有问题。 As I can see from your shared info your app is running on port 9143 on ip 0.0.0.0 as 0.0.0.0:9143 .
正如我从您的共享信息中看到的,您的应用程序在 ip 0.0.0.0上的端口9143上运行为0.0.0.0:9143 。
and you are accessing it as localhost:9143
, which can be interpreted as 127.0.0.1:9143
.并且您以
localhost:9143
访问它,可以将其解释为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).
Can you try to run your app on 127.0.0.1:9143
then share the result.您可以尝试在
127.0.0.1:9143
上运行您的应用程序,然后分享结果。
UPDATE更新
or you can use service to run it by service name as documentation suggest:或者您可以使用 service 按服务名称运行它,如 文档所示:
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. services 关键字仅定义在构建期间运行的另一个 docker 映像,并链接到 image 关键字定义的 docker 映像。 This allows you to access the service image during build time.
这允许您在构建期间访问服务映像。
The service container for MySQL will be accessible under the hostname mysql
. MySQL 的服务容器可以在主机名
mysql
下访问。 So, in order to access your database service you have to connect to the host named mysql instead of a socket or localhost
.因此,为了访问您的数据库服务,您必须连接到名为 mysql 的主机而不是套接字或
localhost
。
Usually a docker machine won't run on localhost, but on a docker host with some other ip address.通常 docker 机器不会在 localhost 上运行,而是在具有其他 IP 地址的 docker 主机上运行。 Try using
docker-machine ip
to get your docker host ip.尝试使用
docker-machine ip
来获取您的 docker 主机 ip。
In case you GitLab CI Runner run with Docker -executor via socket binding use host.docker.internal
-host, because your app is running on the host machine but not on the guest.如果您的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>
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.