玩转Docker 08 — 实战:容器化真实后端并编排

玩转Docker 08 --- 实战:容器化真实后端并编排

一、本课目标

把前 7 课的拼图合体成真实工作流 :给一个 Python/FastAPI 应用写 Dockerfile、用 Compose 的 build: 从源码构建、environment: 注入配置、up -d --build 走"改代码→重新构建→上线"的日常循环。

二、项目:FastAPI + Redis 计数器

scss 复制代码
浏览器 → api(自建镜像, FastAPI, 8100 对外) ⇄ redis(现成镜像, 纯内网)
  • GET / → 应用信息(证明在跑、环境变量注入生效)
  • GET /count → 计数 +1(存在 redis 里,证明 api 连上了 redis)

四个文件

bash 复制代码
lesson8-api/
├── app/main.py           # FastAPI 应用(读环境变量、连 redis)
├── requirements.txt      # fastapi / uvicorn / redis
├── Dockerfile            # 按"先依赖后代码"排序
└── docker-compose.yml    # build: + environment: + redis(无 ports)

三、本课新知识点

新东西 说明
Compose 的 build: . 不用现成镜像,从当前目录 Dockerfile 现场构建
environment: 环境变量注入配置 ------代码 os.getenv() 读,值由 yml 给(生产标配)
up -d --build 先构建再启动------改代码后的日常部署命令
pip 国内源 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple(国内快数倍)
--host 0.0.0.0 Web 服务容器化的头号坑:uvicorn 默认只听 127.0.0.1(容器内部),容器外访问不到;必须 0.0.0.0

Dockerfile 核心排序(第 4 课铁律实战)

sql 复制代码
COPY requirements.txt → RUN pip install → COPY app/代码
(稳定,缓存保住)      (耗时,命中缓存)  (常变,放最后)

四、实验全过程(含目的、命令详解、结果解读)

实验 1:首次构建并启动

【目的】 验证"build: + up"全流程:拉基础镜像 → 逐层构建(含 pip 装依赖)→ 起两个容器。

【命令】

bash 复制代码
docker compose -f ~/桌面/work/Docker-lab/lesson8-api/docker-compose.yml up -d --build

【命令详解】 up -d 后台起全部服务;--build = 先按 build: 构建镜像再起容器。

【过程与结果】

ini 复制代码
[+] Building 29.7s (12/12) FINISHED
 => [1/5] FROM python:3.12-slim    21.1s   ← 拉基础镜像(sha256:... = 分层下载)
 => [2/5] WORKDIR /app              0.1s
 => [3/5] COPY requirements.txt .   0.0s
 => [4/5] RUN pip install ...       4.6s   ← 清华源,快!
 => [5/5] COPY app/ ./app/          0.1s
 => naming to lesson8-api-api:latest        ← 构建出的镜像自动命名:项目名-服务名
[+] up 14/14
 ✔ Image lesson8-api-api   Built
 ✔ Container lesson8-api-redis-1  Started   ← 先 redis(depends_on)
 ✔ Container lesson8-api-api-1    Started

【结论】 5 个构建步骤 = Dockerfile 的 5 条指令,每条一层;镜像自动命名 lesson8-api-apiredis:alpine(4MB)与 python:3.12-slim(50MB)拉取耗时正常。


实验 2:浏览器验证 API 与 Redis 链路

【目的】 确认应用在跑、环境变量注入生效、api 真的连上了 redis。

【命令】 浏览器访问 localhost:8100/localhost:8100/count(或 curl)。

【过程与结果】

json 复制代码
{"app":"demo-api","status":"running","redis_host":"redis"}   ← GET /
{"app":"demo-api","hits":1}                                  ← GET /count
{"app":"demo-api","hits":2}                                  ← 再刷一次

【结果解读】

  • "app":"demo-api" → FastAPI 在跑
  • "redis_host":"redis"环境变量注入生效,值=服务名(compose 网络自动解析成 redis 容器 IP)
  • hits 递增 → 计数真的写进了 redis 容器------api 与另一容器协作干活成功

【结论】 后端 + 依赖服务的容器化架构打通;"配置从环境读、地址用服务名"的生产模式落地。


实验 3:改代码 → rebuild(含一次"没生效"的教训)

【目的】 验证排序铁律的实战价值:改代码后 rebuild,pip install 层应保持 CACHED、只有 COPY 代码层重建。

【过程】 三个版本,完整记录:

版本 1(踩坑) :在编辑器里改了代码 → rebuild → 输出全 CACHED (连 COPY app/ 都是)→ 浏览器无变化。

  • 解读CACHED [5/5] COPY app/ 是铁证------rebuild 那一刻磁盘上的 main.py 没变(编辑器改了但没保存落盘,或保存晚于 build)。
  • 教训Docker 只认磁盘,编辑器画面不算数。"改了没生效"两大元凶:①没保存 ②忘了 rebuild。

版本 2(验证落盘)

bash 复制代码
grep -n version ~/桌面/work/Docker-lab/lesson8-api/app/main.py

有输出(显示带 v2 的行)= 磁盘上确实改了。

版本 3(成功):rebuild 后------

ruby 复制代码
 => CACHED [4/5] RUN pip install ...   ← 依赖层缓存稳住(铁律的价值)
 => [5/5] COPY app/ ./app/             ← 只有它重新执行(代码哈希变了)
 ✔ Container lesson8-api-api-1  Recreated   ← api 被重建
 (redis 无动静 ------ 没改它就不碰)

浏览器刷新 → "version":"v2" 出现 → 上线完成

【结论】 ① 排序铁律省时间(依赖层不重装);② Compose 智能增量更新(只重建变化的服务);③ build 缓存是"改动检测器"------全 CACHED 说明源文件没变。


五、完整时序:改代码 → 上线(标准动作,值得背下来)

css 复制代码
① 编辑器改代码 → ② Ctrl+S 落盘(Docker 只认磁盘)
→ ③ docker compose up -d --build
     ├─ BuildKit 逐层构建+查缓存(依赖层 CACHED,仅代码层重建)
     ├─ 新镜像 = 旧层复用 + 顶部新代码层
     └─ Compose 智能更新(api Recreated,redis 不动)
→ ④ 新容器跑起来(环境变量照常注入)
→ ⑤ 浏览器刷新验证 → 新功能上线 ✅
时序环节 对应知识
② 保存落盘 编辑器≠磁盘(本课坑)
逐层构建 第 3 课(镜像=层)
缓存命中/失效 第 4 课(缓存键=父层+输入;排序铁律)
必须重新 build 第 4 课(镜像不可变)
删旧起新容器 第 4 课(容器一次性)
Recreate/不碰 redis 第 7 课(compose 增量更新)
服务名连 redis 第 6 课(自定义网络 DNS)
8100→8000 第 1 课(端口映射)

六、关键认知

  1. build: vs image::自研代码用 build(现场构建),第三方服务用 image(现成镜像)------一个项目通常两者混用。
  2. 配置注入 :代码只 os.getenv(),值由 compose environment: 给;REDIS_HOST: redis = 服务名当地址。
  3. --host 0.0.0.0 必写:否则容器外访问不到(Web 容器化头号坑)。
  4. Docker 只认磁盘:改完必须保存 + 必须 rebuild,缺一环就"没生效"。
  5. 缓存=改动检测器:rebuild 全 CACHED → 先怀疑"改动没进构建目录/没保存"。

七、命令清单

命令 作用
docker compose up -d --build 构建镜像 + 启动全部服务(改代码后的部署命令)
sed -i 's/旧/新/' 文件 命令行文本替换(流编辑器;-i 直接改文件;脚本自动化必备)
grep -n 关键词 文件 确认改动落盘(改完验证的好习惯)

八、易错点

  1. uvicorn/flask 不监听 0.0.0.0 → 端口映射了也访问不到。
  2. 编辑器改了没保存 → 磁盘没变 → build 全 CACHED → "没生效"。
  3. 改了代码忘了 rebuild → 镜像冻结,容器还是旧的(第 4 课老坑)。
  4. pip 不加国内源 → 构建慢好几倍。
  5. requirements.txt 放在代码后面拷 → 改代码就重装依赖(排序铁律违反)。

九、一句话总结

真实后端容器化 = 好的 Dockerfile(先依赖后代码)+ Compose(build 构建、environment 注入、服务名互连)+ up -d --build 循环。改代码后的标准动作:保存 → rebuild → 验证。

十、本课产物

  • 项目 ~/桌面/work/Docker-lab/lesson8-api/(可反复实验)
  • 运行中:lesson8-api-api-1(8100)、lesson8-api-redis-1;镜像 lesson8-api-api:latest
  • 清理:docker compose -f ~/桌面/work/Docker-lab/lesson8-api/docker-compose.yml down

十一、下一课预告

第 9 课(最后一课):最佳实践与进阶 🎓

  • 多阶段构建(multi-stage build):构建工具不进最终镜像,瘦身 50%+
  • .dockerignore 实战:构建上下文瘦身 + 防密钥泄漏
  • 镜像瘦身技巧:slim/alpine 基础镜像、层合并
  • 依赖固定版本(requirements 锁版本)
  • CI/CD 概览:把"build→push→部署"自动化(push 代码自动构建镜像、自动部署)
相关推荐
神奇小汤圆1 小时前
从原始的CRUD 到高并发架构:关于秒杀系统的问题拆解与推演
后端
魔兽大山哥1 小时前
NL2SQL 最怕越权:我在执行层叠了好几层 SQL 闸门
后端
foggyprojects2 小时前
当 AI 输出销售额时,如何让它解释这个数字是怎么算出来的?
后端
一只叫煤球的猫2 小时前
开个新坑,从头开始完整拆解 Spring AI 2.0 的源码
后端·面试·aigc
自进化Agent智能体2 小时前
Hermes Cron 定时任务 —— 让 Agent 自动工作
后端
我不是码神663 小时前
Windows 下 Codex CLI 报“拒绝访问 (os error 5)”:先查入口,再查配置
后端·chatgpt
她的男孩3 小时前
我用 LLM 把后台 CRUD 效率提升 10 倍:AI 代码生成器的架构与落地实践
java·后端·架构
程序员cxuan3 小时前
本地跑一个 Qwen 3.8,你将拥有一个 Opus 4.6
人工智能·后端·程序员
vortex53 小时前
Container Desktop 安装与配置指南
docker