一、血的教训:容器删了,用户头像全没了
小陈在测试环境验证了一个"经典事故":
# 场景:用户上传头像的服务
docker run -d --name upload01 upload-service:latest
# 用户传了 1000 张头像,都存在容器里……
# 要升级版本了,先删旧容器
docker rm -f upload01
# 再起新容器
docker run -d --name upload01 upload-service:v2
# 然后……用户头像全没了!!
"小陈,你知道问题出在哪吗?"老周问。
"数据写在容器里了……容器一删,数据跟着没了。"
"对。容器的文件系统是'临时'的——容器创建时从镜像生成,容器删除时全部销毁。容器适合跑'无状态'的应用,但数据库、文件上传、配置这些'有状态'的数据,必须放到容器外面。 怎么放?用数据卷(Volume)。"
二、三种"数据放外面"的方式
老周画了一张对比:
容器数据管理的三种方式:
① 数据卷(Volume)—— 官方推荐
docker volume create mydata
docker run -v mydata:/data ...
数据存在 Docker 管理的区域(/var/lib/docker/volumes/)
✅ 持久化、好备份、跨容器共享
✅ 数据与容器解耦(删容器,数据还在)
② 绑定挂载(Bind Mount)—— 直接映射主机目录
docker run -v /opt/upload:/data ...
数据存在主机指定路径(如 /opt/upload)
✅ 方便(能直接看主机上的文件)
❌ 依赖主机路径(可移植性差一点)
③ tmpfs —— 只存内存(临时)
docker run --tmpfs /tmp ...
数据只存在内存里,容器停就没了
✅ 快(内存),适合临时缓存
❌ 重启即失(适合放临时文件,不适合数据)
"生产数据用 Volume(推荐)或 Bind Mount,临时缓存用 tmpfs。 记住这个选择逻辑就行。"
三、数据卷实战:让 MySQL 数据"永生"
老周带小陈把云间书店的 MySQL 容器化,并配上数据卷:
# 1. 创建一个数据卷
docker volume create mysql-data
# 2. 跑 MySQL,把数据目录挂到数据卷上
docker run -d --name db01 \
-v mysql-data:/var/lib/mysql \ # 数据库文件放数据卷(关键!)
-e MYSQL_ROOT_PASSWORD=YunJian2026 \
-e MYSQL_DATABASE=bookstore \
mysql:8.0
# 3. 写点数据
docker exec -it db01 mysql -uroot -pYunJian2026
# CREATE TABLE ...; INSERT INTO books VALUES ('三体', 29.9);
# 4. 模拟"容器删了"
docker rm -f db01
# 5. 用同一个数据卷再起一个容器
docker run -d --name db02 \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=YunJian2026 \
mysql:8.0
# 6. 查一下:数据还在!!
docker exec -it db02 mysql -uroot -pYunJian2026 -e "SELECT * FROM books;"
# → 三体 | 29.9 (数据没丢!)
"看到了吗?容器可以随便删、随便换,但数据卷是'传家宝'——数据跟着卷走,不跟容器走。 这就是生产数据库容器化的正确姿势。"
数据卷的关键命令:
docker volume ls # 查看数据卷
docker volume create mysql-data # 创建卷
docker volume inspect mysql-data # 查看卷详情(挂载点)
docker volume rm mysql-data # 删除卷(数据也没了!)
docker run -v mysql-data:/path # 挂载卷到容器
"注意:删除数据卷 = 删除数据! 删容器没事,删卷要三思。"
四、绑定挂载实战:开发时"改代码即生效"
"数据卷适合数据,绑定挂载适合开发场景。"老周说,"开发时改代码要立即生效,不用反复 build 镜像:"
# 开发模式:把本地代码目录直接映射进容器
docker run -d -p 8000:8000 \
-v /home/chen/app:/app \ # 本地代码 → 容器 /app
-v /home/chen/upload:/upload \ # 本地上传目录 → 容器
yunjian/ai-recommend:dev
# 效果:
# 本地改代码 → 容器里立即生效(不用重新 build!)
# 容器里写的上传文件 → 直接出现在 /home/chen/upload
"绑定挂载是'开发神器',数据卷是'生产标准'——开发图方便用绑定挂载,生产要稳定用数据卷。"
五、匿名卷与容器共享:进阶玩法
"最后两个进阶:匿名卷和共享卷。"
匿名卷(Anonymous Volume):
docker run -v /var/lib/mysql ... # 没给名字的卷
→ Docker 自动生成一个随机名的卷
→ 好处:容器删了卷不会自动删(还有机会找回)
→ 坏处:不好管理(一堆随机名字)
生产建议:总是给卷起名字
容器间共享数据卷:
docker run -v shared-data:/data --name a01 ...
docker run -v shared-data:/data --name a02 ...
→ 两个容器通过同一个卷共享数据(如 nginx 和 php-fpm 共享代码)
六、章末:老周的第四层总结
第四层:数据管理
├── 血的教训:容器文件系统是临时的,删容器=删数据
├── 数据卷 Volume:Docker 管理、持久化、可备份(生产标准)
├── 绑定挂载 Bind Mount:映射主机目录(开发神器)
├── tmpfs:只存内存(临时缓存)
└── 经验:数据库/上传文件必须挂卷;删卷=删数据要三思
"小陈,数据保住了。但下一个问题马上来了:你起了 web 容器、db 容器、cache 容器……它们之间怎么通信? 前端容器怎么找到后端容器?容器有 IP 吗?外面的人怎么访问容器?——下一章,容器网络,这是容器世界里最容易把人绕晕的部分。"