概述

众所周知,Docker Compose是一个同时定义和管理多个容器的工具。默认情况下,Docker Compose 会为定义的容器设置一个专用网络,从而实现它们之间的通信。因此,我们可以使用单个命令使用给定的配置文件创建和运行服务。

在这篇文章中,我们将看到两个 YAML 属性,它们允许我们自定义容器之间的网络: exposeports。我们将详细描述它们,展示基本用例,并突出它们的主要区别。

Expose

services:
  myapp1:
    ...
    expose:
      - "3000"
      - "8000"
  myapp2:
    ...
    expose:
      - "5000"

如我们所见,我们可以为每个服务指定多个值。我们刚刚暴露了myapp1 容器的3000 和8000端口以及myapp2容器的5000端口。现在,同一网络中的其他容器可以在这些端口上访问这些服务。

现在让我们检查暴露的端口:

> docker ps
CONTAINER ID   IMAGE    COMMAND     CREATED     STATUS      PORTS               NAMES
8673c14f18d1   ...      ...         ...         ...         3000/tcp, 8000/tcp  bael_myapp1
bc044e180131   ...      ...         ...         ...         5000/tcp            bael_myapp2

在docker ps命令输出中,我们可以在PORTS 列中找到暴露的端口。

最后,我们来验证一下容器之间的通信:

> docker exec -it bc044e180131 /bin/bash

bash-5.1$ nc -vz myapp1 3000
myapp1 (172.18.0.1:3000) open
bash-5.1$ nc -vz myapp1 8000
myapp1 (172.18.0.1:8000) open

我们刚刚连接到myapp2 CLI。使用netcat命令,我们检查了从myapp1暴露的两个端口是否都可以访问。

Ports

现在让我们看一看Ports部分。和之前的一样,这个属性定义了我们想要从容器中公开的端口。但与Expose不同的是,这些端口可以在内部访问并在宿主机上发布。

和之前一样,我们可以在专用部分为每个服务定义端口,但配置可能更复杂。首先,我们必须在两种语法(短和长)之间进行选择来定义配置。

短句法

让我们从分析短的开始。简短语法是一个以冒号分隔的字符串,用于设置主机 IP 地址、主机端口和容器端口:

[HOST:]CONTAINER[/PROTOCOL]

这里,HOST是一个主机端口号或一系列端口号,可以在前面加上一个 IP 地址。如果我们不指定 IP 地址,Docker Compose 会将端口绑定到所有网络接口。

CONTAINER定义一个容器端口号或一系列端口号。

PROTOCOL将容器端口限制为指定的协议,如果为空,则将它们设置为TCP 。只有CONTAINER 部分是强制性的。

现在我们知道了语法,让我们在 Docker Compose 文件中定义端口:

services:
  myapp1:
    ...
    ports:
    - "3000"                             # container port (3000), assigned to random host port
    - "3001-3005"                        # container port range (3001-3005), assigned to random host ports
    - "8000:8000"                        # container port (8000), assigned to given host port (8000)
    - "9090-9091:8080-8081"              # container port range (8080-8081), assigned to given host port range (9090-9091)
    - "127.0.0.1:8002:8002"              # container port (8002), assigned to given host port (8002) and bind to 127.0.0.1
    - "6060:6060/udp"                    # container port (6060) restricted to UDP protocol, assigned to given host (6060)

如上所述,我们还可以一次发布多个容器端口,使用不同的短语法变体并更精确地配置它。Docker Compose 公开所有指定的容器端口,使它们可以从本地机器内部和外部访问。

和之前一样,让我们使用docker ps命令检查暴露的端口:

> docker ps -a
CONTAINER ID   ... PORTS                                                                        NAMES
e8c65b9eec91   ... 0.0.0.0:51060->3000/tcp, 0.0.0.0:51063->3001/tcp, 0.0.0.0:51064->3002/tcp,   bael_myapp1
                   0.0.0.0:51065->3003/tcp, 0.0.0.0:51061->3004/tcp, 0.0.0.0:51062->3005/tcp, 
                   0.0.0.0:8000->8000/tcp, 0.0.0.0:9090->8080/tcp, 0.0.0.0:9091->8081/tcp
                   127.0.0.1:8002->8002/tcp, 0.0.0.0:6060->6060/udp

在PORTS列中,我们可以找到所有暴露的端口。箭头左侧的值显示了我们可以从外部访问容器的主机地址。

长语法

使用长语法,我们可以以相同的方式配置端口。但是,我们不使用冒号分隔的字符串,而是单独定义每个属性:

services: 
  myapp1:
  ...
  ports:
  # - "127.0.0.1:6060:6060/udp"
  - target: 6060
    host_ip: 127.0.0.1
    published: 6060
    protocol: udp
    mode: host

在这里,target是强制性的,它指定了将要暴露的容器端口(或端口范围),相当于简写语法中的CONTAINER。

host_ip和 published是HOST中的一部分,我们可以在其中定义主机的IP 地址和端口。

protocol与缩写语法中的PROTOCOL相同,将容器端口限制为指定的协议(如果为空,则为TCP )。

mode是具有两个指定端口发布规则的值的枚举。 我们应该使用host用于在本地发布端口。第二个值是ingress, 它为更复杂的容器环境保留,意味着端口将被负载均衡。

总之,任何短语法字符串都可以很容易地用长结构表示。但是,由于缺少mode属性,所以并非所有长语法配置都可以被短语法配置代替。

总结

在这篇文章中,我们介绍了 Docker Compose 中的部分网络配置。我们使用Expose和 Ports 分析和比较了端口配置。

Expose允许我们将容器中的特定端口仅暴露给同一网络上的其他服务 。我们可以简单地通过指定容器端口来做到这一点。

而Ports还暴露了容器中的指定端口到宿主机上。与前一种不同,端口不仅对同一网络上的其他服务开放,而且对宿主机开放。配置稍微复杂一些,我们可以配置暴露的端口、本地绑定地址和受限协议。根据我们的偏好,我们可以在两种不同的语法之间进行选择。