【问题标题】:What is the difference between docker-compose ports vs exposedocker-compose 端口与暴露之间有什么区别
【发布时间】:2020-02-03 00:37:09
【问题描述】:

docker-compose.yml 中的portsexpose 选项有什么区别?

【问题讨论】:

    标签: docker docker-compose


    【解决方案1】:

    根据docker-compose reference

    Ports 定义为:

    公开端口。要么指定两个端口 (HOST:CONTAINER),要么只指定容器端口(将选择随机主机端口)。

    • docker-compose.yml 中提到的端口将在 docker-compose 启动的不同服务之间共享。
    • 端口将向主机公开随机端口或给定端口。

    我的docker-compose.yml 看起来像:

    mysql:
      image: mysql:5.7
      ports:
        - "3306"
    

    如果我做docker-compose ps,它看起来像:

      Name                     Command               State            Ports
    -------------------------------------------------------------------------------------
      mysql_1       docker-entrypoint.sh mysqld      Up      0.0.0.0:32769->3306/tcp
    

    Expose 定义为:

    公开端口而不将它们发布到主机 - 它们只能被链接的服务访问。只能指定内部端口。

    端口不暴露给主机,只暴露给其他服务。

    mysql:
      image: mysql:5.7
      expose:
        - "3306"
    

    如果我做docker-compose ps,它看起来像:

      Name                  Command             State    Ports
    ---------------------------------------------------------------
     mysql_1      docker-entrypoint.sh mysqld   Up      3306/tcp
    

    编辑

    在最新版本的 Dockerfile 中,EXPOSE 不再对操作产生任何影响,它只是提供信息。 (see also)

    【讨论】:

    • 能否解释一下在docker-compose 中指定expose 有什么优势?据我所知,您不需要指定公开来使链接服务可以访问端口。
    • 难道不应该告诉暴露的端口只能用于同一个 docker 网络中的服务(链接正在被大多数部分替换)?。
    • @Juicy 我猜它类似于 Dockerfiles 中的expose:“EXPOSE 指令实际上并没有发布端口。它的功能是一种文档...”docs.docker.com/engine/reference/builder/#expose
    • 端口是否覆盖防火墙级别的任何设置?我刚刚注意到我没有在防火墙上为 mysql 开放端口,但是可以远程访问它们。我将端口设置为“3306:3306”而不是暴露。
    • 请记住,如果您使用docker-compose rundocker-compose.yml 中的端口定义默认忽略。使用docker-compose up 或提供参数--service-ports
    【解决方案2】:

    端口

    1. 激活容器以侦听来自 docker 外部世界的指定端口(可以是同一主机或不同的机器)以及 docker 内部的可访问世界。
    2. 可以指定多个端口(这就是为什么 ports 不能指定端口)

    公开

    1. 激活容器以仅从 docker 内部世界和 docker 外部不可访问的世界侦听特定端口。
    2. 可以指定多个端口

    【讨论】:

    • 请注意,expose 允许多个端口 - docs.docker.com/compose/compose-file/#expose - 但是您只提供内部端口而不是内部 + 外部
    • 这是非常重要的部分:'激活容器以仅从内部世界监听特定端口'
    【解决方案3】:

    端口 该部分用于定义主机服务器和 Docker 容器之间的映射。

    ports:
       - 10005:80
    

    表示容器内运行的应用暴露在80端口,但外部系统/实体无法访问,需要映射到宿主服务器端口。

    注意:您必须打开主机端口 10005 并修改防火墙规则以允许外部实体访问应用程序。

    他们可以使用

    http://{主机 IP}:10005

    类似的东西

    曝光 这专门用于定义在 docker 容器内运行应用程序的端口。

    您也可以在 dockerfile 中定义它。一般来说,在 dockerfile 中定义 EXPOSE 是一种很好且广泛使用的做法,因为很少有人在默认 80 端口以外的其他端口上运行它们

    【讨论】:

      【解决方案4】:

      端口

      ports 部分将在主机上发布端口。 Docker 将为从主机网络到容器的特定端口设置转发。默认情况下,这是通过用户空间代理进程 (docker-proxy) 实现的,该进程侦听第一个端口,然后转发到需要侦听第二个端口的容器。如果容器没有在目标端口上侦听,您仍然会在主机上看到一些东西正在侦听,但是如果您尝试连接到该主机端口,则会从失败的转发到您的容器中获得连接被拒绝。

      请注意,容器必须监听所有网络接口,因为此代理不在容器的网络命名空间内运行,并且无法到达容器内的 127.0.0.1。 IPv4 方法是将您的应用程序配置为侦听0.0.0.0

      另请注意,已发布的端口不会以相反的方向工作。您无法通过发布端口从容器连接到主机上的服务。相反,您会发现尝试侦听已在使用的主机端口时出现 docker 错误。

      公开

      公开是文档。它在图像上设置元数据,并且在运行时也在容器上设置元数据。通常,您在 Dockerfile 中使用 EXPOSE 指令进行配置,它作为运行您的镜像的用户的文档,让他们知道默认情况下您的应用程序将侦听哪些端口。当使用 compose 文件配置时,此元数据仅在容器上设置。当您在映像或容器上运行 docker inspect 时,您可以看到暴露的端口。

      有一些工具依赖于暴露的端口。在 docker 中,-P 标志会将所有暴露的端口发布到主机上的临时端口上。如果您没有明确设置容器端口,那么在向您的应用程序发送流量时,还有各种反向代理默认使用公开端口。

      除了那些外部工具之外,expose 对容器之间的网络完全没有影响。您只需要一个通用的 docker 网络,并连接到容器端口,就可以从另一个容器访问一个容器。如果该网络是用户创建的(例如,不是名为 bridge 的默认桥接网络),您可以使用 DNS 连接到其他容器。

      【讨论】:

      • 听着,伙计们!这个答案可能看起来不太好,但信息量很大。
      【解决方案5】:

      我完全同意之前的答案。 我只想提一下,expose 和 ports 之间的区别是 docker 中安全概念的一部分。它与 docker 的 networking 齐头并进。 例如:

      想象一个具有 Web 前端和数据库后端的应用程序。 外部世界需要访问 web 前端(可能在端口上) 80),但只有后端本身需要访问数据库主机 和港口。使用用户定义的网桥,只需要 web 端口 打开,并且数据库应用程序不需要打开任何端口, 因为网络前端可以通过用户定义的网桥访问它。

      这是在 docker 中设置网络架构时的常见用例。 因此,例如在默认桥接网络中,外部世界无法访问端口。 因此,您可以使用“端口”打开一个入口点。通过使用“公开”,您可以定义网络内的通信。如果要公开默认端口,则无需在 docker-compose 文件中定义“公开”。

      【讨论】: