当前位置: 首页 > news >正文

【Docker-Day 12】揭秘容器网络:深入理解 Docker Bridge 模式与端口映射

Langchain系列文章目录

01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来

Python系列文章目录

PyTorch系列文章目录

机器学习系列文章目录

深度学习系列文章目录

Java系列文章目录

JavaScript系列文章目录

Python系列文章目录

Go语言系列文章目录

Docker系列文章目录

01-【Docker-Day 1】告别部署噩梦:为什么说 Docker 是每个开发者的必备技能?
02-【Docker-Day 2】从零开始:手把手教你在 Windows、macOS 和 Linux 上安装 Docker
03-【Docker-Day 3】深入浅出:彻底搞懂 Docker 的三大核心基石——镜像、容器与仓库
04-【Docker-Day 4】从创建到删除:一文精通 Docker 容器核心操作命令
05-【Docker-Day 5】玩转 Docker 镜像:search, pull, tag, rmi 四大金刚命令详解
06-【Docker-Day 6】从零到一:精通 Dockerfile 核心指令 (FROM, WORKDIR, COPY, RUN)
07-【Docker-Day 7】揭秘 Dockerfile 启动指令:CMD、ENTRYPOINT、ENV、ARG 与 EXPOSE 详解
08-【Docker-Day 8】高手进阶:构建更小、更快、更安全的 Docker 镜像
09-【Docker-Day 9】实战终极指南:手把手教你将 Node.js 应用容器化
10-【Docker-Day 10】容器的“持久化”记忆:深入解析 Docker 数据卷 (Volume)
11-【Docker-Day 11】Docker 绑定挂载 (Bind Mount) 实战:本地代码如何与容器实时同步?
12-【Docker-Day 12】揭秘容器网络:深入理解 Docker Bridge 模式与端口映射


文章目录

  • Langchain系列文章目录
  • Python系列文章目录
  • PyTorch系列文章目录
  • 机器学习系列文章目录
  • 深度学习系列文章目录
  • Java系列文章目录
  • JavaScript系列文章目录
  • Python系列文章目录
  • Go语言系列文章目录
  • Docker系列文章目录
  • 摘要
  • 一、Docker 网络模型概览
    • 1.1 为什么需要容器网络
    • 1.2 Docker 的网络驱动
  • 二、深入理解 Bridge 网络
    • 2.1 Bridge 网络的工作原理
      • 2.1.1 默认的 `docker0` 网桥
      • 2.1.2 veth-pair:连接容器与网桥的“网线”
    • 2.2 容器间通信
      • 2.2.1 通过 IP 地址通信
      • 2.2.2 通过容器名通信
  • 三、连接外部世界:端口映射
    • 3.1 端口映射的原理
    • 3.2 两种映射方式:`-p` 与 `-P`
      • 3.2.1 `-p`:指定端口映射
      • 3.2.2 `-P`:随机端口映射
    • 3.3 `iptables` 的幕后工作
  • 四、总结


摘要

本文是《Docker 与 Kubernetes 从入门到精通》系列第 12 篇。在前面的文章中,我们已经学会了如何创建和管理容器,并实现了数据的持久化。然而,孤立的容器无法构成强大的应用,它们之间以及与外部世界的通信至关重要。本文将深入探讨 Docker 的默认网络模式——Bridge 网络,系统性地解析其工作原理、容器间通信机制以及如何通过端口映射将容器服务暴露给外部。通过本文,你将彻底理解容器是如何在隔离的环境中构建起一个“社交网络”的。

一、Docker 网络模型概览

在深入 Bridge 网络之前,我们首先需要建立一个关于 Docker 网络的宏观认识。

1.1 为什么需要容器网络

Docker 容器本质上是宿主机上的一个隔离进程。这种隔离性体现在文件系统、进程空间以及网络栈上。每个容器都拥有自己独立的网络命名空间(Network Namespace),这意味着它有自己的 IP 地址、路由表和网络接口(如 eth0)。

这种设计带来了极大的好处,比如避免了应用间的端口冲突。但同时也引出了一个核心问题:这些相互隔离的容器该如何通信?又该如何与外部世界(包括宿主机)进行交互?

为了解决这个问题,Docker 设计了一套强大的网络子系统,通过不同的网络驱动(Driver)来满足各种复杂的网络需求。

1.2 Docker 的网络驱动

Docker 提供了多种网络驱动,以支持不同的网络拓扑和应用场景。你可以通过 docker network ls 命令查看当前系统支持的网络驱动。

$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
a1b2c3d4e5f6   bridge    bridge    local
g7h8i9j0k1l2   host      host      local
m3n4o5p6q7r8   none      null      local

常见的网络驱动包括:

  • bridge (网桥模式): Docker 的默认网络驱动。它会为每个容器分配一个独立的网络命名空间,并使用一个虚拟网桥将它们连接起来。本文将重点剖析此模式。
  • host (主机模式): 容器将直接共享宿主机的网络命名空间,不进行隔离。容器的性能最高,但牺牲了隔离性,容易产生端口冲突。
  • none (无网络模式): 容器拥有自己的网络命名空间,但没有任何网络配置。它只有一个 lo (loopback) 接口,完全与外界隔离。
  • overlay (覆盖网络): 用于连接运行在不同宿主机上的容器,是实现 Docker Swarm 等集群通信的核心。
  • macvlan: 允许为容器分配一个 MAC 地址,使其在网络中显示为一台独立的物理设备。

本篇我们将聚焦于最常用、也是默认的 bridge 网络。

二、深入理解 Bridge 网络

当你启动一个容器而未指定任何 --network 参数时,它就会默认连接到名为 bridge 的网络。这个网络是在 Docker 服务启动时自动创建的。

2.1 Bridge 网络的工作原理

Bridge 网络的核心思想是在宿主机上创建一个虚拟的以太网桥(Virtual Bridge),所有连接到此网络的容器都会通过这个网桥进行通信,就像物理世界中的多台计算机连接到同一个交换机上一样。

2.1.1 默认的 docker0 网桥

当 Docker 服务启动时,它会在宿主机上创建一个名为 docker0 的虚拟网络接口。这个接口就是一个网桥,它有一个自己的 IP 地址,并充当所有连接到默认 bridge 网络的容器的网关。

我们可以使用 ip addrifconfig 命令在宿主机上查看到它:

# 在 Linux 宿主机上执行
$ ip addr show docker0
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group defaultlink/ether 02:42:ac:11:00:01 brd ff:ff:ff:ff:ff:ffinet 172.17.0.1/16 brd 172.17.255.255 scope global docker0valid_lft forever preferred_lft forever

从输出中可以看到,docker0 网桥被分配了一个 IP 地址 172.17.0.1,其子网掩码为 /16。所有连接到这个网络的容器都会从 172.17.0.0/16 这个网段中获得一个 IP 地址。

2.1.2 veth-pair:连接容器与网桥的“网线”

那么,隔离的容器是如何连接到宿主机的 docker0 网桥上的呢?答案是 veth-pair (Virtual Ethernet Pair)

veth-pair 是一对成双出现的虚拟网络设备,可以把它们想象成一根虚拟的“网线”。这根“网线”的一端插在容器的网络命名空间里(通常被命名为 eth0),另一端则插在宿主机的 docker0 网桥上。任何从一端进入的数据包都会原封不动地从另一端出来。

工作流程总结:

  1. Docker 守护进程创建 docker0 虚拟网桥。
  2. 每当启动一个容器时,Docker 会创建一个 veth-pair。
  3. veth-pair 的一端(如 veth-xxxxx)连接到 docker0 网桥。
  4. veth-pair 的另一端放入容器的网络命名空间,并被重命名为 eth0
  5. Docker 从 docker0 的 IP 地址段中为容器的 eth0 分配一个 IP 地址(如 172.17.0.2)。

这样,所有容器都连接到了同一个二层网络(docker0 网桥),它们之间可以自由通信。

2.2 容器间通信

在同一个 bridge 网络下,容器间的通信主要有两种方式。

2.2.1 通过 IP 地址通信

由于所有容器都在同一个网段,它们可以直接使用对方的 IP 地址进行通信。

实战演练:

  1. 启动两个 Nginx 容器 c1c2

    docker run -d --name c1 nginx:alpine
    docker run -d --name c2 nginx:alpine
    
  2. 获取容器 c2 的 IP 地址。

    # 使用 docker inspect 命令,并用 Go 模板过滤出 IP 地址
    docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' c2
    # 输出可能为:172.17.0.3
    
  3. 在容器 c1ping 容器 c2 的 IP。

    # 进入 c1 容器的 shell
    docker exec -it c1 sh# 在 c1 容器内执行 ping 命令(alpine 镜像默认没有 ping,需要先安装)
    # / # apk add --no-cache iputils
    # / # ping 172.17.0.3
    PING 172.17.0.3 (172.17.0.3): 56 data bytes
    64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.123 ms
    64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.089 ms
    ...
    

    可以看到,通信是成功的。

2.2.2 通过容器名通信

虽然 IP 地址通信是可行的,但在动态环境中,容器重启后 IP 地址可能会改变。更可靠的方式是使用容器名进行通信。Docker 内置了一个 DNS 服务器,可以将容器名解析为其对应的 IP 地址。

重要说明:在较旧的 Docker 版本中,默认的 bridge 网络不支持通过容器名进行 DNS 解析。你需要创建自定义的 bridge 网络。但在现代 Docker 版本中,默认的 bridge 网络也已经支持此功能

实战演练:

继续使用上面的 c1c2 容器。

  1. 在容器 c1 中直接 ping 容器 c2 的名字。

    # 进入 c1 容器的 shell
    docker exec -it c1 sh# 在 c1 容器内执行 ping 命令
    # / # ping c2
    PING c2 (172.17.0.3): 56 data bytes
    64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.115 ms
    64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.092 ms
    ...
    

    可以看到,c1 成功将 c2 这个名字解析为了它的 IP 地址 172.17.0.3。这是目前推荐的容器间通信方式。

提示:虽然默认 bridge 网络支持了 DNS 解析,但在生产环境中,我们强烈建议创建自定义的 bridge 网络来隔离不同的应用栈。自定义网络提供了更好的隔离性和网络管理能力,我们将在后续文章中详细介绍。

三、连接外部世界:端口映射

默认情况下,容器内的端口只在 docker0 这个内部网络中可见,宿主机和外部网络是无法直接访问的。为了将容器内的服务(如一个 Web 服务器)暴露出去,我们需要进行端口映射

3.1 端口映射的原理

端口映射的本质是在宿主机上设置 NAT (Network Address Translation) 规则。具体来说,Docker 通过操纵宿主机的 iptables,创建了一条 DNAT (Destination NAT) 规则。

这条规则会监听宿主机的某个端口,并将所有访问该端口的流量,其目标地址和端口都重定向到容器的私有 IP 地址和指定端口上。

3.2 两种映射方式:-p-P

docker run 命令中,我们通过 -p-P 参数来设置端口映射。

3.2.1 -p:指定端口映射

-p 参数允许你精确地指定映射关系,其格式为 -p <host_port>:<container_port>

实战演练:

  1. 启动一个 Nginx 容器,并将宿主机的 8080 端口映射到容器的 80 端口。

    docker run -d --name web_server -p 8080:80 nginx:alpine
    
  2. 查看容器运行状态和端口映射。

    $ docker ps
    CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                  NAMES
    a1b2c3d4e5f6   nginx:alpine   "/docker-entrypoint.…"   5 seconds ago    Up 4 seconds    0.0.0.0:8080->80/tcp   web_server
    

    PORTS 列清楚地显示了 0.0.0.0:8080->80/tcp,表示宿主机上所有网络接口 (0.0.0.0) 的 8080 端口的 TCP 流量,都会被转发到容器的 80 端口。

  3. 现在,你可以通过浏览器或 curl 命令访问宿主机的 8080 端口来访问 Nginx 服务。

    # 在宿主机上执行
    $ curl http://localhost:8080<!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    ...
    </html>
    

3.2.2 -P:随机端口映射

-P (大写) 参数则更加自动化。它会读取镜像中通过 EXPOSE 指令声明的所有端口,并将它们随机映射到宿主机上的一个高位端口(通常在 32768-60999 之间)。

实战演练:

官方的 Nginx 镜像的 Dockerfile 中已经包含了 EXPOSE 80

  1. 使用 -P 参数启动一个 Nginx 容器。

    docker run -d --name random_port_web -P nginx:alpine
    
  2. 查看随机映射的端口。

    $ docker ps
    CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                     NAMES
    g7h8i9j0k1l2   nginx:alpine   "/docker-entrypoint.…"   3 seconds ago    Up 2 seconds    0.0.0.0:49153->80/tcp     random_port_web
    

    可以看到,Docker 自动将容器的 80 端口映射到了宿主机的 49153 端口。

这种方式在你需要批量启动多个临时服务实例,且不关心具体端口号时非常有用。

3.3 iptables 的幕后工作

对于有兴趣深入了解的读者,可以查看 Docker 在 iptables 中创建的规则。

# 在宿主机上执行
sudo iptables -t nat -L DOCKER

你会看到类似下面的规则,这正是实现端口映射的核心。

Chain DOCKER (2 references)
target     prot opt source               destination
...
DNAT       tcp  --  anywhere             anywhere             tcp dpt:8080 to:172.17.0.4:80

这条 DNAT 规则清晰地表明:将所有目标端口为 8080 的 TCP 流量,其目标地址和端口修改为 172.17.0.4:80,从而实现了流量的转发。

四、总结

本篇文章我们详细剖析了 Docker 最基础也最重要的网络模式——Bridge 网络。现在,让我们回顾一下核心知识点:

  1. 核心组件:Bridge 网络的核心是宿主机上的一个虚拟网桥(默认为 docker0),它充当了所有连接到该网络的容器的虚拟交换机。
  2. 连接方式:每个容器通过一个 veth-pair(虚拟网线)连接到 docker0 网桥,从而获得一个独立的、位于 docker0 网段的 IP 地址。
  3. 容器间通信:在同一个 bridge 网络中的容器,可以直接通过对方的 IP 地址进行通信。在现代 Docker 版本中,也支持通过容器名进行通信,这是 Docker 内置 DNS 服务提供的便利。
  4. 外部访问:默认情况下容器是隔离的,需要通过端口映射(-p-P 参数)才能将容器内的服务暴露给宿主机和外部网络。
  5. 工作原理:端口映射的底层实现依赖于宿主机的 iptablesDNAT 规则,它将对宿主机特定端口的访问流量转发至容器的 IP 和端口。

理解了 Bridge 网络,你就掌握了 Docker 单机网络通信的基石。在下一篇文章中,我们将继续探索 hostnone 以及功能更强大的自定义 bridge 网络,为构建更复杂的应用架构打下坚实的基础。


http://www.dtcms.com/a/324109.html

相关文章:

  • Python爬虫-爬取政务网站的文档正文内容和附件数据
  • 【Linux | 网络】数据链路层
  • 电脑清理3步速成法
  • 三相LLC拓扑分析
  • CompletableFuture实现Excel sheet页导出
  • 产品经理入门 - 产品解决方案(需求分析、 功能优先级划分、功能价值、用户体验)
  • RabbitMQ面试精讲 Day 19:网络调优与连接池管理
  • NLP---IF-IDF案例分析
  • AI编程插件对比分析:CodeRider、GitHub Copilot及其他
  • 构建企业级Odoo 18 WMS——功能、架构与拓展蓝图
  • 宝塔面板部署sentinel
  • 【传奇开心果系列】基于Flet框架开发的增强版“Hello World“应用程序学习flet框架的拔高起点
  • 【后端】Java 8 特性 `User::getId` 语法(方法引用)介绍
  • Linux常用命令(后端开发版)
  • SQL(结构化查询语言)的四大核心分类
  • 【后端】Java 8 特性 Optional 可选类 介绍
  • Oracle 19C 查看卡慢的解决思路
  • Spring Boot整合knife4j实战
  • iceberg安装部署
  • imx6ull支持4G模块
  • C++高频知识点(十八)
  • 生产环境中Spring Cloud Sleuth与Zipkin分布式链路追踪实战经验分享
  • 咪咕MGV3200-KLH_GK6323V100C_板号E503744_安卓9_短接强刷包-可救砖
  • uni-app 网络请求终极选型:uni.request、axios、uni-network、alova 谁才是你的真命请求库?
  • CD64.【C++ Dev】多态(3): 反汇编剖析单继承下的虚函数表
  • CPP继承
  • Qt—— 下载、工具介绍以及新建项目
  • 机器学习 [白板推导](八)[EM算法]
  • 机器学习-----K-means算法介绍
  • 打靶日常-XSS(反射型和存储型)