Docker 简明教程

Docker - Managing Ports

从设计上讲,Docker 容器是隔离的,它们保留自己的内部端口,不允许响应外部端口。Docker 主机上的端口的此配置可以在使用 -p--publish Docker 标志创建容器时完成;然后,它允许发布端口。这种映射使在容器内运行的应用程序能够被访问,因为它们接收来自外部来源的流量。可以为一个容器启用多个端口映射,这适用于同一容器内运行各种服务的情况。

By design, Docker containers are isolated, keeping internal ports to themselves and not allowing response to the external. This configuration of the ports on the Docker host can be done while creating a container using the -p or --publish Docker flag; then, it allows the port to be published. This mapping makes applications running within the containers accessible, as they receive traffic from outside sources. Multiple port mappings can be enabled for one container, which caters to scenarios where various services are running within the same container.

此外,Docker Compose 为多个容器应用程序抽象了端口映射的复杂性。通过一个 docker-compose.yml 文件定义所有服务及其端口映射,Docker Compose 可以更轻松地创建和连接容器。这样做是为了以一种不会引起冲突的方式自动分配唯一端口,从而使应用程序中容器之间的通信毫无压力。

Additionally, Docker Compose abstracts the port-mapping complexity for multi-container applications. With a docker-compose.yml file defining all services and their port mappings, it becomes easier for Docker Compose to create and wire containers. This is done so that it automatically assigns unique ports in a way that does not cause conflicts, making communication between containers in an application stress-free.

避免冲突的能力和使通信无缝进行的能力使它能够有效地控制端口,因此成为在复杂应用程序中增强开发到部署工作流的非常有用的工具。它是管理容器化环境的一件宝贵工具。

The ability to escape from conflicts and make communication seamless enables it to control ports effectively, hence being a very resourceful tool for enhancing the workflow in development to deployment in complex applications. It is a precious tool for managing containerized environments.

在本教程中,让我们详细了解如何管理 Docker 端口。

In this chapter, let’s learn about managing Docker ports in detail.

EXPOSE vs. PUBLISH: Understanding the Differences

EXPOSE 和 PUBLISH(或 -p)都处理 Docker 中的端口,但它们是两件不同的事情 -

Both EXPOSE and PUBLISH (or -p) deal with ports in Docker, but they are two different things −

EXPOSE

EXPOSE 充当有关容器化应用程序打算用于通信的端口的文档。它是 Dockerfile 中的一条指令,让任何人构建或运行容器都知道它可以提供哪些服务。

EXPOSE acts as documentation regarding which ports a containerized application intends to use for communication. It is a directive in a Dockerfile that lets anyone building or running the container know what services it can potentially offer.

但请记住,仅 EXPOSE 不会让这些容器端口在容器外可访问;该指令本身或多或少就像针对开发人员或系统管理员的说明。

But remember that EXPOSE alone does not make those container ports accessible outside the container; the directive itself more or less acts like a note for the developers or system administrators.

PUBLISH

这是实际的端口映射。当您发布端口时,即当您在 docker run 中包含 -p 时或在 docker-compose.yml 中的 ports 部分包含 -p 时,您就是在 Docker 容器中的某个 PORT 和 Docker 主机上的 PORT 之间建立关联。而这正是使外部流量能够访问容器内运行的应用程序,即您所“意图”的 EXPOSE 生效的地方。

This is the actual port mapping. When you PUBLISH a port, that is, when you include the -p in the docker run or the ports section in the docker-compose.yml, you are making an association between some PORT in the Docker container and the PORT on the Docker host. And that is what enables external traffic to access an application running inside a container, i.e., where the "intention" that you EXPOSE is made real.

How to Expose a Port in Docker using PUBLISH?

Docker 提出了一些可行的方法,最直接、也是广为人知的方法是在运行容器时使用 -p。以下是一个示例 -

Docker proposes several ways by which it can be done, but the most straightforward and widely known is by using the -p when running a container. Below is an example −

Basic Syntax

在运行 Docker 容器时公开端口的基本语法是 -

The basic syntax for exposing a port when running a Docker container is −

$ docker run -p <host_port>:<container_port> <image_name>
  1. <host_port> − This indicates the port number on the Docker host where you want to expose the application.

  2. <container_port> − The port number in the container on which your application listens for traffic.

  3. <image_name> − The name of the Docker image you want to run.

Example: Public Web Server Port

例如,您有一个配置为在容器中的端口 80 上运行 Web 服务器的应用程序。您可以通过执行以下操作将其映射到本地机器端口 8080:

For example, you have an application configured to run a web server on port 80 in the container. You can map this to a local machine port, 8080, by doing −

$ docker run -p 8080:80 <your_web_server_image>

现在,您可以使用您最喜欢的网页浏览器打开 http://localhost:8080 并看到您的应用程序正在提供服务!

Now, you can open http://localhost:8080 with your favorite web browser and see your application being served!

Publish Multiple Ports in Docker

如果您的应用程序需要打开多个端口,您只需多次添加 -p 标志。

If your application requires multiple ports to be open, you can just add the -p flag more than once.

$ docker run -p 8080:80 -p 4433:443 <your_app_image>

这会将您的主机机器上的端口 80(用于 HTTP)和端口 443(用于 HTTPS)公开给该服务。

This exposes port 80 (for HTTP) and port 443 (for HTTPS) on your host machine to the service.

Publish Ports Using Docker Compose

对于多容器应用程序,使用 Docker Compose 维护端口映射非常简单。您在 docker-compose.yml 文件中的每个服务下,在 ports 部分中执行此操作 -

It’s pretty simple to maintain port mappings with Docker Compose for multi-container applications. You do this inside your docker-compose.yml file, under each service, in the ports section −

services:
   web:
      image: <your_web_server_image>
      ports:
      - "8080:80"
   db:
      image: <your_database_image>
      # ... other configurations

Key Considerations

  1. Port Conflicts − Ensure that a host port selected by yourself is not already being used by any other application or service within your system.

  2. Firewall − If Docker runs on a remote server, you may want to configure your firewall to enable traffic across the exposed ports.

  3. Security − Docker vulnerabilities are easily exposed - your port will be exposed, and attackers can breach the container. Consider using reverse proxies or other security measures to protect your containers.

How to Expose a Port in Dockerfile?

虽然 Dockerfile 中的 EXPOSE 指令不会发布端口,但它会提供有关容器在运行时预期的侦听端口的信息。然而,在现实中,它记录了 Docker 镜像将使用的端口,以便用户知道他们可以在容器中考虑发布哪些端口。以下是您可以在 Dockerfile 中定义它的方式 -

While the EXPOSE instruction in a Dockerfile does not publish the port, it provides information about the port that the container is expected to listen on at runtime. In reality, though, it documents the ports that’ll be used by your Docker image so that users know which ports they can consider publishing in the container. Here’s how to define it in your Dockerfile −

The EXPOSE Instruction

语法很简单 -

The syntax is simple −

EXPOSE <port> [<port>/<protocol>]
  1. <port> − Port that you wish to expose.

  2. <protocol> − optional, with a default of TCP. May be TCP or UDP.

Example: Exposing a Web Server Port

对于 Web 服务器镜像的 Dockerfile,您需要以下内容 -

In a Dockerfile for a web server image, you would have −

# ... other Dockerfile instructions
EXPOSE 80

此消息告知查看图像的任何人,内部应用程序很可能正在监听端口 80(标准 HTTP 端口)上的传入连接。

This informs anyone looking at your image that very probably the inside application is listening to an incoming connection on port 80, the standard HTTP port.

Opening up multiple ports and protocols

您可以在 Dockerfile 中拥有多个 EXPOSE

You can have more than one EXPOSE in your Dockerfile −

EXPOSE 80
EXPOSE 443/tcp
EXPOSE 443/udp

这意味着您的应用程序默认情况下使用 TCP 端口 80 和 TCP/UDP 端口 443。

This would mean your application uses TCP port 80 by default and TCP/UDP port 443.

Key Points to Note

EXPOSE 不是必需的;但记录容器的网络使用情况是一个良好做法。

EXPOSE is not necessary; however, it is good practice to document your container’s network usage.

它不会将端口发布到主机 - 在运行容器或在 docker-compose.yml 文件中定义 ports 时仍然需要使用 -p

It doesn’t publish ports to the host - doing that still requires the use of -p when running the container or defining ` ports` in your docker-compose.yml file.

当根据您的 Dockerfile 构建图像时,来自 EXPOSE 的指令会自动在图片的元数据中记下,并且您可以使用 docker inspects <image_name> 公开它。

When an image is built from your Dockerfile, an instruction from the EXPOSE automatically takes a note in the metadata of the picture, and you can expose that using docker inspects <image_name>.

Dockerfile and Running the Container

FROM nginx

EXPOSE 80

# ... any additional configuration you need

运行此容器,现在可以在主机的端口 8080 上访问 Web 服务器 −

Run this container and the web server is now accessible on port 8080 of your host −

$ docker run -p 8080:80 <your_nginx_image>

Conclusion

掌握 Docker 中的端口管理对于处理在容器中运行的应用程序的任何人来说都至关重要。了解 EXPOSE 和 PUBLISH 之间的差异,并应用开放端口的最佳做法,可确保所有容器通信都与外部世界完美。

Mastering port management in Docker is essential for any person dealing with applications running in containers. Understanding the differences between EXPOSE and PUBLISH and applying best practices for opening ports ensures all container communication is perfect with the world beyond.

无论您是开发简单的应用程序还是大规模管理多容器环境,Docker 端口管理都具有创建有效可达解决方案的灵活性和控制权。

Whether you are developing a simple application or managing multi-container environments at scale, Docker port management has the flexibility and controls to create effective reachable solutions.

在继续您的 Docker 之旅时,请始终考虑安全最佳做法。请记住,要持续更新端口映射、使用安全通信协议并考虑更多的安全层-例如反向代理。这样,您可以充分利用 Docker 的强大功能,同时通过专注于主动出击来保护应用程序和基础设施。

As you continue your Docker journey, please always consider security best practices. Remember to keep port mappings updated, use secure communication protocols, and think more security layers - for example, reverse proxies. This then lets you take full advantage of the power of Docker, all while keeping applications and infrastructure safe through your focus on being proactive.

FAQ

Q 1. What’s the difference between EXPOSE and -p(or PUBLISH) in docker?

它们都处理端口,但方式完全不同。EXPOSE 是 Dockerfile 中的一条指令,它充当一条规则语句,用于描述应用程序将利用以进行通信的端口。

They both deal with ports but in entirely different ways. EXPOSE is an instruction in a Dockerfile and acts more as a rule statement to describe ports that your application will leverage for communication.

可以把它理解为对构建或运行容器的人的一条贴心注释。另一方面, -p 或 PUBLISH 是一个实际的运行时命令,用于将 Docker 主机上的端口映射到容器中的端口,以便应用程序可以从外部访问。

Think of it as a nice note for someone building or running your container. -p or PUBLISH, on the other hand, is an actual runtime command to map a port on the Docker host to a port in the container to make your application accessible from the outside.

Q 2. Why can’t I access my application even after exposing a port?

这里可能有几个罪魁祸首。确保主机防火墙没有阻止该已公开端口上的通信。确保您没有选择其他应用程序正在使用的端口。

There could be a few culprits here. Make sure your host machine’s firewall isn’t blocking traffic over this exposed port. Ensure you didn’t select a port already being used by some other application.

如果在虚拟机或远程服务器上运行 Docker,请再次确保网络配置正确。最后,确保您指定的端口映射(主机端口到容器端口)是正确的,并且与应用程序的配置方式一致。

If you run Docker on some virtual machine or remote server, ensure once again that the network configuration is correct. Finally, make sure that the port mapping you have given (host port to container port) is correct and aligns with how your application has been configured.

Q 3. How do I expose multiple ports for a single container?

Docker 可以毫不费力地管理它。只需通过向 docker 运行命令指定多个 -p 标志来完成,每个标志都有一个不同的端口映射。使用 Docker Compose 时,必须在 docker-compose.yml 文件的端口部分中进行多个映射。

Docker manages it effortlessly. Do it simply by specifying — multiple -p flags to your docker run command, each with a different port mapping. When using Docker Compose, multiple mappings must be made in the ports section of your docker-compose.yml file.

每个映射都将提供一条独立的路径,用于将外部流量传送到容器中运行的不同服务或组件。

Each mapping will provide a separate pathway for the outside traffic toward different services or components running within your container.

Q 4. Is it safe to expose ports in Docker?

为访问应用程序而公开的每个端口都会为潜在攻击者创建越来越大的攻击面。遵守所有安全最佳实践以遏制风险。启用强身份验证,只允许来自受信任来源的访问,并可能添加更多安全层,如反向代理或防火墙。

Every port exposed for accessing your applications creates an increasing attack surface for potential attackers. Adhere to all security best practices to curb the risks. Enable strong authentication, allow access only from trusted sources, and possibly add more security layers like reverse proxies or firewalls.

监控系统,并在有常规更新程序可供修补已知漏洞时更新 Docker 映像。

Monitor the systems and update the Docker images whenever routine updates are available to patch known vulnerabilities.

Q 5. What are some common errors to avoid while managing ports in Docker?

最常见的错误是端口暴露方面的安全疏忽,使得应用程序暴露给攻击者。另一个错误是使用之前已启动的另一项服务所使用的端口;在这种情况下,会出现冲突。

The most common mistake is security negligence in port exposure, exposing applications to attackers. The other is in using ports used by another service that has been previously launched; in such a case, conflicts will arise.

对端口映射非常小心,并确保主机上的正确端口和容器内的正确端口已连接。

Be very careful with port mappings and ensure that the correct ports on the host and the correct ports inside the container are connected.

最后,别忘了记录端口映射,是通过 Dockerfile 中的 EXPOSE 还是通过项目文档,以便您或其他人将来可以轻松参考。

Finally, don’t forget to document your port mappings, whether through EXPOSE in your Dockerfile or through your project documentation, so that you or others can reference it with ease in the future.