云服务器运维与项目部署
13.5 Docker容器详解
Tip
在他的电脑上能跑,在我的电脑上跑不起来 (依赖冲突/环境不同)。Docker 就是为了解决这个问题。它把代码和运行环境(OS、库、配置)打包在一起,像一个标转化的集装箱。
1. 为什么要学这个?
你用 Python 3.10 写了个应用,服务器上是 Python 2.7。 你想安装 Postgres 14,但服务器上已经跑了 Postgres 12,端口冲突。 Environment Hell (环境地狱) 让你痛不欲生。
Docker 让你可以对服务器说:“我不管你装了什么,我自带了环境。”
2. 核心概念:Container (容器)
2.1 隐喻:饭盒 vs 餐厅
- 虚拟机 (VM):是一整间餐厅。有独立的厨房、桌椅、服务员。重,启动慢,费资源。
- 容器 (Docker):是一个外卖饭盒。自带餐具和饭菜。你只需要一个桌子(Linux 内核)就能吃。轻,毫秒级启动。
2.2 核心术语
- Image (镜像): 饭菜的配方 (只读)。比如
node:18。 - Container (容器): 照着配方做出来的实物 (可读写)。你可以启动 10 个
node:18的容器。 - Dockerfile: 菜谱。告诉 Docker 怎么把代码打包成镜像。
3. 解决方案 (HOW)
3.1 Dockerfile 写法
在项目根目录新建 Dockerfile:
# 1. 选底料 (基础镜像)
FROM node:18-alpine
# 2. 设定工作目录
WORKDIR /app
# 3. 复制依赖清单并安装 (利用缓存层)
COPY package.json .
RUN npm install
# 4. 复制源码
COPY . .
# 5. 对外暴露端口
EXPOSE 3000
# 6. 启动命令
CMD ["npm", "start"]
3.2 常用命令
# 构建镜像
docker build -t my-app .
# 运行容器 (映射端口 3000->3000)
docker run -d -p 3000:3000 --name app-instance my-app
# 查看日志
docker logs -f app-instance
# 杀掉容器
docker rm -f app-instance
3.3 容器化流程图
graph TD
Code["源码 + Dockerfile"] -->|"Step 1: Build"| Image["Docker Image (镜像)"]
Image --"Step 2: Push"--> Registry["Docker Hub (仓库)"]
Registry --"Step 3: Pull"--> Server["生产服务器"]
Server --"Step 4: Run"--> Container["Running Container (容器)"]
style Image fill:#fff9c4,stroke:#fbc02d
style Container fill:#c8e6c9,stroke:#2e7d32
4. 避坑指南
| ❌ 不要这样做 | ✅ 应该这样做 | 为什么 |
|---|---|---|
| 使用 Latest | 锁定版本 | FROM node:latest 今天是 v20,明天可能就是 v21。生产环境必须锁定具体版本 node:18-alpine。 |
| 拷贝 node_modules | 在 Docker 里安装 | 也就是不要把本地的 node_modules 文件夹 COPY 进去。本地是 macOS 二进制,Docker 是 Linux,不兼容。应该让 Docker 自己 npm install。 |
| 存数据在容器里 | 挂载 Volume | 容器重启后文件就没了。数据库文件、用户上传的图片,必须挂载 Volume 到宿主机。 |
5. 真实案例
Story
2018年,消失的数据
很多新手在 Docker 里运行 MySQL 数据库。运行了一年,想升级一下 MySQL 版本。
于是执行 docker rm mysql 然后 docker run mysql:new。
启动后发现数据库是空的。所有用户数据都没了。
因为他忘记挂载数据卷 (-v /host/data:/var/lib/mysql),数据是存在容器内部的文件系统里的,随容器销毁而灰飞烟灭。
Vibe 心法:容器是易碎的“隔离间”,永远假设它下一秒就会重启。坚持无状态 (Stateless) 的设计原则,将持久化数据锚定在外部数据卷(Volume)中,才能确保应用在动态漂移的环境中获得永恒的生命力。
6. 本章小结
- 一致性:Build once, Run anywhere。
- Dockerfile:是项目的标准说明书,比 Readme 更管用。
- Volume:是数据的救生圈,千万别忘了挂载。