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 后,会发生两件事:
- 创建默认网络:Compose 会创建一个
bridge类型的网络。其名称默认为<项目目录名>_default。 - 连接所有服务:该文件中的所有服务(
web和api)都会被自动连接到这个网络上。
在这个网络内,服务之间可以通过它们的服务名(web, api)作为主机名直接互相通信(类似于互联网域名,但仅限网络内)。
注意:默认网络的优势在于便捷,但劣势在于扁平。所有服务都在同一个广播域内,缺乏网络层面的安全隔离。
2. 自定义网络:掌控网络拓扑
当应用变得复杂时,就需要更精细的控制(隔离数据库、限制服务访问范围等),需要自定义网络。
创建自定义网络的步骤非常简单:
- 顶层
networks块中定义网络。 - 在需要连接到该网络的容器下,通过
networks属性指定网络名称。(若不配置,则该容器默认加入compose文件中定义的所有网络。)
示例:前后端分离与数据库隔离
假设我们有一个 Web 应用,包含前端(nginx)、后端(api)和数据库(db)。我们希望:
nginx只能与api通信。api可以同时与nginx和db通信。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. 高级网络属性:external 与 internal
为了满足更复杂的场景,Docker Compose 提供了几个强大的网络属性。
4.1. external: true - 连接到外部网络
当你需要将服务连接到一个已存在的网络时(例如由其他 Compose 项目创建或手动通过 docker network create 创建的共享网络),external 属性就派上用场了。
使用场景:多个项目共享一个反向代理网络(如 proxy-net)。
- 首先,确保该外部网络已存在(创建网络):
docker network create proxy-net # <-- 这是物理名 - 在
docker-compose.yml中引用它: 这样,services: app-service: image: my-app networks: - proxy # <-- 这是逻辑名 # 使用逻辑名 proxy networks: proxy: external: true name: proxy-net # <-- 这是物理名 # 指定要连接的外部网络的物理名称 proxy-netapp-service就能加入到已存在的proxy-net中,与该网络内的其他服务(如反向代理)通信。
4.2. internal: true - 创建内部隔离网络
为了最大化安全,我们可以创建“内部”网络。连接到该网络的容器可以相互通信,但无法访问外部互联网。
使用场景:保护数据库或敏感的后端服务,防止它们发起任何出站连接。
networks:
database-net:
driver: bridge
internal: true # 关键!任何只连接到 database-net 的容器都将与外界完全隔离,这是一种简单而高效的安全加固措施。
总结
- 默认网络适用于快速启动和简单项目。
- 自定义网络是构建安全、可维护应用的最佳实践,它能实现服务隔离。
- 理解逻辑名称(在 Compose 文件中使用)和物理名称(在 Docker 主机上存在)的区别是避免配置错误的关键。
- 使用
external: true来接入共享或预先存在的网络。 - 使用
internal: true来增强安全性,阻止不必要的出站流量。