行业资讯
搞懂 Docker 镜像与网络隔离:从底层原理到 Nginx 双层代理架构
文章目录一、 Docker 镜像的本质它到底是个什么文件二、 镜像里包含了操作系统吗三、 容器内的 Nginx 与宿主机 Nginx 的关系四、 工业界实战Nginx 双层反向代理架构拆解1. 宿主机 Nginx 负责什么入口大堂经理2. 容器内 Nginx 负责什么干活的员工3. 底层关键技术Docker 如何把 127.0.0.1:8001 接到容器里的4. 为什么要这样“折腾”二次代理优势所在总结在接触 Docker 的过程中很多刚上手的开发者常常会被一系列概念绕晕Docker 镜像到底是个啥它里面装了完整的操作系统吗镜像里的 Nginx 和我宿主机上装的 Nginx 会冲突吗为什么生产环境中经常在宿主机上跑一个 Nginx又在 Docker 容器里跑一个 Nginx流量到底是怎么传过去的今天新节就从镜像本质、系统隔离机制、网络映射原理三个维度把 Docker 的核心逻辑一文彻底讲透。一、 Docker 镜像的本质它到底是个什么文件简而言之Docker 镜像Image就是一个包含了应用程序及其完整运行环境的“只读打包文件”。如果你把一个 Docker 镜像导出docker save并解压你会发现它的内部结构主要由 3 部分组成分层文件系统Layers / Tarballs按照Dockerfile的步骤一层层叠加的只读压缩包。配置文件JSON记录镜像的元数据、启动命令CMD/ENTRYPOINT和环境变量。镜像间依赖与 Hash 校验实现不同镜像间共同底座的复用比如两个镜像都依赖 Ubuntu 基础层本地只需要下载一份。关键点镜像本身是绝对只读Read-Only的。当我们运行docker run启动容器时Docker 引擎只是在镜像只读层的最上方叠加了一层极薄的“容器可写层Writable Layer”。你的改动和日志都写在这层绝不会破坏原始镜像。二、 镜像里包含了操作系统吗包含了但只包含了一半。操作系统在结构上可以拆分为内核空间Kernel Space掌控硬件、调度 CPU 和内存是操作系统的心脏。用户空间User Space包含/bin、/usr、包管理器apt/yum、C 语言基础库等外壳文件。Docker 镜像剥离了内核它打包的只是完整的“用户空间文件”。┌──────────────────────────────────────────────────────────┐ │ 容器 (Container) │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 镜像打包的用户空间 (User Space: apt, glibc, code) │ │ │ └─────────────────────────┬──────────────────────────┘ │ └────────────────────────────┼─────────────────────────────┘ ▼ (系统调用 Direct System Calls) ┌──────────────────────────────────────────────────────────┐ │ 宿主机共享内核 (Host Linux Kernel) │ └──────────────────────────────────────────────────────────┘这也解释了为什么 Docker 容器启动只需要毫秒级因为它不需要经历载入 Kernel 的开机过程直接共享并调用宿主机的内核运行进程。三、 容器内的 Nginx 与宿主机 Nginx 的关系答案是没有任何直接关系它们是两个彻底隔离的独立进程。文件隔离宿主机的/etc/nginx/和容器内的/etc/nginx/处于完全不一样的文件系统互不影响。进程隔离它们使用不同的命名空间Namespace彼此感知不到对方的存在。版本隔离宿主机可以跑 Nginx 1.18容器里可以跑 Nginx 1.25完全不会冲突。它们唯一的“连接点”只有宿主机的网络端口映射Port Mapping。关键对比宿主机 Nginx vs 容器内 Nginx 配置差异配置项宿主机 Nginx 配置容器内 Nginx 配置listen端口80和443暴露给公网80仅在容器内部或网桥中暴露server_name具体的公网域名如example.comlocalhost或_无需关注域名SSL 证书 (ssl_certificate)有配置公网 Let’s Encrypt / 阿里云证书无接收的是宿主机解密后的纯 HTTPproxy_pass目标指向宿主机映射端口[http://127.0.0.1:8001](http://127.0.0.1:8001)指向静态文件路径或容器内后端3000端口总结一句话容器内的 Nginx不需要知道自己叫什么域名也不需要关心 HTTPS 证书。它只需要安静地监听自己的80端口拿到宿主机丢进来的流量然后去读本地静态文件或者丢给同容器的后端程序即可。四、 工业界实战Nginx 双层反向代理架构拆解在实际生产环境中我们经常采用“宿主机总网关 Nginx 容器子服务 Nginx”的双层架构。当用户访问example.com时整个流量路径是如何穿透的呢[ 浏览器 / 用户 ] │ │ 1. 访问 example.com (通过 DNS 解析到宿主机公网 IP) ▼ ┌─────────────────────────────────────────────────────────────┐ │ 宿主机 (Host Machine) │ │ │ │ ┌─────────────────────────┐ │ │ │ 宿主机 Nginx 进程 │ │ │ │ (监听 80 / 443 端口) │ │ │ └────────────┬────────────┘ │ │ │ 2. 匹配 server_name 和 location │ │ │ 执行 proxy_pass http://127.0.0.1:8001; │ │ ▼ │ │ ┌─────────────────────────┐ │ │ │ 宿主机网络栈 / iptables │ │ │ │ (监听本地 8001 端口) │ │ │ └────────────┬────────────┘ │ │ │ 3. Docker nat 表规则重定向 (DNAT) │ │ │ 将流量转投至容器内网 IP:80 │ └────────────────┼────────────────────────────────────────────┘ │ ▼ (通过 docker0 虚拟网桥) ┌─────────────────────────────────────────────────────────────┐ │ Docker 容器 (Container) │ │ │ │ ┌─────────────────────────┐ │ │ │ 容器内 Nginx 进程 │ 4. 收到请求返回响应内容 │ │ │ (监听容器内 80 端口) │ ───────────────────────► │ │ └─────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘1. 宿主机 Nginx 负责什么入口大堂经理域名路由把a.com转发给容器 A127.0.0.1:8001把b.com转发给容器 B127.0.0.1:8002实现单台服务器部署多站点。SSL 卸载把公网 HTTPS 证书配置在宿主机。解密后以纯 HTTP 明文发给内部容器减轻容器负担。宿主机核心配置在宿主机的 Nginx 配置文件通常位于 /etc/nginx/conf.d/example.conf中反向代理的配置大致如下server { listen 443 ssl; server_name example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; location / { # 将流量转发给容器映射在宿主机的 8001 端口 proxy_pass http://127.0.0.1:8001; # 传递真实客户端 IP proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; } }2. 容器内 Nginx 负责什么干活的员工因为宿主机已经把域名解析和 HTTPS 解密做完了容器内的 Nginx 配置可以极度精简它不需要关心证书也不需要关心真实的域名。容器内核心配置server { # 只需监听容器内部的 80 端口 listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; # 支持前端 SPA 路由 } }3. 底层关键技术Docker 如何把127.0.0.1:8001接到容器里的你可能会问“宿主机 Nginx 把请求发给了127.0.0.1:8001容器里的 Nginx 监听的不是容器内部的80端口吗它们是怎么接通的”这里依靠的是 Docker 启动容器时的-p端口映射机制如docker run -d -p 8001:80 nginx宿主机建立端口监听Docker 引擎启动时会在宿主机上开启一个名为docker-proxy的用户态守护进程专门监听宿主机的8001端口绑定在127.0.0.1:8001或0.0.0.0:8001。Linux 内核层重定向iptables / NATDocker 会自动在宿主机的 Linux 内核中写入一条 NAT 防火墙规则iptables。当宿主机的 Nginx 连接127.0.0.1:8001时内核会自动把数据包的目标地址进行目标网络地址转换DNAT将目标改写成容器的虚拟内网 IP例如172.17.0.2:80。网桥转发docker0数据包通过 Docker 创建的虚拟网桥docker0投递进容器内部容器内的 Nginx 就顺利接收到了这个 HTTP 请求。4. 为什么要这样“折腾”二次代理优势所在直接把容器的 80 端口映射到宿主机的 80 端口不就行了吗为什么还要在宿主机上单独加一层 Nginx这种“宿主机总 Gateway 容器子服务”的架构有几个极大的优势多站点共用 80/443 端口如果你这台服务器上有 3 个域名a.com、b.com、c.com它们分别对应 3 个不同的 Docker 容器。由于公网 80 端口只有一个只能由宿主机 Nginx 统一接收然后根据域名转发给不同的容器端口如8001、8002、8003。统一管理 SSL 证书HTTPS 卸载你只需要把 HTTPS 证书配置在宿主机 Nginx 上。宿主机 Nginx 负责解密 HTTPS 流量然后用普通的 HTTP 明文传给容器内的 Nginx/应用容器内部不需要再配置繁琐的证书。动静分离与安全屏障宿主机 Nginx 可以做防火墙、限流、防御 DDoS 攻击、全局日志记录不让恶意请求直接触及内部容器。总结一句话宿主机 Nginx 收到请求后就像一个中转前台按照配置把请求重新打包发给本地的8001端口而 Docker 引擎就像内部网关通过 iptables 规则把8001端口的数据包准确送入容器的80端口中。总结搞懂了 Docker 的镜像本质和网络穿透逻辑你就会发现镜像就是一个包含了用户空间文件与启动配置的只读压缩包。容器与宿主机隔离宿主机没装某软件完全不影响容器运行。通过宿主机 Nginx做入口分发与 SSL 容器 Nginx做应用解耦与静态资源托管我们可以用极低维度的复杂度搭建起一套安全、灵活、易于扩展的现代 Web 架构。 感谢阅读想了解更多 我的博客网站 | 记录思考分享干货 我的个人主页 | 关于我、开源项目
郑州网站建设
网页设计
企业官网