Docker 高效工作流:与 AI 协作的最佳实践

devops进阶8 分钟阅读2026/8/26

(注:您提供的原文已经是简体中文,且行文非常自然流畅、完全符合口语化要求,产品名和技术术语的处理也完美契合您的规则。因此无需进行二次翻译,直接为您输出原稿:)

当 Dockerfile 写到第三十行时,我决定换个思路

上周三下午,我盯着一个怎么也构建失败的 Dockerfile 发了十分钟呆。错误信息是某个依赖版本冲突,但日志刷了三屏,根本找不到关键信息。我试过加 --no-cache,试过分阶段构建,甚至在容器里手动跑命令排查。折腾了快两个小时,我开始想:有没有更聪明的办法?

后来我把这个烂摊子扔给了 Claude,没想到二十分钟就搞定了。但从那以后,我花了不少时间琢磨怎么把这种协作变成稳定的工作流,而不是碰运气。今天分享的就是我踩过坑之后总结出来的一套方法。

第一个教训:别扔一个裸 Dockerfile 过去

我最开始的做法非常蠢——直接把整个 Dockerfile 复制粘贴进去,附上一句"帮我看看哪里错了"。结果返回了一堆正确的废话,什么"建议检查依赖版本""可以尝试多阶段构建",对我当下的困境毫无帮助。

正确的做法是给足上下文。我后来会这样描述问题:

我在构建一个 Python 3.11 的 FastAPI 项目,基础镜像用的 python:3.11-slim。
现在卡在 pip install 阶段,报错如下(只贴关键部分):

ERROR: Could not build wheel for numpy, which is required to install pyproject.toml-based projects

我的 requirements.txt 里指定了 numpy==1.24.3。
容器环境是 Debian bullseye,没有装 build-essential。

我怀疑是缺少编译依赖,但不想装太多东西导致镜像膨胀。
请帮我修改 Dockerfile 相关阶段,并解释每一行的作用。

看到区别了吗?我交代了基础环境、具体错误、我的猜测、以及我的约束条件(不想镜像太大)。这样得到的回复直接给出了方案:

FROM python:3.11-slim AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc g++ gfortran libopenblas-dev \
    && rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

FROM python:3.11-slim
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0"]

多阶段构建,编译依赖留在 builder 阶段,最终镜像干干净净。我照着改完,一次构建成功。

把 docker-compose.yml 也拉进来

单容器还好,一旦涉及多服务编排,光靠嘴说不清楚。我后来养成一个习惯:直接把 docker-compose.yml 的内容贴进去,让它理解服务间的依赖关系。

有一次我的 Redis 和 Worker 服务启动顺序出了问题——Worker 总是先于 Redis 起来,然后连不上就挂了。我贴了这样的内容:

version: "3.8"
services:
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  worker:
    build: ./worker
    depends_on:
      - redis
    command: celery -A tasks worker --loglevel=info

得到的回复指出了问题:depends_on 只保证启动顺序,不保证 Redis 真的准备好了。建议改成:

  worker:
    build: ./worker
    depends_on:
      redis:
        condition: service_healthy
    command: celery -A tasks worker --loglevel=info

  redis:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 3s
      timeout: 2s
      retries: 10

这种东西我知道,但在赶进度的时候就是会忘。有个帮手盯着这些细节,省心不少。

用 docker inspect 输出当"体检报告"

遇到容器运行时问题,我不再自己瞎猜了。直接跑命令把状态 dump 出来:

docker inspect my-container --format='{{json .State}}' | python3 -m json.tool
docker logs my-container --tail 50
docker exec my-container env | sort

把这些输出贴过去,相当于给了一份体检报告。有一次容器里的环境变量死活不对,我贴了 env 输出,立刻被指出:我在 docker-compose 里用了 env_file,但文件里有 BOM 头,导致第一个变量名变成了 \ufeffDB_HOST。这种问题人工看日志根本看不出来。

我踩过的坑

生成的命令没验证就直接跑。 有一次它让我用 docker system prune -a --volumes,我顺手就敲了回车。结果把我开发环境的几个临时卷给删了,丢失了半天的测试数据。现在任何带删除性质的命令,我都会先看懂再执行。

没交代清楚目标环境。 我说"帮我写个 Dockerfile",结果它默认用了 Ubuntu 基础镜像,而我实际要部署到 Alpine 环境。很多包名不一样,构建又炸了。现在我开头就会声明:"目标环境是 Alpine 3.18"。

让它一次做太多事。 我曾经试图在一个对话里同时解决 Dockerfile 优化、compose 编排、还有 nginx 配置。结果顾此失彼,nginx 那块给出的配置引用了错误的容器名。现在我只聚焦一个问题,解决了再开新话题。

实际用下来的几个技巧

第一,让它解释现成的 Dockerfile 而不是从零写。我接手过别人留下的一个 80 行 Dockerfile,里面一堆我没见过的技巧。我逐段贴过去问"这一段在做什么,为什么要这样做",比自己查文档快多了。

第二,明确告诉它镜像大小的预算。比如"最终镜像请控制在 200MB 以内",它就会主动选择 slim 变体、合并 RUN 指令、用 --no-install-recommends 这些操作,不用你一条条提醒。

第三,让它帮你写健康检查。这是很多人懒得做的事情,但写得好不好直接影响生产稳定性。我通常会问:"为这个 FastAPI 服务写一个 healthcheck,要考虑数据库连接的依赖"。

说句大实话

这套工作流不是万能的。遇到特别新的问题——比如 Docker 23.0 刚出的某个特性导致的行为变化——它给出的答案可能是过时的。还有一些涉及底层网络配置的诡异问题,它给的 tcpdump 命令倒是挺有用,但诊断结论经常跑偏。

另外,如果你自己不懂 Docker 的基础概念,这套方法会让你更痛苦。因为你没法判断它给出的方案是否合理,出了问题也不知道怎么纠偏。它是个加速器,不是自动驾驶。

我现在的工作模式是:自己搭框架,让它填细节;自己定约束,让它找方案;自己验证结果,让它解释原因。这样用下来,Docker 相关的杂活大概能省掉一半时间。

相关 Agent

D

Docker

Docker 是一个容器化平台,允许开发者将应用及其依赖项打包成轻量级、可移植的容器。它简化了跨环境的开发、测试和部署过程。该描述强调它最适合容器化和开发环境,提供免费方案和团队方案,团队方案从每用户每月5美元起。

了解更多 →