ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Docker + Nginx 反向代理:从“我电脑能跑”到“哪里都能跑”

Docker + Nginx 反向代理:从“我电脑能跑”到“哪里都能跑” 不知道你有没有遇到过这种场景接手一个三年前的老项目文档上写着“请使用 Node 16 npm 8 启动”而你本机装的是 Node 22。跑起来报错降级又怕影响手头其他项目。这时候你心里大概率会冒出一句“我电脑能跑你电脑怎么就跑不起来”这不是玄学这是环境依赖在作祟。今天的文章就用一个最小实战带你用 Docker 和 Nginx 反向代理把“能跑”这件事从个人电脑上拆下来变成一份可以分发的配置。一、Docker 到底解决了什么问题先抛开那些厚重的概念记住一个类比Docker 应用 运行环境就像海运的集装箱你把货物应用和必要的保护措施运行环境打包进一个标准箱子然后这艘“万吨巨轮”可以把这个箱子运到任何港口。无论目的港是深圳、鹿特丹还是洛杉矶开箱即用。放到开发里也一样。一个完整的 Web 应用往往不止有代码还有Node.js 的版本npm/yarn 的版本Redis、MySQL 等中间件各种系统级依赖任何一个环节不一致都可能导致“你电脑能跑我电脑不能跑”。Docker 做的就是把这些依赖连同代码一起打成一个镜像然后在你任何设备上以容器的形式运行起来。如果你关注 AI Agent会发现一个有趣的类比Agent LLM Harnesstool mcp rag skill...Docker 应用 运行环境本质上它们都是在解决“能力 环境”的组合问题。两个必须理解的概念Image 和 ContainerImage镜像类似于一张光盘。它包含了应用程序和它需要的环境是只读的模板。Container容器类似于光盘放进 DVD 播放器后正在播放的内容。它是镜像运行起来的实例可读可写。所以你会发现Docker 的日常操作基本就是围绕这两个东西展开docker pull nginx # 拉取镜像相当于下载光盘 docker run nginx # 运行镜像相当于把光盘放进播放器 docker stop xxx # 停止容器 docker rm xxx # 删除容器 docker rmi nginx # 删除镜像先记住这两组概念后面实战中你会反复看到它们。二、实战用 Nginx 反向代理一个 Node 服务假设我们现在有一个最简单的 Node 服务// index.js const http require(http) const server http.createServer((req, res) { res.end(hello world) }) server.listen(1314, 0.0.0.0, () { console.log(node service run on 1314) })这个服务监听在1314端口注意这里监听的是0.0.0.0而不是127.0.0.1。为什么要这样后面你会看到因为 Nginx 容器需要通过宿主机访问这个服务如果只监听回环地址容器可能无法访问。现在你在本机启动它node index.js浏览器访问http://localhost:1314会看到熟悉的hello world。但问题来了用户会输入localhost:1314吗不会。用户只会输入http://localhost甚至是一个域名。而 HTTP 协议默认端口是80。也就是说用户永远只会从 80 端口进来但你的服务跑在 1314 端口。这就需要一位“前台接待员”——Nginx。为什么需要 Nginx因为在实际生产环境中你需要一个统一入口来处理请求用户访问 80 端口Nginx 监听 80 端口Nginx 根据配置把请求转发到真正运行服务的 1314 端口这就是反向代理。说白了就是用户不知道你的服务在哪个端口也不该知道Nginx 帮你挡在前面。准备 Nginx 配置文件# nginx.conf events {} http { server { listen 80; location / { proxy_pass http://host.docker.internal:1314; proxy_set_header Host $host; } } }这里有一个关键点host.docker.internal。这是 Docker Desktop 提供的一个特殊 DNS 名称它指向宿主机。因为我们的 Node 服务直接跑在宿主机上而 Nginx 跑在容器里所以 Nginx 需要通过这个地址访问宿主机的 1314 端口。用 Docker 启动 Nginxdocker run --name my-nginx-demo \ -p 80:80 \ -v /path/to/nginx.conf:/etc/nginx/nginx.conf \ -d nginx这条命令拆开来看就是 Docker 的日常操作核心--name my-nginx-demo给容器起个名字方便后续管理。-p 80:80端口映射本机的 80 端口映射到容器的 80 端口。-v /path/to/nginx.conf:/etc/nginx/nginx.conf把本机的配置文件挂载到容器内 Nginx 的默认配置路径。-d nginx后台运行nginx镜像。如果不设置会阻塞运行需要重开一个进程。现在浏览器访问http://localhost请求会先到本机 80 端口然后通过 Docker 端口映射进入 Nginx 容器再根据配置文件代理到宿主机的 1314 端口最终返回hello world。三、请求链路拆解一次请求的完整旅程这个例子虽然简单但把 Docker 和 Nginx 反向代理的核心链路全串起来了。你可以把下面这条链路在脑子里过一遍浏览器 http://localhost:80 ↓ 宿主机 80 端口 ↓ Docker 端口映射 -p 80:80 ↓ Nginx 容器内 80 端口 ↓ nginx.conf 反向代理规则 ↓ host.docker.internal:1314宿主机 Node 服务 ↓ 返回 hello world你会发现整个过程中用户完全不知道服务真正跑在 1314 端口。对于用户来说只有一个入口http://localhost。这就是反向代理和正向代理的区别正向代理代理的是客户端比如你挂了个代理去访问外网服务器不知道你是谁。反向代理代理的是服务端比如 Nginx 挡在服务前面用户不知道真正的服务在哪。反向代理的意义不只是端口转发它把“服务真正在哪里”这件事藏了起来对外只暴露一个干净的入口。四、踩坑点与解决方案在实际操作中有几个点需要特别注意不然很容易卡住。1.host.docker.internal的兼容性问题host.docker.internal是 Docker DesktopWindows/Mac自带的特性。如果你在 Linux 服务器上运行 Docker这个 DNS 名称可能不存在。解决方案是添加--add-host参数docker run --name my-nginx-demo \ -p 80:80 \ -v /path/to/nginx.conf:/etc/nginx/nginx.conf \ --add-hosthost.docker.internal:host-gateway \ -d nginxhost-gateway会让 Docker 自动解析到宿主机 IP这样 Nginx 就能访问宿主机的 Node 服务了。2. 端口映射的顺序-p 80:80里面第一个 80 是宿主机端口第二个 80 是容器端口。这个顺序别搞反了。如果你本机 80 端口已经被占用比如本机已经有 Nginx 在跑可以改成-p 8080:80然后访问http://localhost:8080。3. 挂载路径的格式在 Windows 上挂载路径可能需要写成E:\workspace...但更推荐使用绝对路径或者 Docker 的 volume。上面的示例中我用了/path/to/nginx.conf你需要替换成自己本机的实际路径。4. 容器清理如果折腾了一堆容器想快速清理环境可以用以下命令# 停止所有运行中的容器 docker stop $(docker ps -q) # 删除所有容器 docker rm $(docker ps -aq) # 删除 nginx 镜像 docker rmi nginx注意docker rm只能删除已停止的容器如果容器还在运行需要先执行docker stop或者直接用docker rm -f强制删除。五、扩展用 Docker 跑一个 MySQLDocker 的便利性在数据库这种强环境依赖的场景下体现得更加明显。比如你本机已经装了一个 MySQL 5.7但项目要求 MySQL 8.0你不可能卸载重装。这时候 Docker 就派上用场了。# 拉取 MySQL 8.0 镜像 docker pull mysql:8.0 # 运行 MySQL 容器映射到宿主机 3307 端口 docker run -d --name mysql-demo \ -p 3307:3306 \ -e MYSQL_ROOT_PASSWORD123456 \ mysql:8.0这里有两个点需要注意-p 3307:3306MySQL 默认监听 3306 端口但如果本机已有 MySQL 占用了 3306就映射到 3307避免冲突。-e MYSQL_ROOT_PASSWORD123456通过环境变量设置 MySQL 的 root 密码-e就是--env的缩写。进入容器内部可以像操作普通 Linux 一样操作docker exec -it mysql-demo /bin/bash mysql -uroot -p123456docker exec -it是进入一个正在运行的容器并打开交互式终端之后你就可以在容器内部执行命令了。-i--interactive保持输入流开启能接收键盘输入-t--tty分配虚拟终端显示命令行提示符-it几乎永远成对使用用来做交互式操作六、总结Docker 的核心就三件事回顾一下这篇文章的内容你会发现 Docker 的核心其实就是三件事打包把应用和运行环境打包成镜像。分发镜像可以轻松 pull/push任何设备都能拿到同一份环境。隔离容器之间互不影响不会因为版本冲突而崩溃。而 Nginx 反向代理则是把“用户入口”和“服务端口”解耦让你可以灵活地在后面挂任何服务。环境问题不再是玄学容器化让你把“能跑”这件事固化下来变成一份可移植的配置。下次再遇到“我电脑能跑你电脑跑不起来”的情况别急着怀疑人生先问问自己这件事是不是该交给 Docker 了
返回列表