问题:Docker 服务注册到 Consul 但健康检查失败

我想在 docker 容器中放置一个 spring boot 应用程序。它使用 @EnableDiscoveryClient 将其与 consul u003d> 集成,并且健康检查在 docker 之外完美运行。

我用这个 dockerfile 嵌入了这个示例应用程序(来自http://rpi-cloud.com/apigatewaypattern/的电影应用程序):

# VERSION 1.0
FROM java:8

ADD ./movie-0.0.1-SNAPSHOT.jar /

# server port
EXPOSE 9000

WORKDIR /
CMD ["java", "-jar", "/movie-0.0.1-SNAPSHOT.jar"]

然后从以下 docker-compose.yml 运行它:

# service discovery
consul:
    image: consul    
    ports:
       - "8500:8500"    # 8500 (HTTP)
    command: agent -server -bootstrap-expect 1 -ui -data-dir /tmp -client=0.0.0.0

## test service
movie:
    build: ./movie
    ports:
      - "9000:9000"
    links:
        - consul:localhost  # for consul registry and configuration

如您所见,我试图变得聪明:为了避免将 consul 本身嵌入到电影容器中,我将 consul 主机(ip)绑定到电影容器的 localhost(使用 docker 网络功能)。

它适用于服务发现:consul ui 告诉我电影应用程序能够注册自己,但它不能以其他方式工作:当 consul 服务尝试访问电影服务的 /health api 时,健康检查失败。这是领事日志的输出:

 2016/05/19 15:50:38 [INFO] agent: Synced service 'movie-9000'

后者:

2016/05/19 15:50:43 [WARN] agent: http request failed 'http://ca676cad169e:9000/health': Get http://ca676cad169e:900
0/health: dial tcp: lookup ca676cad169e on 10.0.2.3:53: server misbehaving

它无限期地重复自己。我不明白为什么?任何想法 ?

编辑 使用 docker-compose 版本 2 时:

version: '2'
services:
   consul: ... (unchanged)
   movie: ... (unchanged)
    links:
        - consul:localhost  # for consul registry and configuration

领事开始正常,但电影服务无法自行注册 u003d> 连接被拒绝。链接似乎在 v2 中无效。因为https://github.com/docker/compose/issues/3127

links 不再由 /etc/hosts 提供,它们现在由 Docker 1.10.x. 中可用的嵌入式 DNS 服务器提供,这打破了 localhost 技巧。

阿黛提

如果我为版本 2(使用 consul ip)明确设置附加主机,它工作正常。

version: '2'

services:
  movie:
  # removed link keyword and replaced by
      extra_hosts:
        - "localhost:172.19.0.2"
  # specifying consul ip

阿迪塔

这是版本 2 的电影容器看到的 /etc/hosts,没有添加 extra_hosts:

127.0.0.1  localhost
::1        localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.19.0.3 45210c319110

而在版本 1 中:

127.0.0.1  localhost
::1        localhost ip6-localhost ip6-loopback
... # same +
172.17.0.2 localhost 88a07a35f228 ci_consul_1

如何在保持网络功能的同时自动化并重新创建版本 1 的行为?

Edit4 - 结论

\u003d> 这对于 localhost 技巧来说似乎是不可行的。所以我在docker中使用不同的配置(如建议的那样)。

这最终不是一个大问题,因为默认的 consul 主机可以在 Dockerfile 的 CMD 中的命令行上被覆盖,然后我可以使用 consul 作为主机名。 (参见弹簧过载机制http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html)

# in movie Dockerfile
CMD ["java", "-jar", "/movie-0.0.1-SNAPSHOT.jar", "--spring.cloud.consul.host=consul"]

Docker 版本

我在带有 docker-machine 的 Windows 上使用 docker 1.11.1

Docker 版本 1.11.1,构建 5604cbe

docker-compose 版本 1.7.0,构建 0d7bf73

解答

由于您没有使用 compose 版本 2。这两个容器不共享同一个网络。

Consul 执行定期健康检查以确保服务启动并运行,因此需要访问应用程序健康检查服务。这是“http://ca676cad169e:9000/health”

由于您已经定义了从 app 容器到 consul 容器的链接,因此服务的注册工作正常。该应用程序出现时会向领事注册。

您可以定义由容器共享的网络,也可以在主机网络上运行容器。

您将需要使用net: "host"选项

这是文档https://docs.docker.com/compose/compose-file/#net的链接

使用 docker 现有的 docker compose 版本,您可以更新电影应用程序的健康检查端点。然后它将不使用默认值,并将在外部化端口上查询应用程序。

spring:
  cloud:
    consul:
      discovery:
        healthCheckPath: localhost:9000/health
        healthCheckInterval: 15s`

我用 docker compose 版本 2 尝试了这个,并且可以通过两种方式访问容器,网络应该允许你以任何一种方式进行通信。在我的示例中,我使用 consul 容器下载了 nginx 页面。

version: "2"

services:
  app:
    image: nginx
    ports:
      - "9000:80"
  discovery:
    image: consul
    ports:
        - "8500:8500"
    command: agent -server -bootstrap-expect 1 -ui -data-dir /tmp -client=0.0.0.0
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区