【问题标题】:Docker-Compose dynamically assigned ports with ConsulDocker-Compose 使用 Consul 动态分配端口
【发布时间】:2018-08-10 00:52:35
【问题描述】:

我正在运行许多使用 Consul 进行服务发现的 Spring Boot 应用程序(使用 Actuator)。如果我使用 docker-compose 启动应用程序,为每个容器指定主机和容器端口,那么它们会在 Consul 中正确注册并很快被标记为健康。

spring:
  application:
    name: myapp-A
  profiles:
    active: default 
  cloud:
    consul:
      enabled: true
      host: consul
      port: 8500
      discovery:
        prefer-ip-address: true
        healthCheckUrl: http://docker-host:${server.port}/health

“consul”和“docker-host”的主机地址值在启动时作为环境变量传入 docker-compose yml 文件中,简单来说与 docker 主机的 IP 地址相关(我正在运行领事在同一台服务器上)。

还请注意:

${server.port}

变量告诉 Consul 如何连接回容器以检查其健康状况(在这方面它只是使用了 Actuator)。这需要是外部可访问的地址和端口,以便 Consul 可以检查服务。

当我在 docker-compose 文件中为容器指定主机和容器端口号时,这一切正常。

我已经到了想要扩展一些容器的地步,但是当我尝试执行时

docker-compose up -d --scale myapp-A=5

命令它告诉我这是不可能的,因为已经指定了主机端口。如果我将 docker-compose yml 文件更改为仅定义容器端口,并让主机端口动态分配,那么这一切都会出错,因为 Consul(在外部运行)获得了错误的 URL 来连接并将容器标记为不健康。

我的问题是如何告诉 Consul 动态和“外部”公开的端口号,以便在容器内运行的我的应用程序中使用?

有没有办法在创建时获取端口号并将其传递到容器中?

如果可以的话,我想尝试使用 Compose 来破解这个问题(而不是使用 Swarm,或者通过在同一组容器中的另一个容器中运行 Consul)。

【问题讨论】:

    标签: docker docker-compose consul spring-cloud-consul


    【解决方案1】:

    单个主机上的扩展和端口映射通常不能很好地结合在一起。

    如果您想支持动态映射的端口,那么您可能需要服务发现来进行服务发现。由于 spring 应用程序本身永远不会知道您需要以某种方式从 Docker 守护程序提供信息的外部映射端口。

    在 Docker 方面,由于您已经在使用 consul,Registrator 可以将容器信息发布为服务:

    → docker ps -f name=verdaccio
    CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                    NAMES
    a9f0726027fd        deployable/verdaccio:2.7.3   "node --trace_gc /ap…"   3 days ago          Up 12 hours         0.0.0.0:4873->4873/tcp   verdaccio
    

    最终以 consul 作为服务:

    → curl -s 10.8.8.8:8521/v1/catalog/service/verdaccio | jq
    [
      {
        "ID": "fe50cd37-576f-fbce-cb63-567359c87257",
        "Node": "c8fecf7ed36a",
        "Address": "172.16.231.22",
        "Datacenter": "dc1",
        "TaggedAddresses": {
          "lan": "172.16.231.22",
          "wan": "172.16.231.22"
        },
        "NodeMeta": {
          "consul-network-segment": ""
        },
        "ServiceID": "registrator:verdaccio:4873",
        "ServiceName": "verdaccio",
        "ServiceTags": [
          "mhmb"
        ],
        "ServiceAddress": "",
        "ServicePort": 4873,
        "ServiceEnableTagOverride": false,
        "CreateIndex": 139,
        "ModifyIndex": 139
      }
    ]
    

    端口在 SRV DNS 记录中可用:

    → dig @127.0.0.1 -p 8621 verdaccio.service.consul. SRV
    
    ; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8621 verdaccio.service.consul. SRV
    ; (1 server found)
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4713
    ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2
    ;; WARNING: recursion requested but not available
    
    ;; QUESTION SECTION:
    ;verdaccio.service.consul.  IN  SRV
    
    ;; ANSWER SECTION:
    verdaccio.service.consul. 0 IN  SRV 1 1 4873 c8fecf7ed36a.node.dc1.consul.
    
    ;; ADDITIONAL SECTION:
    c8fecf7ed36a.node.dc1.consul. 0 IN  A   172.16.231.22
    c8fecf7ed36a.node.dc1.consul. 0 IN  TXT "consul-network-segment="
    
    ;; Query time: 2 msec
    ;; SERVER: 127.0.0.1#8621(127.0.0.1)
    ;; WHEN: Thu Mar  1 23:08:15 2018
    ;; MSG SIZE  rcvd: 142
    

    不过,我不确定如何配置 Spring Cloud Consul 以使用此信息。 Spring Cloud 是否包含一些注入动态属性的功能?如果您可以让 Spring 在发布服务之前查找 SRV 记录或发出 API 请求,那么您将被排序。或者,Consul 需要直接支持健康检查 SRV 记录,我不相信它会这样做。

    【讨论】:

    • 谢谢马特。我放弃了抗争,最终在同一个 Docker 网络中的容器中运行 Consul。不过,感谢您的意见,给我进一步的说明非常有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-11
    • 1970-01-01
    • 2017-08-24
    • 1970-01-01
    相关资源
    最近更新 更多