Docker 系列 | 06 - 容器网络:实现容器间通信

引言

在之前的文章中,我们学习了 Docker 镜像、容器和数据持久化。现在,我们需要解决一个关键问题:容器之间以及容器与外部世界如何进行通信?这就是 Docker 网络所负责的任务。

Docker 提供了一套强大的网络功能,允许您配置容器的网络连接方式,以满足各种应用场景的需求。本篇文章将详细解析 Docker 的几种网络模式,并指导您如何在实践中配置和管理容器网络。

Docker 网络基础概念

Docker 引擎默认使用桥接网络(Bridge Network)来连接容器,但同时也提供了其他几种网络模式。理解这些模式对于正确部署和管理容器化应用至关重要。

1. 虚拟网桥 (Bridge)

Docker 引擎在宿主机上会创建一个名为 docker0 的虚拟网桥(默认),并为每个容器分配一个独立的 IP 地址。容器通过这个虚拟网桥与宿主机通信,并通过宿主机进行外部网络访问。

特点:

  • 默认模式docker run 不指定网络时,容器默认连接到 bridge 网络。
  • 网络隔离:不同容器之间默认可以通过 IP 地址互相访问(如果它们在同一个桥接网络中)。
  • 端口映射:为了让外部世界访问容器内部的服务,通常需要通过 -p--publish 进行端口映射。

工作原理示意图:

+——————————————————-+

| 宿主机 |

| |

| +—————————————————+ |

| | docker0 网桥 | |

| | | |

| | +———–+ +———–+ +———–+ | |

| | | 容器 A | | 容器 B | | 容器 C | |

| | | (eth0: IP1) | | (eth0: IP2) | | (eth0: IP3) | |

| | +———–+ +———–+ +———–+ | |

| +—————————————————+ |

| ^ ^ ^ |

| | | | |

| 宿主机网络接口(如 eth0/en0) |

+——————————————————-+

(请您自行根据此描述绘制一个示意图,包含宿主机、docker0 网桥、连接到网桥的多个容器及其各自的 IP 地址,以及网桥连接到宿主机网络接口。)

2. 主机网络 (Host)

主机网络模式下,容器不会有自己独立的网络栈,而是直接共享宿主机的网络栈。容器的端口直接暴露在宿主机上,无需进行端口映射。

特点:

  • 高性能:没有网络虚拟化的开销,性能接近直接在宿主机上运行。
  • 无隔离:容器直接使用宿主机的网络,容器内服务的端口不能与宿主机上已占用的端口冲突。
  • 端口映射无效:因为容器直接共享主机网络,所以 -p 选项不再有效。

使用场景:

  • 对网络性能有极高要求的应用。
  • 当容器内服务需要直接使用宿主机上的特定网络配置时。

语法:docker run --network host ...

示例:运行 Nginx 使用主机网络

1
2
3
# 运行 Nginx 容器,直接使用宿主机网络
# 注意:此时 Nginx 监听的 80 端口会直接占用宿主机的 80 端口
docker run -d --name my-nginx-host-mode --network host nginx:latest

此时,您直接访问 http://localhost (宿主机的 IP 地址) 就能看到 Nginx 页面,无需端口映射。

3. 无网络 (None)

无网络模式下,容器拥有自己的网络栈,但没有配置任何网络接口(除了 loopback 接口)。容器之间或容器与外部都无法通信。

特点:

  • 完全隔离:容器没有任何网络连接。
  • 安全:适用于只需要本地文件操作,不需要任何网络连接的容器。

语法:docker run --network none ...

4. 容器网络 (Container)

容器网络模式下,新创建的容器会共享另一个已有容器的网络命名空间。这两个容器会共享 IP 地址、端口等网络资源。

特点:

  • 网络共享:两个容器拥有相同的 IP 地址和端口空间。
  • 共同通信:一个容器内的进程可以访问另一个容器内进程通过 localhost 暴露的服务。

使用场景:

  • 主应用容器和辅助代理/日志收集容器。

语法:docker run --network container:<name|id> ...

5. 自定义桥接网络 (User-defined Bridge Networks)

这是 Docker 网络中最推荐且最常用的模式,尤其是在多容器应用中。它允许您创建自己的桥接网络,提供比默认 docker0 网桥更好的隔离性和服务发现功能。

特点:

  • 内置 DNS 服务发现:连接到自定义网络的容器可以通过服务名称直接互相通信,无需知道对方的 IP 地址。
  • 更好的隔离:不同自定义网络中的容器相互隔离。
  • 默认互联:同一个自定义网络中的容器默认可以直接互相访问。
  • docker-compose 完美集成docker-compose 默认就会为服务创建自定义网络。

创建自定义网络:docker network create

1
2
3
4
5
# 创建一个名为 my-app-net 的自定义桥接网络
docker network create my-app-net

# 查看所有网络
docker network ls

示例:使用自定义网络运行应用和数据库

  1. 运行 MySQL 容器并连接到自定义网络

    1
    2
    3
    4
    5
    docker run -d \
    --name my-mysql-db \
    --network my-app-net \
    -e MYSQL_ROOT_PASSWORD=mysecretpassword \
    mysql:8.0
  2. 运行 Flask 应用容器并连接到同一个自定义网络

    1
    2
    3
    4
    5
    6
    # 假设你的 Flask 应用配置中,数据库地址是 'my-mysql-db'
    docker run -d \
    -p 5000:5000 \
    --name my-flask-app \
    --network my-app-net \
    my-flask-app:1.0

现在,my-flask-app 容器可以通过 my-mysql-db 这个服务名称(而不是 IP 地址)来访问 MySQL 数据库,Docker 会自动进行 DNS 解析。

端口映射 (Port Mapping)

端口映射是让宿主机或其他外部设备访问容器内部服务的方法。它将宿主机的一个端口转发到容器的某个端口。

语法:-p <host_port>:<container_port>--publish <host_port>:<container_port>

  • **<host_port>**:宿主机上暴露的端口。
  • **<container_port>**:容器内部服务监听的端口。

示例:

1
2
3
4
5
6
7
# 将容器的 80 端口映射到宿主机的 8080 端口
docker run -d -p 8080:80 --name webserver nginx:latest

# 将容器的 80 端口映射到宿主机上的随机可用端口
docker run -d -p 80 --name random-port-webserver nginx:latest
# 查看映射到的端口
docker ps -a

管理网络:常用命令

  • **docker network ls**:列出所有 Docker 网络。
  • **docker network create <name>**:创建一个自定义网络。
  • **docker network rm <name>**:删除一个网络。
  • **docker network inspect <name>**:查看网络的详细信息,包括连接到该网络的容器的 IP 地址。
  • **docker network connect <network> <container>**:将一个运行中的容器连接到指定网络。
  • **docker network disconnect <network> <container>**:将一个容器从指定网络断开。

结语

本篇文章深入探讨了 Docker 的几种网络模式,包括默认的桥接网络、主机网络、无网络、容器网络,以及最推荐的自定义桥接网络。理解并灵活运用这些网络模式,是构建复杂多容器应用的基础。端口映射也是将容器服务暴露给外部的关键。

在下一篇文章中,我们将对目前所学的 Docker 基础命令进行一个汇总和速查,帮助您更高效地记忆和使用这些命令。