docker - 无法连接到在 VSTS 中运行的 Docker 容器

标签 docker azure-devops azure-pipelines

我有一个测试,它启动一个 Docker 容器,执行验证(它与 Docker 容器中的 Apache httpd 对话),然后停止 Docker 容器。

当我在本地运行这个测试时,这个测试运行得很好。但是当它在托管 VSTS 上运行时,即托管构建代理,它无法连接到 Docker 容器中的 Apache httpd。

这是 .vsts-ci.yml 文件:

queue: Hosted Linux Preview

steps:
- script: |
    ./test.sh

这是用于重现问题的 test.sh shell 脚本:
#!/bin/bash
set -e
set -o pipefail

function tearDown {
    docker stop test-apache
    docker rm test-apache
}
trap tearDown EXIT

docker run -d --name test-apache -p 8083:80 httpd
sleep 10

curl -D - http://localhost:8083/

当我在本地运行这个测试时,我得到的输出是:
$ ./test.sh 
469d50447ebc01775d94e8bed65b8310f4d9c7689ad41b2da8111fd57f27cb38
HTTP/1.1 200 OK
Date: Tue, 04 Sep 2018 12:00:17 GMT
Server: Apache/2.4.34 (Unix)
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
ETag: "2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
Content-Type: text/html

<html><body><h1>It works!</h1></body></html>
test-apache
test-apache

这个输出完全符合我的预期。

但是当我在 VSTS 上运行这个测试时,我得到的输出是(用 替换了不相关的部分)。
2018-09-04T12:01:23.7909911Z ##[section]Starting: CmdLine
2018-09-04T12:01:23.8044456Z ==============================================================================
2018-09-04T12:01:23.8061703Z Task         : Command Line
2018-09-04T12:01:23.8077837Z Description  : Run a command line script using cmd.exe on Windows and bash on macOS and Linux.
2018-09-04T12:01:23.8095370Z Version      : 2.136.0
2018-09-04T12:01:23.8111699Z Author       : Microsoft Corporation
2018-09-04T12:01:23.8128664Z Help         : [More Information](https://go.microsoft.com/fwlink/?LinkID=613735)
2018-09-04T12:01:23.8146694Z ==============================================================================
2018-09-04T12:01:26.3345330Z Generating script.
2018-09-04T12:01:26.3392080Z Script contents:
2018-09-04T12:01:26.3409635Z ./test.sh
2018-09-04T12:01:26.3574923Z [command]/bin/bash --noprofile --norc /home/vsts/work/_temp/02476800-8a7e-4e22-8715-c3f706e3679f.sh
2018-09-04T12:01:27.7054918Z Unable to find image 'httpd:latest' locally
2018-09-04T12:01:30.5555851Z latest: Pulling from library/httpd
2018-09-04T12:01:31.4312351Z d660b1f15b9b: Pulling fs layer
[…]
2018-09-04T12:01:49.1468474Z e86a7f31d4e7506d34e3b854c2a55646eaa4dcc731edc711af2cc934c44da2f9
2018-09-04T12:02:00.2563446Z   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
2018-09-04T12:02:00.2583211Z                                  Dload  Upload   Total   Spent    Left  Speed
2018-09-04T12:02:00.2595905Z 
2018-09-04T12:02:00.2613320Z   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (7) Failed to connect to localhost port 8083: Connection refused
2018-09-04T12:02:00.7027822Z test-apache
2018-09-04T12:02:00.7642313Z test-apache
2018-09-04T12:02:00.7826541Z ##[error]Bash exited with code '7'.
2018-09-04T12:02:00.7989841Z ##[section]Finishing: CmdLine

关键是这样的:
curl: (7) Failed to connect to localhost port 8083: Connection refused

10 秒应该足以让 apache 启动。
为什么 curl 不能在其 8083 端口上与 Apache 通信?

PS:

我知道像这样的硬编码端口是垃圾,我应该使用临时端口。我想让它首先通过硬编码端口运行,因为这比使用临时端口更简单,然后在硬编码端口工作后立即切换到临时端口。如果由于端口不可用而导致硬编码端口不起作用,则错误看起来应该有所不同,在这种情况下,docker run 应该会失败,因为无法分配端口。

更新:

可以肯定的是,我已经使用 sleep 100 而不是 sleep 10 重新运行了测试。结果不变, curl 无法连接到 localhost 端口 8083

更新 2:

扩展脚本以执行 docker logs 时,docker logs 显示 Apache 正在按预期运行。
扩展脚本以执行 docker ps 时,它​​显示以下输出:
2018-09-05T00:02:24.1310783Z CONTAINER ID        IMAGE                                                          COMMAND                  CREATED              STATUS              PORTS                  NAMES
2018-09-05T00:02:24.1336263Z 3f59aa014216        httpd                                                          "httpd-foreground"       About a minute ago   Up About a minute   0.0.0.0:8083->80/tcp   test-apache
2018-09-05T00:02:24.1357782Z 850bda64f847        microsoft/vsts-agent:ubuntu-16.04-docker-17.12.0-ce-standard   "/home/vsts/agents/2…"   2 minutes ago        Up 2 minutes                               musing_booth

最佳答案

问题在于 VSTS 构建代理在 Docker 容器中运行。当 Apache 的 Docker 容器启动时,它与 VSTS 构建代理 Docker 容器在同一级别上运行,而不是嵌套在 VSTS 构建代理 Docker 容器内。

有两种可能的解决方案:

  • 更换 localhost使用docker主机的ip地址,保留端口号8083
  • 更换 localhost用docker容器的ip地址,改变主机端口号8083到容器端口号 80 .

  • 通过 Docker 主机访问

    这种情况下,解决办法是更换localhost使用 docker 主机的 IP 地址。下面的 shell 片段可以做到这一点:
    host=localhost
    if grep '^1:name=systemd:/docker/' /proc/1/cgroup
    then
        apt-get update
        apt-get install net-tools
        host=$(route -n | grep '^0.0.0.0' | sed -e 's/^0.0.0.0\s*//' -e 's/ .*//')
    fi
    curl -D - http://$host:8083/
    
    if grep '^1:name=systemd:/docker/' /proc/1/cgroup检查脚本是否在 Docker 容器内运行。如果是这样,它会安装 net-tools访问 route命令,然后从 route 解析默认的 gw命令获取主机的IP地址。请注意,这仅在容器的网络默认 gw 实际上是主机时才有效。

    直接访问 Docker 容器

    启动docker容器后,可以通过以下命令获取其ip地址:
    docker container inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}' <container-id>
    

    替换 <container-id>使用您的容器 ID 或名称。

    因此,在这种情况下,它将是(假设第一个 IP 地址没问题):
    ips=($(docker container inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}' nuance-apache))
    host=${ips[0]}
    curl http://$host/
    

    关于docker - 无法连接到在 VSTS 中运行的 Docker 容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52166372/

    相关文章:

    docker - Ultraedit docker 语法高亮文件

    Docker 容器未运行

    AKS Kubectl 任务的 Azure Devops 管道无法将 list 部署到 AKS

    docker - 无法在Azure发布管道的App Service内部创建Docker网络

    azure-devops - 在 Azure DevOps 中的构建和发布管道之间共享变量

    Docker 正在运行,但我无法访问 localhost - Flask 应用程序

    php - 如何在不终止 docker 容器的情况下重新启动 apache2?

    azure - 如何限制azure devops服务器中状态之间的事务?

    azure - 从变量中读取 Azure Key Vault 任务中的 secret 变量

    azure - 从 AzureDevOps 替换 token 在应用程序设置中设置 JSON key