Docker 入门:把应用和运行环境一起打包
容器,就像海运的万吨巨轮------把货物(应用)连同它需要的所有环境,打包成一个标准化的集装箱,运到任何港口都能直接卸货使用。
为什么需要 Docker
先看一个几乎每个开发者都遇到过的场景:
你到公司接手一个 N 年前的 Vue2 项目,要求使用 Node 16 + npm 8 。而你电脑上装的是 Node 22,直接跑,项目起不来。
代码本身没变,变的只是运行环境。一个项目除了代码,往往还依赖一堆有版本要求的运行环境:
- node
- redis
- mysql
- next / react
- ...
"我的电脑能跑,为什么你的电脑跑不起来?" 这个问题困扰了无数团队。Docker 的出现,就是为了彻底解决它------把「应用 + 运行环境」打包成一个整体,在任何设备上都能一致地部署和运行。
一句话理解 Docker
可以用两个类比快速抓住它的本质:
ini
Agent = LLM + Harness(tool + mcp + rag + skill + ...)
Docker = 应用 + 运行环境
- Agent 是把大模型和各种工具/能力打包成一个智能体;
- Docker 是把你的应用和它依赖的运行环境打包成一个容器。
两者内核一致:把「程序本身」和「程序能跑起来所需的一切」封装成一个可复用的整体。
核心概念:image 与 container
Docker 有两个最基础、也最容易混淆的概念:
| 概念 | 类比 | 说明 |
|---|---|---|
| image(镜像) | 光盘 | 只读的模板,包含应用 + 环境的完整定义 |
| container(容器) | DVD 播放器里的光盘 | image 运行起来之后的实例 |
对应到操作上:
git pull image------ 拉取一个镜像(相当于拿到一张光盘);docker run image------ 把镜像启动成一个可运行的容器(相当于把光盘放进播放器开始播放)。
一个 image 可以启动出多个互不干扰的 container,正如一张光盘可以刻录出多份拷贝,各自独立运行。
实战:Node 服务 + Nginx 反向代理
1. 一个简单的 Web 应用
先写一个最朴素的 Node 服务,监听在 1314 端口,返回一句 hello world:
js
// index.js ------ node 早期的 commonjs 规范
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');
});
本地访问 http://localhost:1314 就能看到 hello world。
2. 为什么要 Nginx
这里涉及一点运维知识:
- 用户访问网站,浏览器默认走
80端口(比如www.juejin.cn); - 而我们的 Node 服务跑在
1314端口; - 服务器软件需要把「对 80 端口的请求」代理转发给「3000/1314 这类业务端口」。
Nginx 就是干这件事的:监听 80 端口的访问,通过配置文件把请求转发到 1314 端口。它还能承担高并发、反向代理等职责。
对应的 nginx.conf:
nginx
# nginx.conf
events {}
http {
server {
listen 80;
location / {
proxy_pass http://host.docker.internal:1314;
proxy_set_header Host $host;
}
}
}
3. 启动 Nginx 容器
一条命令,把上面这套东西跑起来:
bash
docker run --name my-nginx-demo \
-p 80:80 \
-v E:\workspace\zzh_ai\backend\docker\demo\nginx.conf:/etc/nginx/nginx.conf \
-d nginx
这条命令信息量很大,逐段拆解:
| 参数 | 含义 |
|---|---|
docker run |
启动一个镜像,成为可运行的容器 |
--name my-nginx-demo |
给容器起个名字 |
-p 80:80 |
端口映射:本机 80 端口 : 容器 80 端口 |
-v 本地配置:容器配置 |
把本机 nginx.conf 挂载到容器的 /etc/nginx/nginx.conf |
-d nginx |
后台运行 nginx 镜像 |
整个链路串起来是这样:
css
用户输入 localhost(浏览器)
→ 本机 80 端口
→ docker -p 映射到容器的 80 端口
→ -v 挂载了我们的 nginx.conf 配置
→ nginx 监听 80,按配置反向代理到 :1314
→ Node 服务返回 hello world
关键点:用户只需要输入 localhost,完全不知道后端具体跑在哪个端口上。 这就是反向代理的意义------对外屏蔽了内部服务的真实端口和拓扑。
正向代理 vs 反向代理
这块是常考的运维知识点,用一张链路图就能分清:
scss
正向代理(帮客户端上网):
用户上网 intent → browser(chrome,正向代理) → 目标服务器
反向代理(帮服务器挡在客户端前面):
用户 → localhost:80 → nginx → 后端 :1314
- 正向代理 :代理的是客户端,帮用户访问外部资源(比如浏览器访问 Google);
- 反向代理 :代理的是服务器,把外部请求转发给内部服务,客户端并不知道后端在哪。
Docker 常用命令速查
bash
# 拉取任意想要的镜像
docker pull nginx
# 运行任意镜像
docker run -d nginx
# 停止所有正在运行的容器
docker stop $(docker ps -q)
# 删除所有容器
docker rm $(docker ps -aq)
# 删除镜像
docker rmi nginx
小结
Docker 解决的核心问题是环境一致性与可移植性:把「应用 + 运行环境」打包成镜像(image),运行时实例化为容器(container),再配合 Nginx 的反向代理,就能把一套服务干净利落地部署到任何设备上。
- image 是只读模板(光盘),container 是运行实例(DVD);
-p做端口映射,-v做文件挂载,-d后台运行;- Nginx 负责反向代理,把 80 端口的请求转发给内部业务端口。
掌握「镜像 / 容器 / 端口映射 / 反向代理」这四个概念,Docker 的大门就算真正推开了。