【问题标题】:Docker-compose multiple ports exposeDocker-compose 多个端口暴露
【发布时间】:2019-06-21 01:54:38
【问题描述】:

我的问题是关于在ENV 变量示例中在一行中公开多个端口,并且这些端口不是连续的,来自主机的相同端口在容器上将是相同的。

PORTS=80
PORTS=80,443
PORTS=80 443

并在docker-compose 中公开它们。

根据docs,你可以做到。

ports:
 - "3000"
 - "3000-3005"
 - "8000:8000"
 - "9090-9091:8080-8081"
 - "49100:22"
 - "127.0.0.1:8001:8001"
 - "127.0.0.1:5000-5010:5000-5010"
 - "6060:6060/udp"

但我想用另一种可变的方式来做

ports:
  - ${PORTS}:${PORTS}
#Sometimes this will be 
ports:
  - 80:80

#Other times this will be
ports:
  - 80,443:80,443 # Is this possible?
ports:
  - 80-443:80-443 # Don't want this because will export all the ports between
ports:
  - 80 443:80 443 # I think this is wrong syntax

任何线索或任何其他想法?

【问题讨论】:

    标签: docker nginx docker-compose


    【解决方案1】:

    IIUC 你不能动态指定ports 映射。

    Docker Compose YAML 文件主要是静态配置。

    解决问题的一种方法是生成(ports 部分)YAML 文件。

    您可以使用 sed 之类的工具将 Compose 文件中的变量替换为生成的输出。

    假设你有docker-compose.yaml:

      service:
        ...
        {{PORTS}}
    

    然后

    # List of ports to create
    PORTS="80 443 8888"
    
    # Generates "80:80""443:443""8888:8888" NB no commas between items
    PORTS=$(for PORT in ${PORTS}; do printf '"%s:%s"' ${PORT} ${PORT}; done)
    
    # Separate items with commas
    PORTS=$(echo ${PORTS} | sed 's|""|","|g')
    
    # Finalize the syntax for ports
    PORTS="ports: [${PORTS}]"
    
    # Replace {{TEMPLATE}} with the result
    sed "s|{{PORTS}}|${PORTS}|g" docker-compose.yaml > docker-compose.new.yaml
    

    会产生docker-compose.new.yaml:

      service:
        ...
        ports: ["80:80","443:443","8888:8888"]
    

    它不是很优雅,但应该足够了。

    NB 为了方便起见,我将端口生成为 JSON(以避免换行问题)。 YAML 是 JSON 的超集,因此您可以在 Docker Compose 文件中使用 JSON 而不是 YAML。

    Google(我的雇主)有一个非常好的工具,可以使用基于 JSON 的模板语言生成 JSON(!):Jsonnet。因为 YAML 是 JSON 的超集,所以您可以在 Docker Compose 文件中使用 JSON 而不是 YAML。

    Jsonnet:

    local ports = ["80", "443", "8888"]; 
    {"service":{
        "ports": [
            port + ":" + port
            for port in ports
        ]
    }}
    

    生成:

    {
      "service": {
        "ports": [
          "80:80",
          "443:443",
          "8888:8888"
        ]
      }
    }
    

    【讨论】:

    • 使用 Jsonnet 的非常好的解决方案。但是,你如何将它传递给 Jsonnet 并得到结果?我打算在 CI/CD 上使用它。我假设你使用 GO 构建来使用 Jsonnet,这就是我要做的,并从每个 CI 的模板生成 docker-compose JSON。
    • 是的,完全正确。请在您承诺之前测试所有内容,以确保我没有错过一个明显的陷阱!或者等着看其他人是否有更优雅的解决方案。我为 Google Cloud Platform 的 Cloud Build 服务编写了一个 Jsonnet 构建器。 Cloud Build(以前的 Container Builder)是 Google 的 CI|CD 服务。 medium.com/@DazWilkin/….