1. 开胃菜:这是啥玩意儿?(用极致白话介绍核心功能)
想象一下这个场景:
你是一家跨国海运公司的调度员 。你手下有一艘万吨巨轮(Docker) ,这艘船很特别------它可以把货物(代码) 和货物所需的存放环境(运行环境:Node版本、操作系统依赖等) 打包成一个标准集装箱(Image) 。
现在问题来了:港口(你的电脑)有无数个卸货点(端口号)。你要把某个集装箱里的货物(Node.js 应用)精准地送到某个卸货点(1314端口),并且还要在港口入口(80端口)设置一个智能分拣中心(Nginx) ,让所有进来的货物请求按照规则自动转送到正确的卸货点。
这套系统解决了什么痛点?
"我的电脑能跑,你的电脑怎么就跑不起来?"
传统开发中,你给同事发了个 Node.js 项目,同事电脑装的 Node 版本和你不一样,项目直接报错。Docker 就是那个"环境保险箱",把代码和它依赖的精确环境一起锁进集装箱,任何码头(操作系统)都能无缝运行。
而 Nginx 在这里扮演的是"高级快递分拣员",它监听 80 端口(互联网默认的入口),看到请求来了,根据配置文件规则,精准转发给内部 1314 端口的 Node.js 服务。
正向代理 vs 反向代理的通俗理解:
- 正向代理 :你找代购帮你买东西,商店不知道你是谁,只知道代购来了
- 反向代理 :你打 10086 客服热线,你不知道接电话的是哪个客服,但你的问题被解决了
在本项目中,Nginx 就是那个"10086 客服中心",用户只知道拨打了 10086(访问了 80 端口),完全不知道背后是哪个客服(哪个端口)在处理。
2. 名词解释大全(扫清学习障碍,专有名词逐一击破)
📦 Docker 容器
-
官方定义:Docker 是一个开源的应用容器引擎,让开发者可以打包应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux 或 Windows 机器上。
-
大白话翻译 :Docker 就是给你代码准备的一个标准化运输箱。箱子里不仅装了你的代码,还装了它需要的所有"生存物资"(Node 版本、系统库、配置文件)。
-
代码上下文中体现:
bash
bashdocker run --name my-nginx-demo -p 80:80 -v ./nginx.conf:/etc/nginx/nginx.conf -d nginx这一行命令就是"启动一个装满 Nginx 的集装箱 ",给它取名叫
my-nginx-demo,把集装箱的 80 号舱门和宿主机的 80 号舱门打通。 -
解决痛点:消除了"环境不一致"这个历史难题,让"在我电脑上能跑"成为历史。
🖼️ Docker Image vs Container
| 概念 | 比喻 | 代码体现 |
|---|---|---|
| Image(镜像) | 一张光盘,只读的,存储了应用和环境的"快照" | docker pull nginx 拉取的是镜像 |
| Container(容器) | 把光盘放进DVD 播放机运行起来的实例,可读可写 | docker run nginx 启动的是容器 |
关键理解 :容器不是 "在里面放东西",而是镜像本身就包含了所有东西 。容器的"可变性"体现在运行时产生的数据和通过 -v 挂载进来的外部配置。
🔄 反向代理 (Reverse Proxy)
-
官方定义:反向代理服务器位于用户与目标服务器之间,对用户而言,反向代理服务器就是目标服务器,用户无需知道真实服务器的地址。
-
大白话翻译 :你打电话给 10086 客服,客服帮你转接到具体业务部门。你只知道你是打给 10086,并不知道最后接电话的人是谁、在哪个工位。 这里的 10086 就是反向代理。
-
代码上下文中体现:
nginx
arduinolocation / { proxy_pass http://host.docker.internal:1314; }这段配置告诉 Nginx:"只要是访问根路径的请求,都偷偷转给本机的 1314 端口",用户浏览器只看到 Nginx 的 80 端口。
-
解决痛点:隐藏真实服务器、负载均衡、安全隔离、缓存加速。
🔗 端口映射 (-p 参数)
-
官方定义:将容器内部的服务端口映射到宿主机端口,使外部可以访问容器内服务。
-
大白话翻译 :容器是一个独立的"小房间",外面的世界看不到房间里的东西。端口映射就是在墙上开一扇门,门外是宿主机端口,门内是容器端口。
-
代码上下文中体现:
bash
css-p 80:80左边是本机端口,右边是容器端口。访问
http://localhost:80就相当于访问容器内部的 80 端口。
重要纠正:Docker 不是"拦截"请求,而是做"端口映射"------在宿主机和容器之间建立一条直接的网络通道,就像在一堵墙上开了一扇门。
📂 卷挂载 (-v 参数)
-
官方定义:将宿主机目录或文件挂载到容器内,实现数据持久化或配置共享。
-
大白话翻译 :容器就像一次性纸杯,用完扔掉就没了。挂载就是在纸杯底部开个洞,连到一个大水桶,纸杯扔了水还在。
-
代码上下文中体现:
bash
javascript-v D:\workspace...\nginx.conf:/etc/nginx/nginx.conf把本地的
nginx.conf文件"映射"进容器,替换默认配置。修改本地文件,容器内立即生效。
实际场景 :当你本地有多个 nginx.conf 文件时(不同项目的不同配置),可以通过 -v 挂载不同的文件到不同的容器,实现项目隔离。
🔍 正向代理 (Forward Proxy)
-
官方定义:正向代理是客户端和原始服务器之间的代理服务器,为了从原始服务器获取内容,客户端向代理发送请求并指定目标,然后代理向原始服务器转交请求。
-
大白话翻译 :你找代购帮你从国外买东西,商家只知道代购来买了,不知道是你买的。
-
与反向代理的核心区别:
- 正向代理:代理"帮客户端"去访问服务器(隐藏客户端)
- 反向代理:代理"帮服务器"接收客户端的访问(隐藏服务器)
🔥 面试补充:容器 vs 虚拟机
| 维度 | 虚拟机 | Docker 容器 |
|---|---|---|
| 资源占用 | 完整的操作系统,GB 级内存 | 共享宿主机内核,MB 级内存 |
| 启动速度 | 分钟级 | 秒级 |
| 隔离级别 | 硬件虚拟化,强隔离 | 进程级隔离,轻量 |
| 本质 | Hypervisor + Guest OS + App | Docker Engine + App(直接跑在宿主机内核上) |
3. 核心流程图解
步骤详解
步骤 1:用户发起请求
用户在浏览器输入 http://localhost(浏览器自动补全 80 端口),按下回车。
步骤 2:宿主机端口监听
你的 Windows/Mac/Linux 系统在 80 端口上有一个"门卫",因为 Docker 启动时做了 -p 80:80 映射,这个门卫知道要把请求转给 Docker 容器。
步骤 3:Docker 网络桥接
Docker 创建一个虚拟网络,把宿主机 80 端口的流量"桥接"到容器内部的 80 端口。这里你可能会有疑问:Docker 怎么做到的?它利用了 Linux 的 iptables 网络地址转换(NAT)技术,Windows/Mac 上则通过 Hyper-V 或虚拟化网络实现。
步骤 4:Nginx 接收请求
Nginx 容器内的 80 端口正在监听(这是 Nginx 的默认行为),收到请求后,进入 HTTP 请求处理阶段。
步骤 5:配置文件路由匹配
Nginx 读取 /etc/nginx/nginx.conf,找到 location / 块。注意这里的关键是 proxy_pass 指令------它告诉 Nginx:"不要自己处理这个请求,把它代理给另一个地址"。
步骤 6:反向代理转发
http://host.docker.internal:1314 这个地址特殊在哪?
host.docker.internal是 Docker 提供的一个特殊域名,指向宿主机本身。- 因为 Node.js 应用运行在宿主机上(不是容器内),Nginx 需要通过这个域名"跳出容器"访问宿主机的 1314 端口。
步骤 7:Node.js 处理请求
Node.js 的 http.createServer 创建了一个 HTTP 服务器,监听 0.0.0.0:1314。0.0.0.0 表示监听所有网络接口,所以不管是 localhost 还是 host.docker.internal 发来的请求都能收到。
步骤 8:返回响应
Node.js 回调函数执行 res.end('<h1>Hello World</h1>'),构建 HTTP 响应报文,包含状态码 200、Content-Type 头、HTML 内容。
步骤 9-10:响应原路返回
响应沿着来时的路反向传递:Node.js → Nginx → Docker → 宿主机 → 浏览器,最终用户看到 "Hello World"。
🔥 正向代理 vs 反向代理流程图解

4. 重难点深度剖析(核心中的核心)
🔥 难点一:Nginx 反向代理的 proxy_pass 原理
为什么要有这个设计?
想象一下,你的 Node.js 应用直接暴露在 80 端口:
- 安全问题:恶意流量直接攻击你的应用服务器
- 扩展问题:要启动多个 Node 实例做负载均衡怎么办?
- 维护问题:Node 服务重启时,用户会看到连接错误
Nginx 反向代理就像一个保安+前台,所有请求先经过它,它再决定转发给谁。这样 Node 应用可以"藏"在内网,对外只暴露 Nginx。
底层实现机制
当 Nginx 执行 proxy_pass 时,它做了这些事情:
text
perl
1. 解析 proxy_pass 中的 URL → 获取目标 IP 和端口
2. 创建一个新的 socket 连接到目标服务器(TCP 三次握手)
3. 接收客户端的 HTTP 请求,解析请求头
4. 根据 proxy_set_header 指令修改请求头(如 Host)
5. 将修改后的请求通过新 socket 转发给目标服务器
6. 等待目标服务器响应
7. 将响应原样返回给客户端
8. 关闭或复用连接(keepalive)
代码逐行注释
nginx
ini
# 这是一个 Nginx 配置文件,控制着"分拣中心"的运作规则
events {}
# events 块:配置 Nginx 的 网络连接处理机制
# 虽然是空的,但 Nginx 要求必须有这个块
# 内部可以配置 worker_connections(每个 worker 进程最大连接数)等
http {
# http 块:所有 HTTP 相关配置的"大本营"
# 可以包含多个 server 块,类似"多个分拣中心"
server {
# server 块:定义一个虚拟主机/站点
# 就像分拣中心里的一个"专用通道"
listen 80;
# listen 指令:告诉 Nginx 在 80 端口"站岗"
# 相当于"我在 80 号门口等着,有请求我就接"
# 底层:Nginx 会创建一个 TCP socket,绑定到 80 端口
location / {
# location 块:URL 路由规则
# / 表示匹配所有路径(根路径及其子路径)
# 就像"所有从正门进来的快递,都走这条传送带"
proxy_pass http://host.docker.internal:1314;
# proxy_pass:反向代理的核心指令
# 意思:把请求"偷偷"转给这个地址
# http://host.docker.internal:1314 是目标服务器
proxy_set_header Host $host;
# proxy_set_header:修改转发时的请求头
# Host $host 保持原始域名不变
# 如果后端服务器需要知道原始域名(比如虚拟主机),这个很重要
# $host 是 Nginx 内置变量,值为请求中的 Host 头
}
}
}
🔥 难点二:Docker 容器网络与 host.docker.internal
为什么会有这个特殊域名?
Docker 容器默认运行在隔离的网络命名空间中。你可以理解为:容器有自己的"小网络世界",它看到的 localhost(127.0.0.1)是它自己,不是宿主机。
如果你的 Node.js 应用运行在宿主机上(而不是容器里),容器内的 Nginx 需要访问宿主机的 1314 端口,但 localhost 指向容器自己,127.0.0.1 也指向容器自己,那怎么访问宿主机呢?
Docker 的解决方案:
- Linux :使用
172.17.0.1(默认网桥网关)访问宿主机 - Mac/Windows :使用
host.docker.internal特殊 DNS 记录
代码注释
javascript
javascript
// node 早期的 commonjs 规范
// 这是 Node.js 应用入口文件 index.js
const http = require('http');
// require:Node.js 的模块加载机制
// http 是 Node.js 内置模块,不需要 npm install
// 底层:Node.js 会从核心模块缓存中加载,或从文件系统读取
const server = http.createServer((req, res) => {
// createServer:创建一个 HTTP 服务器实例
// 参数是一个回调函数,每次有请求到达时执行
// req(请求对象):包含 URL、方法、请求头等
// res(响应对象):用于构建返回数据
res.end('<h1>Hello World</h1>');
// end():结束响应并发送数据
// 底层:Node.js 会构建 HTTP 响应报文:
// HTTP/1.1 200 OK
// Content-Type: text/plain (默认)
// Content-Length: 22
// <h1>Hello World</h1>
});
server.listen(1314, '0.0.0.0', () => {
// listen:让服务器开始监听端口
// 1314:端口号,和 Nginx proxy_pass 的目标端口一致
// '0.0.0.0':监听所有网络接口
// 重要!如果只写 '127.0.0.1',只有本机能访问
// 但 Nginx 在容器里要通过网络访问,必须用 0.0.0.0
// 回调函数:服务器启动成功时执行
console.log('Server is running on port 1314');
});
🔥 难点三:端口映射与通信链路
完整的网络通信链路
text
scss
用户浏览器
↓ (HTTP 请求)
宿主机 80 端口 (Windows/Mac/Linux 网络栈)
↓ (iptables / 虚拟网络桥接)
Docker 虚拟网桥 (docker0 / hyper-v 虚拟交换机)
↓ (容器网络命名空间)
Nginx 容器 80 端口
↓ (Nginx 内部处理 + proxy_pass)
Nginx 发起新 TCP 连接到 host.docker.internal:1314
↓ (通过网络地址转换 NAT)
宿主机 1314 端口
↓ (Node.js 的 TCP 服务器)
Node.js 应用处理请求
为什么需要 -p 80:80?
Docker 容器有自己独立的网络栈,默认情况下,容器内的 80 端口完全对外不可见 。-p 参数在宿主机和容器之间建立了一个"管道":
- 原理:Docker 在宿主机上创建一个代理进程,监听宿主机 80 端口
- 所有发往宿主机 80 端口的数据包,通过 iptables NAT 规则重定向到容器的 80 端口
- 这相当于在宿主机和容器之间架了一座"网络桥"
为什么需要 -v 挂载配置文件?
Nginx 镜像内部默认有一个 /etc/nginx/nginx.conf。如果直接用默认配置,它只会提供一个欢迎页面。我们想要自定义反向代理规则,有两种方式:
- 方式一:进入容器修改(不推荐,容器重启配置丢失)
- 方式二 :使用
-v挂载本地配置文件(推荐,方便调试)
-v 挂载本质上是一个文件系统层面的映射 ,容器内读取 /etc/nginx/nginx.conf 时,实际读取的是你本机的文件。
🔥 难点四:多配置文件管理与项目隔离(实战补充)
场景:本地有多个项目的 nginx.conf 怎么办?
这是非常实际的问题!在工作中,你可能同时开发多个项目,每个项目都需要独立的 Nginx 配置。
解决方案:
方案一:按项目隔离(最常用)
bash
javascript
# 项目A
docker run -v ~/project-a/nginx.conf:/etc/nginx/nginx.conf --name nginx-a -p 8080:80 -d nginx
# 项目B
docker run -v ~/project-b/nginx.conf:/etc/nginx/nginx.conf --name nginx-b -p 8081:80 -d nginx
每个项目有自己的 Nginx 容器,通过不同端口区分,互不干扰。
方案二:使用 include 语法(企业级)
nginx
ini
# 主配置文件 nginx.conf
http {
include /etc/nginx/conf.d/*.conf; # 加载所有 .conf 文件
}
# /etc/nginx/conf.d/project-a.conf
server {
listen 80;
server_name project-a.local;
location / {
proxy_pass http://project-a:3000;
}
}
# /etc/nginx/conf.d/project-b.conf
server {
listen 80;
server_name project-b.local;
location / {
proxy_pass http://project-b:3000;
}
}
通过域名区分不同项目,一个 Nginx 容器服务多个项目。
方案三:Docker Compose 统一管理
yaml
bash
# docker-compose.yml
services:
nginx:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./conf.d:/etc/nginx/conf.d # 整个目录挂载
ports:
- "80:80"
5. 避坑指南:新手的十面埋伏
🚨 坑点一:监听地址只写 localhost 或 127.0.0.1
❌ 错误示范
javascript
javascript
// 错误!监听 127.0.0.1
server.listen(1314, '127.0.0.1', () => {
console.log('Server running');
});
✅ 正确姿势
javascript
javascript
// 正确!监听 0.0.0.0 允许外部访问
server.listen(1314, '0.0.0.0', () => {
console.log('Server running');
});
💥 后果
127.0.0.1 是回环地址 ,只允许本机(宿主机)访问。Docker 容器内的 Nginx 尝试连接 host.docker.internal:1314 时,这个请求来自"外部网络"(相对 Node.js 进程而言),会被拒绝连接。
线上事故:应用部署到服务器后,Nginx 总是返回 502 Bad Gateway,排查半天才发现是监听地址写错了。这类问题在本地开发时可能不会暴露(因为你在本机浏览器直接访问 localhost:1314 能通),但一旦通过 Nginx 代理就挂了。
🚨 坑点二:Nginx 配置中的 proxy_pass 末尾斜杠问题
❌ 错误示范
nginx
bash
location /api/ {
proxy_pass http://host.docker.internal:1314; # 末尾没有斜杠
}
✅ 正确姿势
nginx
bash
location /api/ {
proxy_pass http://host.docker.internal:1314/; # 末尾有斜杠
}
💥 后果
Nginx 的 proxy_pass 中,location 和 proxy_pass 的 URL 路径组合规则非常容易搞混:
- 如果
proxy_pass末尾有斜杠/:请求/api/user→ 转发到/user(去掉 location 前缀) - 如果
proxy_pass末尾没有斜杠 :请求/api/user→ 转发到/api/user(保留完整路径)
线上事故 :API 路由全部 404,因为后端 Node 应用没有 /api 这个路由前缀。
🚨 坑点三:Docker 容器启动后修改了本地配置文件但未重启
❌ 错误操作
bash
bash
# 修改了本地 nginx.conf
# 以为会自动生效,结果配置没变
✅ 正确姿势
bash
perl
# 方式一:重启容器
docker restart my-nginx-demo
# 方式二:热加载(Nginx 支持)
docker exec -it my-nginx-demo nginx -s reload
💥 后果
虽然通过 -v 挂载了配置文件,但 Nginx 只在启动时读取配置(或者收到 reload 信号时重新读取)。修改本地文件后,Nginx 进程还在用内存中的旧配置。
线上事故:修改了负载均衡配置想切流量,改了文件以为生效了,结果流量还在往旧服务器打,引发雪崩。
🚨 坑点四:混淆正向代理和反向代理的概念
❌ 错误理解
"在正向代理用户访问哪个端口就是返回哪个端口的数据"
✅ 正确理解
核心区别不在于端口,而在于代理的方向和目的:
| 维度 | 正向代理 | 反向代理 |
|---|---|---|
| 谁在用 | 客户端(你) | 服务器端(网站运维) |
| 目的 | 访问外部资源 | 接收外部访问 |
| 类比 | 你找代购买东西,商家不知道你是谁 | 你打 10086,你不知道接电话的是哪个客服 |
| 本项目中 | 没有正向代理 | Nginx 就是反向代理 |
💥 后果
概念混淆会导致架构设计错误。如果把反向代理当成正向代理来配置,可能出现:
- 代理服务器无法正确转发请求
- 负载均衡配置错误
- 安全策略失效
6. 面试官问什么?(备战八股文)
面试题一:什么是反向代理?和正向代理有什么区别?
回答大纲
text
markdown
1. 一句话定义:
- 正向代理:客户端用代理访问外部资源(翻墙、上网行为管理)
- 反向代理:服务器端用代理接收客户端请求(负载均衡、安全隔离)
2. 核心区别(用类比):
- 正向代理:**你找代购帮你买东西**,商店不知道你是谁
- 反向代理:**你打 10086 客服热线**,你不知道接电话的是哪个客服
3. 技术层面:
- 正向代理隐藏客户端(服务器不知道谁在访问)
- 反向代理隐藏服务端(客户端不知道实际服务器在哪)
4. 本项目体现:
Nginx 作为反向代理,客户端只访问 Nginx 的 80 端口,
不知道背后 Node.js 运行在 1314 端口
面试题二:Docker 容器和虚拟机(VM)有什么区别?
回答大纲
text
markdown
1. 一句话概括:
虚拟机是"模拟一台完整电脑",容器是"隔离的一个进程"
2. 资源开销对比:
- 虚拟机:需要完整的操作系统,占用 GB 级内存
- 容器:共享宿主机内核,只占用 MB 级内存
3. 启动速度:
- 虚拟机:分钟级启动
- 容器:秒级启动
4. 隔离级别:
- 虚拟机:硬件虚拟化,隔离性强
- 容器:进程级隔离,共享宿主机内核
5. 架构本质:
- 虚拟机:Hypervisor + Guest OS + App
- 容器:Docker Engine + App(直接跑在宿主机内核上)
6. 本项目的使用场景:
我们用 Docker 运行 Nginx,是因为它轻量、快速,
而且 Nginx 本身不需要完整的操作系统
面试题三:Nginx 实现反向代理时,proxy_pass 和 proxy_set_header 的作用是什么?
回答大纲
text
markdown
1. proxy_pass 的作用:
- 指定请求转发的目标服务器地址
- 支持 HTTP/HTTPS 协议,也支持 socket
2. proxy_set_header 的作用:
- 在转发请求时,修改或添加 HTTP 请求头
- 最常见的:Host、X-Real-IP、X-Forwarded-For
3. 为什么需要修改 Host 头:
- 后端可能有多个虚拟主机(基于域名区分)
- 保持原始 Host,让后端知道用户想访问哪个站点
- 不传的话,后端看到的 Host 是 proxy_pass 的目标地址
4. 为什么需要传递真实 IP:
- X-Real-IP:传递真实客户端 IP
- X-Forwarded-For:记录代理链路
- 后端日志才能记录真实用户 IP,否则全是 Nginx 的内网 IP
5. 本项目中的配置:
proxy_set_header Host $host;
保留了用户请求的原始域名,让后端应用可以识别
面试题四:Docker 的端口映射 -p 80:80 是如何工作的?
回答大纲
text
markdown
1. 基本概念:
- 左边 80:宿主机(你电脑)的端口
- 右边 80:容器内部的端口
- 访问 localhost:80 就等于访问容器内部的 80 端口
2. 底层原理:
- Linux:通过 iptables NAT 规则实现
- 具体:docker-proxy 进程监听宿主机端口,通过 NAT 转发到容器
- Windows/Mac:通过 Hyper-V 虚拟网络实现
3. 为什么需要端口映射:
- 容器有独立的网络命名空间
- 默认外部无法访问容器内部服务
- 端口映射在宿主机和容器之间建立网络通道
4. 常见误区:
- 不是"拦截",是"映射"
- 可以映射不同端口:-p 8080:80(访问 8080 进容器 80)
7. 实战演练:从零开始复现整个项目
步骤 1:准备 Nginx 配置文件
创建 nginx.conf:
nginx
ini
events {}
http {
server {
listen 80;
location / {
proxy_pass http://host.docker.internal:1314;
proxy_set_header Host $host;
}
}
}
步骤 2:编写 Node.js 应用
创建 index.js:
javascript
javascript
const http = require('http');
const server = http.createServer((req, res) => {
res.end('<h1>Hello World</h1>');
});
server.listen(1314, '0.0.0.0', () => {
console.log('Server is running on port 1314');
});
步骤 3:启动 Node.js 应用
bash
vbscript
node index.js
# 输出:Server is running on port 1314
步骤 4:启动 Nginx 容器
bash
bash
docker run --name my-nginx-demo \
-p 80:80 \
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf \
-d nginx
步骤 5:测试访问
打开浏览器访问 http://localhost,看到 "Hello World" 即成功!
步骤 6:验证反向代理
bash
perl
# 查看 Nginx 日志,确认请求被代理
docker logs my-nginx-demo
# 查看 Docker 端口映射
docker port my-nginx-demo
# 输出:80/tcp -> 0.0.0.0:80
总结:从零到一,你已打通任督二脉
让我们回顾一下今天走完的旅程:
- 开胃菜:理解了 Docker 是"巨轮 + 集装箱",Nginx 是"智能分拣中心"
- 术语扫盲:掌握了 Image、Container、反向代理、端口映射、卷挂载、正向代理
- 流程图:看清了从浏览器输入到 Hello World 的完整链路
- 源码剖析:拆解了 Nginx 配置和 Node.js 代码的每一行
- 避坑指南:躲开了四个"新手必踩"的陷阱
- 面试准备:拿下了四道大厂高频题
- 实战演练:亲手复现了整个项目
核心知识点速查表:
| 概念 | 一句话记忆 | 本项目体现 |
|---|---|---|
| Docker 镜像 | 光盘(只读模板) | nginx 镜像 |
| Docker 容器 | DVD 播放机(运行实例) | docker run nginx |
| 端口映射 | 墙上开门 | -p 80:80 |
| 卷挂载 | 纸杯连水桶 | -v ./nginx.conf:/etc/nginx/nginx.conf |
| 反向代理 | 10086 客服中心 | Nginx 转发到 Node.js |
| 正向代理 | 找代购 | 用户主动配置代理访问外网 |