Docker + Nginx + Node.js 容器化部署 —— 从零到一理解反向代理与容器化原理

0 阅读11分钟

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

    docker 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

    location / {
        proxy_pass http://host.docker.internal:1314;
    }
    

    这段配置告诉 Nginx:"只要是访问根路径的请求,都偷偷转给本机的 1314 端口",用户浏览器只看到 Nginx 的 80 端口。

  • 解决痛点:隐藏真实服务器、负载均衡、安全隔离、缓存加速。

🔗 端口映射 (-p 参数)

  • 官方定义:将容器内部的服务端口映射到宿主机端口,使外部可以访问容器内服务。

  • 大白话翻译:容器是一个独立的"小房间",外面的世界看不到房间里的东西。端口映射就是在墙上开一扇门,门外是宿主机端口,门内是容器端口。

  • 代码上下文中体现

    bash

    -p 80:80
    

    左边是本机端口,右边是容器端口。访问 http://localhost:80 就相当于访问容器内部的 80 端口。

重要纠正:Docker 不是"拦截"请求,而是做"端口映射"——在宿主机和容器之间建立一条直接的网络通道,就像在一堵墙上开了一扇门。

📂 卷挂载 (-v 参数)

  • 官方定义:将宿主机目录或文件挂载到容器内,实现数据持久化或配置共享。

  • 大白话翻译:容器就像一次性纸杯,用完扔掉就没了。挂载就是在纸杯底部开个洞,连到一个大水桶,纸杯扔了水还在。

  • 代码上下文中体现

    bash

    -v D:\workspace...\nginx.conf:/etc/nginx/nginx.conf
    

    把本地的 nginx.conf 文件"映射"进容器,替换默认配置。修改本地文件,容器内立即生效。

实际场景:当你本地有多个 nginx.conf 文件时(不同项目的不同配置),可以通过 -v 挂载不同的文件到不同的容器,实现项目隔离。

🔍 正向代理 (Forward Proxy)

  • 官方定义:正向代理是客户端和原始服务器之间的代理服务器,为了从原始服务器获取内容,客户端向代理发送请求并指定目标,然后代理向原始服务器转交请求。

  • 大白话翻译你找代购帮你从国外买东西,商家只知道代购来买了,不知道是你买的。

  • 与反向代理的核心区别

    • 正向代理:代理"帮客户端"去访问服务器(隐藏客户端)
    • 反向代理:代理"帮服务器"接收客户端的访问(隐藏服务器)

🔥 面试补充:容器 vs 虚拟机

维度虚拟机Docker 容器
资源占用完整的操作系统,GB 级内存共享宿主机内核,MB 级内存
启动速度分钟级秒级
隔离级别硬件虚拟化,强隔离进程级隔离,轻量
本质Hypervisor + Guest OS + AppDocker 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:13140.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 反向代理流程图解

image.png

4. 重难点深度剖析(核心中的核心)

🔥 难点一:Nginx 反向代理的 proxy_pass 原理

为什么要有这个设计?

想象一下,你的 Node.js 应用直接暴露在 80 端口:

  • 安全问题:恶意流量直接攻击你的应用服务器
  • 扩展问题:要启动多个 Node 实例做负载均衡怎么办?
  • 维护问题:Node 服务重启时,用户会看到连接错误

Nginx 反向代理就像一个保安+前台,所有请求先经过它,它再决定转发给谁。这样 Node 应用可以"藏"在内网,对外只暴露 Nginx。

底层实现机制

当 Nginx 执行 proxy_pass 时,它做了这些事情:

text

1. 解析 proxy_pass 中的 URL → 获取目标 IP 和端口
2. 创建一个新的 socket 连接到目标服务器(TCP 三次握手)
3. 接收客户端的 HTTP 请求,解析请求头
4. 根据 proxy_set_header 指令修改请求头(如 Host)
5. 将修改后的请求通过新 socket 转发给目标服务器
6. 等待目标服务器响应
7. 将响应原样返回给客户端
8. 关闭或复用连接(keepalive)

代码逐行注释

nginx

# 这是一个 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

// 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

用户浏览器
    ↓ (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。如果直接用默认配置,它只会提供一个欢迎页面。我们想要自定义反向代理规则,有两种方式:

  1. 方式一:进入容器修改(不推荐,容器重启配置丢失)
  2. 方式二:使用 -v 挂载本地配置文件(推荐,方便调试)

-v 挂载本质上是一个文件系统层面的映射,容器内读取 /etc/nginx/nginx.conf 时,实际读取的是你本机的文件。

🔥 难点四:多配置文件管理与项目隔离(实战补充)

场景:本地有多个项目的 nginx.conf 怎么办?

这是非常实际的问题!在工作中,你可能同时开发多个项目,每个项目都需要独立的 Nginx 配置。

解决方案:

方案一:按项目隔离(最常用)

bash

# 项目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

# 主配置文件 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

# 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

// 错误!监听 127.0.0.1
server.listen(1314, '127.0.0.1', () => {
  console.log('Server running');
});

✅ 正确姿势

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

location /api/ {
    proxy_pass http://host.docker.internal:1314;  # 末尾没有斜杠
}

✅ 正确姿势

nginx

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

# 修改了本地 nginx.conf
# 以为会自动生效,结果配置没变

✅ 正确姿势

bash

# 方式一:重启容器
docker restart my-nginx-demo

# 方式二:热加载(Nginx 支持)
docker exec -it my-nginx-demo nginx -s reload

💥 后果

虽然通过 -v 挂载了配置文件,但 Nginx 只在启动时读取配置(或者收到 reload 信号时重新读取)。修改本地文件后,Nginx 进程还在用内存中的旧配置。

线上事故:修改了负载均衡配置想切流量,改了文件以为生效了,结果流量还在往旧服务器打,引发雪崩。

🚨 坑点四:混淆正向代理和反向代理的概念

❌ 错误理解

"在正向代理用户访问哪个端口就是返回哪个端口的数据"

✅ 正确理解

核心区别不在于端口,而在于代理的方向和目的

维度正向代理反向代理
谁在用客户端(你)服务器端(网站运维)
目的访问外部资源接收外部访问
类比你找代购买东西,商家不知道你是谁你打 10086,你不知道接电话的是哪个客服
本项目中没有正向代理Nginx 就是反向代理

💥 后果

概念混淆会导致架构设计错误。如果把反向代理当成正向代理来配置,可能出现:

  • 代理服务器无法正确转发请求
  • 负载均衡配置错误
  • 安全策略失效

6. 面试官问什么?(备战八股文)

面试题一:什么是反向代理?和正向代理有什么区别?

回答大纲

text

1. 一句话定义:
   - 正向代理:客户端用代理访问外部资源(翻墙、上网行为管理)
   - 反向代理:服务器端用代理接收客户端请求(负载均衡、安全隔离)

2. 核心区别(用类比):
   - 正向代理:**你找代购帮你买东西**,商店不知道你是谁
   - 反向代理:**你打 10086 客服热线**,你不知道接电话的是哪个客服

3. 技术层面:
   - 正向代理隐藏客户端(服务器不知道谁在访问)
   - 反向代理隐藏服务端(客户端不知道实际服务器在哪)

4. 本项目体现:
   Nginx 作为反向代理,客户端只访问 Nginx 的 80 端口,
   不知道背后 Node.js 运行在 1314 端口

面试题二:Docker 容器和虚拟机(VM)有什么区别?

回答大纲

text

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

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

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

events {}
http {
    server {
        listen 80;
        location / {
            proxy_pass http://host.docker.internal:1314;
            proxy_set_header Host $host;
        }
    }
}

步骤 2:编写 Node.js 应用

创建 index.js

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

node index.js
# 输出:Server is running on port 1314

步骤 4:启动 Nginx 容器

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

# 查看 Nginx 日志,确认请求被代理
docker logs my-nginx-demo

# 查看 Docker 端口映射
docker port my-nginx-demo
# 输出:80/tcp -> 0.0.0.0:80

总结:从零到一,你已打通任督二脉

让我们回顾一下今天走完的旅程:

  1. 开胃菜:理解了 Docker 是"巨轮 + 集装箱",Nginx 是"智能分拣中心"
  2. 术语扫盲:掌握了 Image、Container、反向代理、端口映射、卷挂载、正向代理
  3. 流程图:看清了从浏览器输入到 Hello World 的完整链路
  4. 源码剖析:拆解了 Nginx 配置和 Node.js 代码的每一行
  5. 避坑指南:躲开了四个"新手必踩"的陷阱
  6. 面试准备:拿下了四道大厂高频题
  7. 实战演练:亲手复现了整个项目

核心知识点速查表

概念一句话记忆本项目体现
Docker 镜像光盘(只读模板)nginx 镜像
Docker 容器DVD 播放机(运行实例)docker run nginx
端口映射墙上开门-p 80:80
卷挂载纸杯连水桶-v ./nginx.conf:/etc/nginx/nginx.conf
反向代理10086 客服中心Nginx 转发到 Node.js
正向代理找代购用户主动配置代理访问外网