Docker Compose 网络实践

Docker Compose 网络[network]实践

在 Docker Compose 中,网络(networks)连接各个服务、构建复杂应用架构,正确的网络配置保证服务间的通信顺畅、清晰、安全、易维护。

本文从 Docker Compose 的默认网络行为开始,逐步深入到自定义网络、高级属性,并辨析核心概念。

1. 默认网络:default

docker-compose.yml 文件未配置任何网络时,Docker Compose 会自动处理网络问题。

# docker-compose.yml
services:
  web:
    image: nginx
  api:
    image: python

执行 docker-compose up 后,会发生两件事:

  1. 创建默认网络:Compose 会创建一个 bridge 类型的网络。其名称默认为 <项目目录名>_default
  2. 连接所有服务:该文件中的所有服务(webapi)都会被自动连接到这个网络上。

在这个网络内,服务之间可以通过它们的服务名web, api)作为主机名直接互相通信(类似于互联网域名,但仅限网络内)。

注意:默认网络的优势在于便捷,但劣势在于扁平。所有服务都在同一个广播域内,缺乏网络层面的安全隔离。

2. 自定义网络:掌控网络拓扑

当应用变得复杂时,就需要更精细的控制(隔离数据库、限制服务访问范围等),需要自定义网络。

创建自定义网络的步骤非常简单:

  1. 顶层 networks 块中定义网络。
  2. 在需要连接到该网络的容器下,通过 networks 属性指定网络名称。(若不配置,则该容器默认加入compose文件中定义的所有网络。)

示例:前后端分离与数据库隔离

假设我们有一个 Web 应用,包含前端(nginx)、后端(api)和数据库(db)。我们希望:

  • nginx 只能与 api 通信。
  • api 可以同时与 nginxdb 通信。
  • db 只能被 api 访问,且不能访问外部网络。
services:
  nginx:
    image: nginx:latest
    networks:
      - frontend # 只连接到前端网络

  api:
    image: my-api:latest
    networks:
      - frontend # 连接前端,与 nginx 通信
      - backend  # 连接后端,与 db 通信

  db:
    image: postgres:latest
    networks:
      - backend # 只连接到后端网络

networks:
  frontend:
    # 自定义网络1,用于前后端通信
  backend:
    # 自定义网络2,用于后端与数据库通信

这种配置,服务间的访问被严格限制在其所需的最小范围内,网络拓扑更安全。

3. ⭐逻辑名称 vs 物理名称:一个关键区别

配置网络时,区分“逻辑名称”和“物理名称”,避免网络无法联通。

  • 逻辑名称 (Logical Name):是 Compose 文件内部标识符,编写compose文件时使用。在 docker-compose.yml 文件中,在 networks: 顶层块和服务容器的 networks: 属性里使用的键名(Key)。

  • 物理名称 (Physical Name):是网络在 Docker 主机上实际创建的名称。它由 name 属性指定。如果未指定,Compose 会自动生成一个(例如 <项目名>_frontend)。

示例:

services:
  proxy:
    image: nginx
    networks:
      - public # <-- 使用逻辑名 'public'

networks:
  public: # <-- 这是逻辑名
    name: my-shared-proxy-net # <-- 这是物理名

核心规则:在服务容器中引用网络时,永远使用逻辑名称。

提示:网络命名规则
Docker 网络的物理名称必须符合正则表达式 [a-zA-Z0-9][a-zA-Z0-9_.-]*。简单来说,它可以用字母、数字、下划线、点号和连字符,但必须以字母或数字开头。

4. 高级网络属性:externalinternal

为了满足更复杂的场景,Docker Compose 提供了几个强大的网络属性。

4.1. external: true - 连接到外部网络

当你需要将服务连接到一个已存在的网络时(例如由其他 Compose 项目创建或手动通过 docker network create 创建的共享网络),external 属性就派上用场了。

使用场景:多个项目共享一个反向代理网络(如 proxy-net)。

  1. 首先,确保该外部网络已存在(创建网络):
    docker network create proxy-net # <-- 这是物理名
  2. docker-compose.yml 中引用它:
    services:
      app-service:
        image: my-app
        networks:
          - proxy # <-- 这是逻辑名 # 使用逻辑名 proxy
    
    networks:
      proxy:
        external: true
        name: proxy-net # <-- 这是物理名 # 指定要连接的外部网络的物理名称 proxy-net
    这样,app-service 就能加入到已存在的 proxy-net 中,与该网络内的其他服务(如反向代理)通信。

4.2. internal: true - 创建内部隔离网络

为了最大化安全,我们可以创建“内部”网络。连接到该网络的容器可以相互通信,但无法访问外部互联网

使用场景:保护数据库或敏感的后端服务,防止它们发起任何出站连接。

networks:
  database-net:
    driver: bridge
    internal: true # 关键!

任何只连接到 database-net 的容器都将与外界完全隔离,这是一种简单而高效的安全加固措施。

总结

  • 默认网络适用于快速启动和简单项目。
  • 自定义网络是构建安全、可维护应用的最佳实践,它能实现服务隔离。
  • 理解逻辑名称(在 Compose 文件中使用)和物理名称(在 Docker 主机上存在)的区别是避免配置错误的关键。
  • 使用 external: true 来接入共享或预先存在的网络。
  • 使用 internal: true 来增强安全性,阻止不必要的出站流量。

Docker Compose 网络实践
http://blog.zhens.site/docker-network/
作者
zhens
发布于
2025年7月12日
许可协议