Expose More Than One Port With Docker – 用Docker暴露一个以上的端口

最后修改: 2021年 6月 30日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

When we dockerize our applications, we usually need to expose one port. The application uses that port to interact with other containers or the outside world. Sometimes, one port is not sufficient. One or more additional ports may be required to serve other purposes. For example, in a Spring Boot application, we need a separate port to publish management endpoints to monitor the application using the actuator.

当我们将我们的应用程序docker化时,我们通常需要暴露一个端口。应用程序使用该端口与其他容器或外部世界互动。有时,一个端口是不够的。可能需要一个或多个额外的端口来为其他目的服务。例如,在一个Spring Boot应用程序中,我们需要一个单独的端口来发布管理端点,以便使用执行器来监控应用程序。

In this article, we’ll see how to declare more than one port to expose and how to bind the exposed ports with the ports of the host computer in order to achieve the above.

在这篇文章中,我们将看到如何声明暴露一个以上的端口,以及如何将暴露的端口与主机的端口进行绑定,以实现上述目的。

2. Declaring Ports

2.申报端口

First, we need to declare the ports to be exposed. We can do that while building the docker image. It’s also possible to declare ports while running a container based on the image. Let’s see how we do that.

首先,我们需要声明要暴露的端口。我们可以在构建docker镜像时进行。也可以在运行基于镜像的容器时声明端口。让我们来看看我们如何做到这一点。

We’ll start with an example of a sample Spring Boot application – my-app. Throughout the article, we will use the same example to understand the concepts. Our application has only one GET endpoint, which returns “Hello buddy“. It also has the Spring actuator enabled. The application runs on port 8080, and the management endpoints run on port 8081. So, when the application is running on the local computer, these commands work:

我们将从一个Spring Boot应用程序的例子开始 – my-app。在整个文章中,我们将使用同一个例子来理解这些概念。我们的应用程序只有一个GET端点,它返回”Hello buddy“。它还启用了Spring执行器。该应用程序在端口8080上运行,而管理端点在端口8081上运行。因此,当应用程序在本地计算机上运行时,这些命令是有效的。

$ curl http://localhost:8080
Hello buddy

$ curl http://localhost:8081/actuator/health
{"status":"UP"}

2.1. Declaration in Dockerfile

2.1.在Dockerfile中的声明

As our application my-app publishes its endpoints in two ports, 8080 and 8081, we need to expose both ports in our Dockerfile. The EXPOSE verb in the Dockerfile exposes ports:

由于我们的应用程序my-app在两个端口发布其端点,80808081,我们需要在Dockerfile中公开这两个端口。EXPOSE动词在Dockerfile中暴露了端口

FROM openjdk:8-jdk-alpine
EXPOSE 8080
EXPOSE 8081
ARG JAR_FILE=target/my-app-0.1.jar
ADD ${JAR_FILE} my-app.jar
ENTRYPOINT ["java","-jar","/my-app.jar"]

However, when we build the image using this Dockerfile:

然而,当我们使用这个Dockerfile构建图像时。

$ docker build -t my-app:latest .

This doesn’t actually open the ports because the author of the Dockerfile has no control over the network the container will be running on. Rather, the EXPOSE command acts as documentation. With this, the person who runs a container understands which ports of the container need to be published in the host computer to communicate with the application.

这实际上并没有打开端口,因为Dockerfile的作者对容器将要运行的网络没有控制。相反,EXPOSE命令起到了文件的作用。有了这个,运行容器的人就会明白容器的哪些端口需要在主机中发布,以便与应用程序通信。

We can also specify the protocol – TCP or UDP – for communicating on this port:

我们还可以指定在此端口进行通信的协议–TCPUDP

EXPOSE 8080/tcp
EXPOSE 8081/udp

If we don’t specify anything, it takes TCP as default.

如果我们不指定任何东西,它就把TCP作为默认值。

The command also supports port declaration in a range:

该命令还支持在一个范围内声明端口。

EXPOSE 8000-8009

The above command tells that the application needs to open 10 ports starting from 8000 to 8009 for communication.

上述命令告诉我们,应用程序需要打开从80008009的10个端口进行通信。

2.2. Declaration in docker run Command

2.2.docker run命令中的声明

Let’s assume we already have a docker image for my-app that exposes only one port 8080 using the EXPOSE command in its Dockerfile. Now, if we want to expose the other port, 8081, we should use the –expose parameter along with the run command:

让我们假设我们已经有一个my-app的docker镜像,它只使用EXPOSE命令在其Dockerfile中暴露了一个端口8080。现在,如果我们想暴露另一个端口,8081,我们应该使用-expose参数和run/em>命令

$ docker run --name myapp -d --expose=8081 my-app:latest

The above command runs a container named myapp from the image my-app and exposes 8081 along with port 8080. We can check this using:

上述命令从图像my-app中运行一个名为myapp的容器,并将8081与端口8080一起暴露出来。我们可以用以下方法检查。

$ docker ps
CONTAINER ID   IMAGE           COMMAND                  CREATED             STATUS              PORTS              NAMES
2debb3c5345b   my-app:latest   "java -jar /my-app.j…"   5 seconds ago       Up 3 seconds        8080-8081/tcp      myapp

It is important to understand that this parameter only exposes – but does not publish – the ports in the host computer. To understand it more clearly, let’s execute:

重要的是要理解这个参数只暴露–但不公布–主机中的端口。为了更清楚地理解它,我们来执行。

$ docker port myapp

This doesn’t print anything because no ports have been opened and mapped in the host computer. Therefore, we’re not able to access the application even though it’s running inside the container:

这并没有打印出任何东西,因为在主机中没有打开和映射端口。因此,即使应用程序在容器中运行,我们也无法访问它。

$ curl http://localhost:8080
curl: (7) Failed to connect to localhost port 8080: Connection refused

We may also opt to expose a range of ports in the same way:

我们也可以选择以同样的方式暴露一系列的端口。

$ docker run --name myapp -d --expose=8000-8009 my-app:latest

3. Publishing Ports

3.发布端口

We’ve already learned to expose ports for a dockerized application. Now it’s time to publish them.

我们已经学会了为一个docker化的应用程序暴露端口。现在是发布它们的时候了。

3.1. Publishing in Run Command

3.1.在运行命令中发布

Let’s reuse the example of the my-app image from the previous section. It has two ports exposed in its Dockerfile8080 and 8081. While running the container based on this image, we can publish all the exposed ports at once using the -P argument:

让我们重新使用上一节中的my-app图像的例子。它的Dockerfile中有两个暴露的端口 – 80808081。在运行基于这个镜像的容器时,我们可以使用-P参数一次性发布所有暴露的端口。

$ docker run --name myapp -d -P myApp:latest

The above command opens two random ports in the host computer and maps them with ports 8080 and 8081 of the Docker container. It behaves the same way if we expose a range of ports.

上述命令在主机中打开了两个随机端口,并将它们与Docker容器的端口80808081进行映射。如果我们暴露了一系列的端口,它的表现也是一样的。

To check the mapped ports, we use:

为了检查映射的端口,我们使用。

$ docker port myapp
8080/tcp -> 0.0.0.0:32773
8081/tcp -> 0.0.0.0:32772

Now, the application is accessible using port 32773, and the management endpoints are accessible through 32772:

现在,应用程序可以使用端口32773,进行访问,管理端点可以通过32772进行访问。

$ curl http://localhost:32773
Hello buddy
$ curl http://localhost:32772/actuator/health
{"status":"UP"}

Instead of allocating random ports, we may choose specific ports in the host computer by using the -p parameter:

不分配随机端口,我们可以通过使用-p参数选择主机中的特定端口

$ docker run --name myapp -d -p 80:8080 my-app:latest

The above command publishes only port 8080 and maps with port 80 in the host server. It doesn’t make the actuator endpoints accessible from outside the container:

上述命令只发布了端口8080,并在主机服务器中用端口80进行映射。它不会使执行器端点从容器外部被访问。

$ curl http://localhost:80
Hello buddy
$ curl http://localhost:8081/actuator/health
curl: (7) Failed to connect to localhost port 8081: Connection refused

To publish multiple port mappings, we use the -p parameter multiple times:

为了发布多个端口映射,我们多次使用-p参数

$ docker run --name myapp -d -p 80:8080 -p 81:8081 my-app:latest

This way, we also keep control of which ports of the container opens up to the outside.

这样一来,我们还可以控制集装箱的哪些端口向外开放。

3.2. Publishing in docker-compose

3.2.在docker-compose中发布

If we use our application in docker-compose, we can provide a list of ports that needs to be published in the docker-compose.yml file:

如果我们在docker-compose中使用我们的应用程序,我们可以在docker-compose.yml文件中提供一个需要发布的端口列表

version: "3.7"
services:
  myapp:
    image: my-app:latest
    ports:
      - 8080
      - 8081

If we launch this setup, it assigns random ports of the host server with the given ports:

如果我们启动这个设置,它会用给定的端口随机分配主机服务器的端口。

$ docker-compose up -d
Starting my-app_myapp_1 ... done
$ docker port  my-app_myapp_1
8080/tcp -> 0.0.0.0:32785
8081/tcp -> 0.0.0.0:32784

However, it’s possible to provide the specific choice of ports:

但是,可以提供具体选择的端口。

version: "3.7"
services:
  myapp:
    image: my-app:latest
    ports:
      - 80:8080
      - 81:8081

Here, 80 and 81 are the ports of the host machine, whereas 8080 and 8081 are the container ports.

这里,8081是主机的端口,而80808081是容器端口。

4. Conclusion

4.总结

In this article, we have discussed different ways of exposing and publishing more than one port in a Docker container. We have seen what exposing actually means and also how to gain full control over the publishing of the ports between the container and the host computer.

在这篇文章中,我们讨论了在Docker容器中暴露和发布一个以上的端口的不同方法。我们已经看到了公开的实际含义,以及如何获得对容器和主机之间的端口发布的完全控制。