Не удается подключиться к контейнеру Docker, работающему в VSTS - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть тест, который запускает контейнер Docker, выполняет проверку (которая обращается к Apache httpd в контейнере Docker), а затем останавливает контейнер Docker.

Когда я запускаю этот тест локально, этот тест работает нормально Но когда он работает на размещенном VSTS , то есть размещенном агенте сборки , он не может подключиться к Apache httpd в контейнере Docker.

Это файл .vsts-ci.yml:

queue: Hosted Linux Preview

steps:
- script: |
    ./test.sh

Это сценарий test.sh для воспроизведения проблемы:

#!/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 не может связаться с Apache через его порт 8083?

P.S:.

Я знаю, что такой жестко закодированный порт - это мусор, и что вместо этого я должен использовать эфемерный порт. Сначала я хотел, чтобы он работал с жестко запрограммированным портом, потому что это проще, чем использовать эфемерный порт, а затем переключиться на эфемерный порт, как только будет работать жестко запрограммированный порт. И в случае, если жестко заданный порт не работает из-за того, что порт недоступен, ошибка должна выглядеть иначе, в этом случае 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

1 Ответ

0 голосов
/ 05 сентября 2018

Проблема в том, что агент сборки VSTS работает в контейнере Docker. Когда контейнер Docker для Apache запущен, он работает на том же уровне, что и контейнер Docker агента сборки VSTS, не вложенный в контейнер Docker агента сборки VSTS.

Существует два возможных решения:

  • Замена localhost на IP-адрес хоста докера с сохранением номера порта 8083
  • Замена localhost на ip-адрес контейнера-докера, замена номера порта хоста 8083 на номер порта контейнера 80.

Доступ через Docker Host

В этом случае решение состоит в том, чтобы заменить localhost на IP-адрес хоста докера. Следующий фрагмент оболочки может сделать это:

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, а затем анализирует gw по умолчанию из команды route, чтобы получить IP-адрес хоста. Обратите внимание, что это работает только в том случае, если gw контейнера по умолчанию является хостом.

Прямой доступ к Docker-контейнеру

После запуска docker-контейнера его ip-адреса можно получить с помощью следующей команды:

docker container inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}' <container-id>

Замените <container-id> на ваш идентификатор контейнера или имя.

Итак, в этом случае это будет (при условии, что первый IP-адрес в порядке):

ips=($(docker container inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}' nuance-apache))
host=${ips[0]}
curl http://$host/
...