简体   繁体   English

Gitlab CI 运行程序无法公开嵌套 Docker 容器的端口

[英]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 named mysql instead of a socket or localhost .因此,为了访问您的数据库服务,您必须连接到名为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

According to 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).

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM