解决
node-gyp报错、端口被占用、环境变量不对的那些破事。
本文涵盖:Node.js 服务、Nginx 反向代理、MySQL 容器化部署,一套组合拳打通本地开发环境。
一、Docker 是什么?集装箱与万吨巨轮
官方说 Docker 是一个应用容器化工具。我们不必死记硬背那些晦涩的定义,可以用一个比喻来理解:
- 传统开发:你在本地装好 Node、MySQL、Redis。这就像你在一艘船上到处堆满货物,换个船(服务器)就得重新搬一次。
- Docker 容器化:Docker 就像海运的万吨巨轮,而每个容器就是一个标准集装箱。
核心公式:
Docker = 你的应用程序 + 它所需要的运行环境(Node版本、系统库等)
Docker 解决了什么问题?
解决了“在我的电脑上能跑,怎么在你电脑上就跑不起来了? ”这个世纪难题。
一个真实场景:
你到公司接手一个 n 年前的 Vue2 项目,要求 Node16 + npm8。你的电脑装的是 Node22,跑不起来。用 Docker 容器化虚拟技术,将各个依赖隔离安装,就能完美兼容。
二、Docker 核心概念:光盘(Image)与 DVD(Container)
刚开始接触 Docker,最容易搞混的就是 Image 和 Container。
| 概念 | 比喻 | 特点 |
|---|---|---|
| 镜像 (Image) | 光盘 | 只读的。包含了应用程序和运行环境的蓝图。你可以把它 push 到远程仓库(比如 Docker Hub)。 |
| 容器 (Container) | DVD | 可运行的。是镜像的一个实例。就像把光盘放进光驱播放,容器就是把镜像加载到内存里跑起来。 |
简单来说,我们通过 docker pull 拉取镜像(光盘),通过 docker run 运行镜像,生成容器(DVD)。
三、实战一:Node.js + Nginx 反向代理
我们先做一个最经典的组合:用 Docker 启动一个 Nginx,反向代理到本地的 Node.js 服务。
1. 准备 Node.js 服务(模拟后端)
写一个最简单的 Node.js HTTP 服务,监听 1314 端口。
文件名:index.js
javascript
// 1. 引入 Node.js 原生 http 模块
const http = require('http');
// 2. 创建一个 HTTP 服务器
const server = http.createServer((req, res) => {
// 无论请求什么,都返回 Hello World
res.end('Hello Docker!');
});
// 3. 监听 1314 端口,0.0.0.0 表示监听所有网络接口
server.listen(1314, '0.0.0.0', () => {
console.log('Node server is running at http://localhost:1314/');
});
运行它:
bash
node index.js
访问 http://localhost:1314,你应该能看到 Hello Docker!。
2. 配置 Nginx(反向代理)
我们不直接访问 1314 端口(毕竟用户不会输入 :1314 来访问网站),而是通过 Nginx 监听默认的 80 端口,然后把请求转发给 Node 服务。
文件名:nginx.conf
nginx
# nginx.conf 核心配置
# 1. Events 块:配置连接数等,一般保持默认
events {}
# 2. http 块:配置 HTTP 服务
http {
# 3. server 块:配置一个虚拟主机
server {
# 监听 80 端口
listen 80;
# 4. location 块:匹配根路径 /
location / {
# **重点**:反向代理!
# 将请求转发给 host.docker.internal:1314
# 注意:在 Docker for Mac/Windows 中,host.docker.internal 指向宿主机(你的电脑)
proxy_pass http://host.docker.internal:1314;
# 设置请求头,保持客户端真实 IP 等信息
proxy_set_header Host $host;
}
}
}
为什么要用
host.docker.internal?
因为 Nginx 运行在 Docker 容器里,它不能直接访问localhost:1314(容器的 localhost 指的是它自己)。我们需要通过这个特殊的域名告诉 Nginx:“去宿主机的 1314 端口找那个 Node 服务”。
3. 使用 Docker 运行 Nginx
现在,我们要把 Nginx 跑起来,并把我们刚才写的 nginx.conf 配置文件塞进去。
bash
# 命令分解:
# docker run : 启动一个容器
# --name my-nginx : 给容器起个名字
# -p 80:80 : 端口映射。把宿主机的 80 端口映射到容器的 80 端口
# -v 配置文件路径:/etc/nginx/nginx.conf : 挂载卷。将本地的 nginx.conf 覆盖容器内的默认配置
# -d : 后台运行(detach 模式)
# nginx : 使用的镜像名称
docker run --name my-nginx-demo -p 80:80 -v C:\Users\你的用户名\Desktop\workspace\hhai\backend\docker\demo\nginx.conf:/etc/nginx/nginx.conf -d nginx
参数解析(非常重要):
-
-p 80:80:端口映射。左边的80是你的电脑(宿主机)端口,右边的80是容器内 Nginx 监听的端口。- 当你在浏览器输入
http://localhost(默认就是80端口),请求就会到达你电脑的80端口,然后 Docker 将其转发给容器的80端口。
- 当你在浏览器输入
-
-v:数据卷挂载。这相当于把本地的文件“映射”进容器里。这里我们把本地的nginx.conf挂载到容器内的/etc/nginx/nginx.conf,替换掉默认配置。
4. 验证结果
执行上面的 docker run 命令后,打开浏览器访问 http://localhost(注意,是 80 端口,可以省略)。
如果一切顺利,你会看到 Node.js 输出的 Hello Docker! 。
流量走向回顾:
text
用户浏览器访问 localhost:80 (宿主机80端口)
↓ (端口映射 -p 80:80)
Docker 容器内的 Nginx 接收到请求 (容器内80端口)
↓ (Nginx 反向代理 proxy_pass)
Nginx 转发请求到 host.docker.internal:1314
↓ (Docker 网络桥接)
你电脑本机上运行的 Node.js 服务 (localhost:1314)
↓
Node.js 返回 "Hello Docker!"
↓ (原路返回)
浏览器展示页面
四、实战二:MySQL 容器化部署(版本隔离)
前端开发中,数据库也是常见依赖。你的本地可能装了 MySQL 5.7,但项目需要 MySQL 8.0——版本不兼容,SQL 语法可能报错。用 Docker 拉取指定版本的镜像,就能和团队完全一致。
1. 拉取 MySQL 8.0 镜像
bash
# 拉取 MySQL 8.0 镜像(明确指定 tag,避免拉到 latest 版本)
docker pull mysql:8.0
2. 启动 MySQL 容器
bash
docker run -d \
--name mysql-demo \ # 容器名字
-p 3307:3306 \ # 宿主机 3307 映射到容器 3306(避免和本地已有 MySQL 冲突)
-e MYSQL_ROOT_PASSWORD=123456 \ # 设置 root 密码(生产环境请用强密码)
mysql:8.0
参数解读:
-d:后台运行。-p 3307:3306:把宿主机的3307端口映射到容器的3306。这样你就可以用localhost:3307连接容器里的 MySQL,不会和你本机已有的 MySQL(通常占 3306)冲突。-e:设置环境变量。MYSQL_ROOT_PASSWORD是 MySQL 镜像约定好的变量,用来指定 root 密码。
3. 进入容器并操作数据库
bash
# 进入容器的 bash 终端(/bin/bash 是 Linux 的 shell)
docker exec -it mysql-demo /bin/bash
# 在容器内连接 MySQL
mysql -uroot -p123456
# 创建一个测试数据库
create database blog;
退出容器可以用 exit 命令(先退出 MySQL,再退出 bash)。之后你就可以在宿主机上用任何 MySQL 客户端(如 Navicat、DBeaver、VS Code 插件)连接 localhost:3307,用 root / 123456 登录,看到刚才创建的 blog 数据库。
五、组合起来:你的全套本地开发环境
现在你有了:
| 服务 | 运行方式 | 访问地址 |
|---|---|---|
| Node.js 服务 | 宿主机直接运行(node index.js) | http://localhost:1314 |
| Nginx 容器 | Docker 运行,反向代理到 Node | http://localhost:80 |
| MySQL 容器 | Docker 运行,数据库服务 | localhost:3307(root/123456) |
三者完全隔离,互不干扰,版本完全可控。以后换新电脑,只需把 Docker 命令复制一遍,环境秒级重建,不用再折腾各种版本安装包。
六、常用 Docker 运维指令(建议收藏)
开发过程中经常需要清理环境,这里整理了几个高频命令:
bash
# 1. 查看当前正在运行的容器
docker ps
# 2. 查看所有容器(包括已停止的)
docker ps -a
# 3. 停止所有正在运行的容器
docker stop $(docker ps -q)
# 4. 删除所有已停止的容器(释放磁盘空间)
docker rm $(docker ps -aq)
# 5. 删除指定的镜像(比如删除 nginx 镜像)
docker rmi nginx
# 6. 拉取任意想要的镜像(以 Redis 为例)
docker pull redis:7.0
# 7. 进入正在运行的容器内部(调试用)
docker exec -it 容器名字 /bin/bash
七、总结
通过这次实践,我们不仅了解了 Docker 的基本概念(镜像 vs 容器),还亲手搭建了一套包含 Node.js + Nginx 反向代理 + MySQL 数据库 的完整本地开发环境。
核心要点回顾:
- Docker 容器 = 应用 + 运行环境,解决了环境不一致的问题。
- 镜像(Image) 是静态的“光盘”,容器(Container) 是动态运行的“DVD”。
- 端口映射(
-p) 是连接宿主机和容器的网络桥梁。 - 数据卷挂载(
-v) 让修改配置文件变得像修改本地文件一样简单。 - 环境变量(
-e) 可以快速配置容器内应用的运行时参数。 docker exec -it让你能进入容器内部,像操作 Linux 服务器一样调试。
希望这篇文章能帮你迈过 Docker 入门的门槛。如果你在实践过程中遇到问题,欢迎在评论区交流讨论! 😊