当 LLM 遇上集装箱:我的 Docker 学习笔记与 AI 后端的思考(含反向代理Nginx)

方向:AI 应用开发后端 写作日期:2026-08-18

一、缘起:为什么一个想做 AI 后端的我,要先学 Docker

我给自己定的未来方向是 AI 应用开发后端 。在很多人的想象里,"AI 后端"等于调模型接口、写 prompt、搭 RAG。但真正开始做之后我发现,一个能用的 AI 应用,落到工程层面其实是一堆服务在协作:模型推理服务、向量数据库、对话缓存(Redis)、用户与业务数据(MySQL)、网关与代理......

这些服务各自有严格的环境与版本要求。Python 要 3.10,CUDA 要对应某个版本,Node 要 16,Redis 要 7。装在一个机器上,互相踩版本、互相污染环境,是我最先撞上的墙。

于是我问了自己一个问题:那些大规模生产环境里的 AI 应用,基础设施到底是怎么搭的? 顺着这个问题,我走到了 Docker 面前。

二、第一课:集装箱思维 ------ Docker 到底是什么

学习 Docker 时,最先让我"开窍"的是这个类比:

Docker 就像海运里的万吨巨轮和集装箱。

一艘万吨巨轮,可以同时运送成千上万个集装箱。每个集装箱里装着完全不同的货物------有的装着汽车,有的装着服装,有的装着水果。它们互不干扰,装进船里就能漂洋过海,到达任何一个港口,卸下来就能用。

我们的应用也是这样。过去交付一个软件,是"交一堆代码 + 一堆环境要求文档"。到部署方手里,还要现场配环境、对版本、踩坑。而 Docker 把代码和运行环境一起打包成一个标准化的容器,任何一台装了 Docker 的机器,拉下来就能跑,就像集装箱在任何港口都能吊装一样。

我用一句话把 Docker 的本质记了下来:

ini 复制代码
Agent  = LLM + Harness(tool + mcp + rag + skill + ...)
Docker = 应用 + 运行环境

这行对照是我自己的一个小心得。我在做 AI Agent 时理解了"一个 Agent 不是只有模型,而是模型加上一整套工具、上下文、技能的装载"。同样的思维模型,放在 Docker 身上就通了------一个应用不是只有代码,而是代码加上它依赖的一整套运行环境。打包这个"整体",正是容器化干的事情。

三、我踩过的坑:为什么需要"隔离"

道理是空的,坑是实的。让我真正想做这件事的,是一个身边真实的场景:

你到公司接手一个 n 年前写的 Vue2 项目,要求 Node16 + npm 8。而你的电脑装的是 Node 22,代码一跑就报错,跑不起来。

这不是罕见情况,而是后端日常。Java 有 JDK 版本之争,Python 有 2/3 之争,Node 有版本飞速迭代,更别提 C 系的依赖地狱。每一个版本差异,都是一次环境冲突;每一次环境冲突,都是一次无效加班。

容器化技术把各个依赖隔离化安装:每个项目一个容器,各装各的 Node 版本、各装各的依赖,互不打扰。你不需要在自己的机器上为了一个老项目把 Node 卸了重装------就像一辆万吨巨轮不会因为其中一个集装箱里的水果需要冷藏,就把整艘船都改造成冷库。

这个"隔离"的思想,对我后面理解 AI 后端的服务治理特别重要:模型服务、向量库、业务库,本质上是各自独立的集装箱,跑在各自的容器里,通过端口和网络互相协作。

四、核心概念:镜像与容器

理解了"集装箱"这个心智模型,Docker 里最重要的两个概念就顺了:

  • 镜像(Image) :一个打包好的、只读的模板 ,包含应用和环境。我把它类比成 git pull------从远程仓库拉一份代码。Docker 则是从镜像仓库 pull 一个镜像。
  • 容器(Container) :镜像运行起来的实例 。我把它类比成一张 DVD------镜像像母盘,可以复制出很多张,每一张运行起来就是一个独立的容器;或者说,镜像像一张光盘模板,run 一次就烧录出一个能播放的"播放器"。
bash 复制代码
# 拉取镜像(类比:git pull)
docker pull nginx

# 运行镜像,成为可运行的容器
docker run --name my-nginx-demo -d nginx

# 停掉所有容器 / 删除所有容器 / 删除镜像
docker stop $(docker ps -q)
docker rm   $(docker ps -aq)
docker rmi  <镜像名>

还有一个一开始困扰我的点:端口

我们访问网站时输入 www.juejin.cn:3000,域名后跟的 :3000 就是端口。默认的 :80 是 HTTP 的默认端口,所以访问 www.example.com 其实访问的是 www.example.com:80,只是浏览器帮我们隐藏了。

Docker 里容器是隔离的,外部访问不进来,所以要端口映射:把宿主机(我们这台机器)的一个端口,映射到容器内部的端口。比如:

bash 复制代码
docker run --name my-nginx-demo -p 80:80 -d nginx
#          ↑ 容器的名字     ↑ 本机80端口:容器80端口

-p 80:80 表示"本机的 80 端口 对应 容器内部的 80 端口"。用户浏览器输入 http://localhost:80,请求被转发映射进容器的 80。

五、动手实践:用 nginx 反向代理部署一个 Node 服务

理论讲再多,不如跑一遍。我照着笔记做了一个最简单但完整的实践:一个 Node 服务 + nginx 反向代理

先写一个最朴素的 Node 服务,监听 1314 端口,返回 "hello world":

js 复制代码
// demo/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 server run on 1314');
});

demo/conf.d/nginx.conf 里配置 nginx 反向代理,把 80 端口的请求转发给 1314 端口的 Node 服务:

nginx 复制代码
# demo/conf.d/nginx.conf
server {
    listen 80;
    location / {
        proxy_pass http://host.docker.internal:1314;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

然后启动 nginx 容器,把本机配置挂载进去:

powershell 复制代码
docker run `
 --name my-nginx-demo `
 -p 80:80 `
 -v D:\workspace\sw_ai\backend\docker\demo\conf.d:/etc/nginx/conf.d `
 -d nginx

这条命令拆开看:

参数 作用
--name my-nginx-demo 给容器起名
-p 80:80 本机 80 端口 映射 容器 80 端口
-v 本机目录:容器目录 把本机的 nginx 配置文件挂载进容器,改配置不用重新打包镜像
-d nginx 以后台方式运行 nginx 镜像

跑起来后,完整的请求链路是:

csharp 复制代码
用户浏览器(chrome)
   → localhost:80(正向代理出网)
   → docker -p 端口映射 → 容器内部 :80
   → nginx 收到 80 端口的访问
   → 按配置文件反代到 :1314(host.docker.internal 指向宿主机)
   → Node 服务返回 "hello world"

六、反身思考:反向代理到底意味着什么

这个 demo 看起来简单,但它让我想明白了一件后端的关键事:反向代理。

用户访问 localhost:80,浏览器(正向代理)帮我们出网;而 nginx 在 80 端口"替后端服务器接收请求"------用户根本不知道后端真正跑在哪个端口、哪台机器上。这个动作叫反向代理。

它的意义远不止"转发":

  1. 隐藏后端集群:真实的后端服务躲在内网,外面只看到一个 80 端口,安全得多。
  2. 高并发承接 :nginx 能扛很高的并发,把请求按规则分摊给后面多个后端实例,这就是负载均衡的雏形。
  3. 可扩展:后端想加一台、减一台机器,前端完全无感。

运维知识:服务器软件把所有在 80 端口的请求,代理给 3000(或 1314)端口。

这个"外面一个口,里面一群服务"的形态,正是所有现代后端(包括 AI 后端)的标准姿势。

七、Docker 在我 AI 后端路线图里的位置

这是这篇博客我最想讲的部分。学 Docker 不是单纯补一门运维知识,而是我发现 AI 应用后端的整个基础设施,几乎都能用这套"集装箱"思维来理解

1. 模型服务化:LLM 本身就是一个容器

生产环境里,你几乎不会在代码里直接 import 一个千亿参数模型。通常是把模型推理封装成一个独立的模型服务(比如一个跑着 vLLM / Ollama 的容器),对外暴露 HTTP 接口,业务后端去调用它。这跟上面 Node 服务 + nginx 的模型一模一样------模型服务就是一个躲在代理后面的 1314。

2. MCP / Agent 工具链:每个工具都可以容器化

我理解的 Agent 是 LLM + Harness(tool + mcp + rag + skill...)。这些 tool、MCP server,本质上是独立的服务。把它们各自容器化,就能独立升级、独立扩容、独立部署------今天升级某个工具,不影响主服务,就像船上一个集装箱的货物损坏,不影响其他集装箱。

3. RAG 基础设施:Redis + MySQL + 向量库

一个 RAG 应用背后挂着缓存(Redis)、业务数据(MySQL)、向量数据库。我在笔记里用 Docker 装 mysql 时第一次体会到:

bash 复制代码
docker exec -it mysql-demo /bin/bash   # 进入容器
mysql -uroot -p123456                   # 连上 mysql
create database blog;                    # 建库

这些"数据库服务"完全不需要在我自己的电脑上装任何东西------拉个镜像、起个容器就完事。我笔记本上干干净净,却能同时跑 MySQL、Redis、Postgres 好多个版本。这就是隔离的价值。

4. 环境一致性的终极方案

AI 领域的环境地狱比普通后端更夸张:CUDA 版本、Python 版本、推理框架(PyTorch / vLLM / llama.cpp)......每个人的机器都不一样,同一个 prompt 在不同环境可能跑出不同结果。Docker 把整个运行环境(包括 GPU 驱动依赖、CUDA 版本)锁进镜像,开发和生产的每一步都在同一个"集装箱"里,从根上消灭"在我电脑上是好的"。

八、下一步计划

学完 Docker 基础,我的路线图是这样的:

  1. 补全 Docker 实践 :用 docker-compose.yml 一次性编排 Node + Redis + MySQL + 一个模型服务,搭出"类生产"的本地 AI 后端。
  2. 写一个真正的 AI 应用后端:基于 NodeJS(我的主力后端框架)实现一个带 RAG 的服务,把模型服务、向量库、Redis 缓存都容器化跑起来。
  3. 深入 MCP 与 Agent 服务化:把自研的工具封装成 MCP server,用 Docker 部署,体验"可插拔工具链"的后端形态。
  4. 理解 GPU 容器与生产部署:研究模型服务在带 GPU 的容器里怎么跑、怎么扩容,为将来上生产做准备。

九、结语

回过头看,Docker 教给我的第一课不是某个命令,而是一种思维:把一个复杂系统拆成一堆互不干扰、又能协作的"集装箱"。

这个思维模型,恰好和我做 AI Agent 时理解的东西同构------Agent 是 LLM + Harness,Docker 是 应用 + 环境,都是"核心 + 配套装载"的整体打包。而 AI 应用后端,说到底就是把这些集装箱合理编排、让它们协作运转。

从一杯咖啡的功夫写下一个返回 hello world 的 Node 服务,到把 nginx 反代、mysql、redis 一个个容器化跑起来------路还很长,但方向越来越清晰了。

我们搬进集装箱的,不只是代码,还有未来每一个 AI 应用赖以生存的基础设施。

相关推荐
bytemaster1 小时前
SSH 连接被秒断?从握手失败到跳板机自动中转的完整排查路径
后端·架构
smallswan1 小时前
《Rust七十二变》开源了
开发语言·后端·rust·ai编程
Kismet_nvi1 小时前
Kubernetes 核心模块详细总结
云原生·容器·kubernetes
想要成为糕糕手1 小时前
🚀 NestJS 完全入门指南: Module/Controller/Service讲解 + 实战 CRUD
后端·nestjs
开心就好20251 小时前
appuploader-cli 使用教程:在 Windows 上用命令行把 IPA 上传到 App Store
后端·ios
倾颜1 小时前
Node.js 为什么会慢?从 Event Loop、CPU、内存到并发控制聊性能问题
后端
用户921080262861 小时前
AI 应用平台为什么要拆分 Java 后端和 Python AI 服务
后端
星火10241 小时前
【LangChain4j系列08】Agentic AI 多智能体协作
人工智能·后端
凤山老林2 小时前
零停机数据库演进:Spring Boot 集成 Flyway 与平滑DDL变更策略
数据库·spring boot·后端