一、五个容器,二十条命令,谁来记?
小陈把直播带货模块容器化之后,部署流程是这样的:
# 每次部署要敲的命令(节选):
docker network create livestream-net
docker volume create ls-db-data
docker volume create ls-upload
docker run -d --network livestream-net -v ls-db-data:/var/lib/mysql --name ls-db mysql:8.0
docker run -d --network livestream-net -v ls-upload:/upload --name ls-upload upload:v1
docker run -d --network livestream-net -p 8000:8000 --name ls-api api:v1
docker run -d --network livestream-net -p 80:8080 --name ls-web web:v1
docker run -d --network livestream-net --name ls-cache redis:7
# ……还有环境变量、重启策略、资源限制……全都得记得清清楚楚
小陈瘫在椅子上:"师傅,这哪是部署,这是背口诀啊。换个新人来,光这些参数就够他记三天。"
老周:"所以有了 docker-compose——把'整个系统怎么部署'写成一个配置文件,一条命令,全部搞定。"
二、docker-compose.yml:系统的"部署说明书"
老周带小陈写了一个 docker-compose.yml:
# docker-compose.yml —— 云间书店直播带货模块
version: "3.8"
services: # 定义"有哪些服务"(= 容器)
db: # 数据库
image: mysql:8.0
container_name: ls-db
environment: # 环境变量(代替 -e)
MYSQL_ROOT_PASSWORD: YunJian2026
MYSQL_DATABASE: livestream
volumes: # 数据卷(代替 -v)
- db-data:/var/lib/mysql
restart: always # 重启策略(代替 --restart)
cache: # 缓存
image: redis:7
container_name: ls-cache
restart: always
api: # 后端 API
build: ./api # 用 Dockerfile 构建(代替 docker build)
container_name: ls-api
environment:
DB_HOST: db # 直接写服务名!compose 自动 DNS
DB_PASSWORD: YunJian2026
depends_on: # 依赖:先启动 db 再启动 api
- db
restart: always
web: # 前端
build: ./web
container_name: ls-web
ports: # 端口映射(代替 -p)
- "80:8080"
depends_on:
- api
restart: always
volumes: # 声明数据卷(代替 docker volume create)
db-data:
"看到了吗?之前所有 docker run 的参数,全部变成了配置文件里的一行行声明。 这个文件就是整个系统的'部署说明书'——团队任何人拿到它,都能一键部署出完全一样的系统。"
三、一条命令搞定一切
# 启动全家桶(核心命令)
docker compose up -d
# 其他常用命令
docker compose ps # 看所有服务状态
docker compose logs -f api # 看某个服务的日志
docker compose down # 停掉所有服务(容器删除)
docker compose down -v # 连数据卷一起删(数据也没了!慎用)
docker compose restart api # 重启某个服务
docker compose exec api bash # 进某个服务
docker compose pull # 拉取最新镜像
# 更新:改了代码,重新构建并启动
docker compose up -d --build
"docker compose up -d 就是云间书店的标准部署命令。 部署从'背二十条命令'变成'一条命令 + 一个配置文件'——而且这个文件可以放进 Git 版本管理,谁改了什么一目了然。"
四、compose 三件套:服务、网络、卷
"compose 文件里最核心的三个顶级配置:services、networks、volumes。"老周说:
services(服务) :定义"有哪些容器",每个服务就是一个容器
networks(网络) :定义"容器之间的网络"(默认自动建一个)
volumes(卷) :定义"数据卷"(容器之间共享/持久化)
关键机制:
① 自动网络:compose 默认创建一个网络,
所有服务都在里面,直接用"服务名"互访(不用手动建网)
② 自动卷:声明在 volumes 里的卷,Docker 自动创建
③ 依赖顺序:depends_on 控制启动顺序
(先 db,再 api,再 web)
对比手动 docker run:
手动:网络、卷、启动顺序、环境变量……全靠人脑记
compose:全部写进文件,可版本管理、可审阅、可复用
"compose 的价值不是'少敲几条命令',是'把部署逻辑变成代码'——可复现、可审计、可交接。这就是前面说的'环境即代码'的完整落地。"
五、环境变量与 .env:配置和代码分离
"还有一个生产必备技巧:环境变量分离。"老周说,"密码写死在 compose 文件里,要是文件传到 Git 上,密码就泄露了。"
# docker-compose.yml 里用变量占位
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD} # 从 .env 读取
# .env 文件(不提交到 Git!)
MYSQL_PASSWORD=YunJian2026Secret
# 或者部署时用环境变量
export MYSQL_PASSWORD=YunJian2026Secret
docker compose up -d
配置管理原则:
- 代码、镜像可以进 Git,密码、密钥绝对不进 Git
- 用 .env 文件(加 .gitignore)+ 部署机环境变量
- 敏感信息还可以用 Docker Secret(Swarm/K8s 场景)
"记住:配置文件里永远不要写死密码。 这是安全底线,也是专业和业余的分水岭。"
六、云间书店的完整 compose 架构
老周最后给小陈看了直播带货模块的完整架构:
docker compose up -d 之后,云间书店得到:
┌─────────────────────────────────────────┐
│ 外部访问 → 宿主机:80 │
│ │ │
│ ▼ │
│ ls-web(前端, 80:8080) │
│ │ 调用 │
│ ▼ │
│ ls-api(后端 API) │
│ ├──→ ls-db(MySQL, 数据卷 db-data) │
│ └──→ ls-cache(Redis) │
│ ls-upload(文件上传, 卷 ls-upload) │
│ (都在同一个自动网络里,用服务名互访) │
└─────────────────────────────────────────┘
部署 = git pull + docker compose up -d --build
回滚 = docker compose down + 用旧镜像 up
"师傅,compose 已经很好用了,为什么还要学 Kubernetes?"小陈问。
"问到点子上了。"老周说,"compose 适合'单台机器上的多容器编排'。但云间书店以后要多台服务器、容器要跨机器调度、流量大了要自动扩容、一台机器挂了容器要自动迁移……compose 管不了跨机器的'集群'。 那就是第九章 Kubernetes 的领域。不过在那之前,还有一件要紧事——镜像仓库。你的镜像,总不能只存在自己电脑上吧?"