摘要
从"你的电脑能跑,我的电脑怎么跑"出发,用Image与Container类比、Node.js服务+nginx反向代理实战,详解docker run参数与容器生命周期管理。
为什么需要 Docker?
"你的电脑能跑,我的电脑怎么跑?"这句话概括了 Docker 解决的核心问题。
你接手一个 n 年前的 Vue2 项目,要求 Node 16 + npm 8,而你电脑装的是 Node 22,项目跑不起来。依赖的版本冲突、操作系统的差异、系统库的缺失------这些是每个开发者每天都在踩的坑。
Docker 的解法很直接:把应用和运行环境打包成一个整体,像海运集装箱一样搬运到任何设备上,保证环境完全一致。
Docker 核心概念
Docker 有两个基本概念:Image(镜像) 和 Container(容器)。
Image 就像一张光盘,里面刻录了完整的应用程序和运行环境,但光盘本身不能运行------它是一个静态的只读模板。Container 就像把光盘放进 DVD 播放机,镜像被加载到运行环境中,变成一个可运行的实例。
git pull/push 管理代码版本,docker pull/push 管理镜像版本。Docker Hub 就像 GitHub 一样,是镜像的中央仓库。
搭建 Node.js HTTP 服务
先写一个最简单的 Node.js 服务,监听 1314 端口:
javascript
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.createServer 创建 HTTP 服务器,收到请求后返回 Hello World!。listen(1314, '0.0.0.0') 监听所有网络接口的 1314 端口------0.0.0.0 允许外部访问,如果只写 127.0.0.1 则只能本机访问,Docker 容器外面无法连通。
nginx 反向代理
nginx 是一个高性能的 HTTP 服务器和反向代理服务器。用户的浏览器访问 80 端口,nginx 监听 80 端口,根据配置文件把请求转发给后端服务:
nginx
events {}
http {
server {
listen 80;
location / {
proxy_pass http://host.docker.internal:1314;
proxy_set_header Host $host;
}
}
}
listen 80 监听 80 端口。location / 匹配所有请求路径。proxy_pass 是核心指令------把匹配到的请求全部转发给 http://host.docker.internal:1314 上的 Node.js 服务。
host.docker.internal 是 Docker 提供的特殊域名,指向宿主机的 IP 地址。Docker 容器和宿主机有独立的网络命名空间,容器内不能直接通过 localhost 访问宿主机服务,host.docker.internal 打通了这条通道。
docker run 命令详解
docker run 把镜像启动为容器,是 Docker 最核心的命令:
bash
docker run \
--name my-nginx-demo \
-p 80:80 \
-v /path/to/nginx.conf:/etc/nginx/nginx.conf \
-d nginx
四个参数各司其职:
--name my-nginx-demo:给容器命名,后续用名字管理容器(停止、删除、查看日志),不用记容器 ID。-p 80:80:端口映射。格式-p 宿主机端口:容器端口,把宿主机 80 端口的流量映射到容器内的 80 端口。用户在浏览器输入http://localhost:80,请求进入宿主机 80 端口,Docker 转发到容器内 80 端口,nginx 接收请求。-v /path/to/nginx.conf:/etc/nginx/nginx.conf:卷挂载。把宿主机上的配置文件映射到容器内,覆盖容器默认配置。修改配置文件不需要重新构建镜像,宿主机文件变化容器内自动生效。-d nginx:-d是 detached 模式,容器在后台运行不占用终端。nginx是镜像名,Docker 从本地或 Docker Hub 拉取 nginx 官方镜像。
nginx 反向代理 vs 正向代理
这条链路的完整请求流向:
csharp
用户浏览器 → localhost:80 → Docker 端口映射 → 容器内 nginx:80 → proxy_pass → host.docker.internal:1314 → Node.js 服务
正向代理是用户主动设置的代理。浏览器配置代理服务器,用户的请求经过代理发出。代理知道用户是谁,但目标服务器不知道------用户通过代理隐藏了真实 IP。
反向代理 是服务端配置的代理。用户访问 localhost:80,不知道背后是 nginx 在转发给 1314 端口的 Node.js 服务。nginx 隐藏了后端结构,用户只知道 80 端口有服务在响应。
nginx 做反向代理有几个实际好处:多个后端服务可以共享 80 端口(按路径转发到不同端口),后端服务可以独立重启不影响 nginx 监听,负载均衡和安全防护在 nginx 层统一处理。
容器生命周期管理
Docker 提供了一组命令管理容器和镜像:
bash
docker stop $(docker ps -q) # 停止所有运行中的容器
docker rm $(docker ps -q) # 删除所有已停止的容器
docker rmi nginx # 删除 nginx 镜像
docker ps -q 只输出容器 ID,与 stop 和 rm 组合实现批量操作。docker rmi 删除镜像释放磁盘空间。
Docker 部署 MySQL
部署数据库是 Docker 的典型场景,MySQL 8.0 只需一条命令:
bash
docker pull mysql:8.0
docker pull 从 Docker Hub 拉取指定版本的镜像。mysql:8.0 中的 8.0 是标签,精确指定版本。没有 Docker 时,安装 MySQL 需要手动下载安装包、处理依赖冲突、配置用户权限;Docker 把这一切封装在镜像中。不同项目需要不同 MySQL 版本时,Docker 可以同时运行多个版本互不干扰。
总结
Docker 的核心思想是"应用 + 运行环境 = 镜像"。从一个 Node.js 服务到 nginx 反向代理,再到 MySQL 数据库部署,Docker 通过 docker run 的 -p 端口映射、-v 卷挂载、-d 后台运行,把开发和部署的各个环节串联起来。host.docker.internal 打通容器与宿主机通信,docker ps/stop/rm 管理容器生命周期。掌握了这些基本操作,就迈出了容器化部署的第一步。