mcpField
G
generate-dockerfile

generate-dockerfile

github.com/vtmocanu云与 DevOps3283 次安装今天更新
代码仓库

关于 generate-dockerfile

面向开发者的容器化技能,通过分析项目生成或改进生产用 Dockerfile 和 .dockerignore。它要求依据代码库验证配置,并关注多阶段构建、安全与多架构支持。

主要功能

  1. 01基于代码库分析项目
  2. 02生成或改进 Dockerfile
  3. 03创建优化的 .dockerignore
  4. 04多阶段构建指导
  5. 05安全与多架构检查

适用场景

  1. 01为生产部署构建应用容器
  2. 02检查现有 Dockerfile 的安全性与构建实践

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/vtmocanu/skills --skill generate-dockerfile

安装后在 Claude Code 中输入/generate-dockerfile确认已加载。

详细介绍

移植自 vfarcic/dot-ai shared-prompts/generate-dockerfile.md(MIT,版权所有 (c) 2025 Viktor Farcic)。原作者:Viktor Farcic。

生成可用于生产环境的 Dockerfile

通过分析当前项目的结构、语言、框架和依赖项,生成经过优化、安全的多阶段 Dockerfile 和 .dockerignore。

说明

你正在帮助开发者为其应用容器化,以便部署到生产环境。你的任务是分析项目结构并生成两个文件:

  1. Dockerfile:采用安全最佳实践、可用于生产环境的多阶段构建文件
  2. .dockerignore:经过优化的构建上下文配置

核心原则

以下规则不可妥协,优先级高于所有其他指导。

添加前先核实所有内容

绝对规则:在 Dockerfile 中添加任何指令、配置或功能之前,务必检查实际代码库并进行核实。

必需流程:

  1. 确定你认为应该添加的内容
  2. 搜索代码库,核实该内容是否存在或确实有必要
  3. 仅在核实后添加——如果在代码中找不到证据,就不要添加
  4. 不确定时请询问用户——如果无法通过分析代码库推断出某些内容,应询问用户,而不是猜测

绝不臆测。始终核实。不确定时就询问。Dockerfile 必须以证据为依据。

彻底优先于速度:分析浅显会导致 Dockerfile 出错。生成任何内容之前:

  • 阅读实际源文件,而不只是文件名或目录列表
  • 必要时使用不同查询多次搜索相关模式
  • 通过导入和依赖追踪应用程序入口点
  • 不要停留在第一个搜索结果,要进行全面调查
  • 如果分析过程感觉太快,你很可能遗漏了某些内容

花更多时间生成的正确 Dockerfile,远胜于快速生成却无法使用的 Dockerfile。请预先投入足够时间。

支持多种架构

要求:确保所有 Dockerfile 指令都支持多种架构(amd64、arm64 等)。

适用于:

  • 基础镜像选择:使用官方多架构镜像
  • 二进制文件下载:动态检测架构,绝不硬编码(amd64、x86_64 等)
  • 系统软件包安装:使用软件包管理器(会自动处理架构)
  • 构建命令:确保跨平台兼容性

Dockerfile 必须能够在不同 CPU 架构上无需修改即可成功构建。

绝不添加 HEALTHCHECK

绝对禁止:在任何情况下都不要添加 HEALTHCHECK 指令。

原因:

  • 健康检查端点因应用而异,无法通过分析代码库进行核实
  • 添加未经核实的健康检查会导致容器被错误地标记为不健康
  • 如果应用有健康检查端点,用户会自行添加 HEALTHCHECK

如果添加了 HEALTHCHECK,就违反了“核实所有内容”原则。


最佳实践参考

生成 Dockerfile 时应考虑以下最佳实践。仅在适用于项目时应用——并非每项实践都适用于所有情况:

  • 软件包管理器的标志取决于使用的软件包管理器(apt-get、apk 或其他)
  • 特定语言的指导仅适用于对应语言
  • “核实所有内容”原则优先于一切:如果某项实践不适合项目,就跳过

生成时可将本节作为指导,并在验证时作为参考。

安全性
实践说明
非 root 用户创建专用用户(UID 10001+)并以该用户运行,绝不以 root 身份运行
固定镜像版本使用具体标签,例如 node:20-alpine,绝不使用 :latest
官方镜像优先选择来自可信来源的 Docker Official Images 或 Verified Publishers
镜像中不包含密钥绝不在 Dockerfile 或 ENV 指令中嵌入凭据、API 密钥或密码
不使用 sudo不要在容器中使用 sudo;需要 root 权限时,显式切换 USER
最少安装软件包仅安装应用实际需要的软件包
--no-install-recommends使用此标志搭配 apt-get,避免安装可选软件包
优先使用 COPY 而非 ADD除非确实需要 ADD 的 tar 解压功能,否则始终使用 COPY;绝不将 ADD 用于 URL
不安装调试工具除非应用需要,否则避免在生产镜像中安装 curl、wget、vim、netcat
在同一层中清理在安装软件包的同一条 RUN 命令中清除软件包管理器缓存
可执行文件归 root 所有应用二进制文件应归 root 所有,但由非 root 用户执行
镜像选择
实践说明
最小化基础镜像优先选择 alpine、slim、distroless 或 scratch,而非完整发行版镜像
多阶段构建始终将构建依赖与运行时分开;构建阶段 → 运行时阶段
匹配语言需求编译型语言 → distroless/scratch;解释型语言 → 配备运行时的 slim/alpine
根据项目确定版本从项目文件(package.json 中的 engines、go.mod 等)获取语言版本
构建优化
实践说明
层缓存在源代码之前复制依赖清单(package.json、go.mod)
合并 RUN 命令使用 && 链接相关命令,以减少层数并便于清理
显式 COPY绝不使用 COPY . .;仅显式复制所需文件和目录
按变更频率排序将稳定的指令(基础镜像、依赖项)放在前面,将易变的指令(源代码)放在最后
仅安装生产依赖仅安装生产依赖,不安装 devDependencies
可维护性
实践说明
对参数排序按字母顺序排列多行软件包列表,便于维护和审查
使用 WORKDIR始终使用 WORKDIR 更改目录,绝不使用 RUN cd
CMD 使用 exec 格式使用 JSON 数组格式:CMD ["executable", "arg1"],以便正确处理信号
为不明显的决策添加注释说明做出特定选择的原因,而非命令的作用
OCI 标签(可选)添加元数据标签以管理镜像(org.opencontainers.image.*)

流程

步骤 0:检查是否已有 Dockerfile

在生成任何内容之前,检查项目是否已有 Dockerfile。

  1. 在项目根目录查找 Dockerfile(同时检查 Dockerfile.prod 等变体)
  2. 如果找到,读取并保存其内容,以供步骤 2 使用
  3. 同样检查 .dockerignore,如果存在则读取

这将决定步骤 2 是生成新文件,还是改进现有文件。

步骤 1:分析项目结构

通过探索而非模式匹配来识别项目特征。

这些是分析目标,而非查找表。以下示例仅供说明——遇到任何语言、框架或工具链时,都应采用相同的分析方法。

  1. 语言检测:检查项目,确定其使用的编程语言。

    • 查找依赖清单文件(例如,package.json、go.mod、requirements.txt、Cargo.toml、Gemfile、composer.json、mix.exs、build.sbt 等)
    • 检查源文件扩展名
    • 阅读清单文件内容,了解其生态系统
    • 原则:每种语言都有某种形式的依赖声明,找到并阅读它
  2. 版本检测:查找所需的语言/运行时版本。

    • 在清单文件中搜索版本约束或引擎要求
    • 查找版本文件(例如,.node-version、.python-version、.ruby-version、.tool-versions)
    • 检查 CI 配置文件,其中通常会指定版本
    • 如果项目指定了版本 → 使用该确切版本
    • 如果未指定版本 → 在线查询该语言/运行时当前的 LTS/稳定版本
    • 原则:若项目指定了所需版本,就使用该版本;否则查询当前推荐版本,切勿猜测
  3. 框架检测:根据依赖项和项目结构识别框架。

    • 阅读清单文件中的依赖项列表
    • 查找特定于框架的配置文件
    • 检查项目结构中是否有符合框架惯例的内容
    • 原则:框架会留下明显特征,包括配置文件、目录结构和依赖项
  4. 应用类型:检查入口点和配置,确定应用的类型。

    • Web 服务/API:查找 HTTP 服务设置、路由定义和端口绑定
    • CLI 工具:查找参数解析、命令定义和 bin 条目
    • Worker/后台任务:查找队列消费者和计划任务
    • 静态站点:查找构建输出配置,确认没有服务端代码
    • 原则:入口点及其导入内容揭示了应用的用途
  5. 端口检测:在源代码和配置文件中搜索端口配置。

    • 查找环境变量的使用(例如,PORT、HTTP_PORT)
    • 搜索服务初始化时硬编码的端口号
    • 检查配置文件中的端口设置
    • 只有找到确凿依据时才添加 EXPOSE
  6. 构建要求:确定项目的构建方式。

    • 阅读清单文件,查找构建脚本/命令
    • 确定构建工具(可能是语言标准工具,也可能是第三方工具)
    • 确定构建输出(编译后的二进制文件、转译后的代码、打包后的资源)
    • 原则:每个需要构建的项目都有构建说明,找到它们
  7. 系统依赖项:关键步骤——缺少运行时二进制文件会导致静默失败。

    • 在代码库中搜索执行外部命令或二进制文件的代码
    • 常见模式:Shell 执行、子进程调用、exec 函数、系统调用
    • 对于找到的每个二进制文件,确认它是否为运行时所需(而不仅仅是构建时所需)
    • 考虑应用实际执行的操作——是否需要 CLI 工具、数据库客户端、图像处理程序?
    • 如果不确定某项是否为运行时依赖项,请询问用户
  8. 环境变量检测:关键步骤——缺少环境变量会导致运行时失败。

    • 在代码库中搜索环境变量访问(每种语言都有读取环境变量的方式)
    • 查找 .env.example、.env.sample 或类似文件,其中可能记录了必需的变量
    • 检查配置和启动代码中的环境变量用法
    • 确定哪些变量为必需(没有默认值,缺少时应用会失败),哪些为可选(有默认值)
    • 对于必需变量,在 Dockerfile 中设置合理的默认值
    • 原则:如果代码读取了某个环境变量,容器很可能需要对其进行配置
步骤 2:生成或改进 Dockerfile

如果没有现有的 Dockerfile → 使用以下模式生成新的多阶段 Dockerfile。

如果找到现有的 Dockerfile → 根据以下最佳实践和检查清单进行分析,然后改进:

  1. 对照检查清单评估 - 检查 Builder 和 Runtime 检查清单中的每一项
  2. 找出问题 - 安全问题(以 root 身份运行、:latest 标签)、缺少优化(未使用多阶段构建、COPY . .)、可维护性问题
  3. 保留有意的自定义设置 - 解释决策的注释、自定义配置、特定环境的设置
  4. 编辑以修复问题 - 应用最佳实践,同时保留已有的正确结构
  5. 说明更改 - 展示改进后的 Dockerfile 时,简要说明更改内容及原因

生成和验证时都使用以下模式和检查清单。

以下示例展示的是结构模式,而非可直接复制粘贴的模板。 根据项目使用的语言、包管理器和构建工具调整模式。

阶段 1:Builder
# Build stage - use an image with build tools for this language
FROM <language-image>:<version>-<variant> AS builder

WORKDIR /app

# PATTERN: Copy dependency manifests FIRST for layer caching
# Examples: package.json, go.mod, requirements.txt, Gemfile, Cargo.toml, pom.xml
COPY <dependency-manifest-files> ./

# PATTERN: Install dependencies, clean cache in same layer
# Use whatever package manager the project uses
RUN <install-dependencies-command> && \
    <clean-cache-command>

# PATTERN: Copy only the source files needed for build
# Never use "COPY . ." - be explicit about what's needed
COPY <source-directories> ./
COPY <config-files-needed-for-build> ./

# PATTERN: Run the project's build command
RUN <build-command>

Builder 阶段检查清单:

  • 命名阶段(AS builder)
  • 基础镜像适用于该语言(包含构建工具)
  • 版本根据项目文件确定(而非假设)
  • 在源代码之前复制依赖清单
  • 在同一个 RUN 中安装依赖并清理缓存
  • 只复制必需文件(绝不使用 COPY . .)
  • 构建命令与项目实际使用的命令一致
阶段 2:Runtime
# Runtime stage - use minimal image appropriate for the language
# Compiled languages: consider distroless, scratch, or alpine
# Interpreted languages: use slim or alpine variant with runtime only
FROM <minimal-runtime-image>:<version>

WORKDIR /app

# PATTERN: Create non-root user (syntax varies by base image)
# Alpine uses addgroup/adduser, Debian uses groupadd/useradd
RUN <create-group-command> && \
    <create-user-command>

# PATTERN: Copy ONLY runtime artifacts from builder
# What you copy depends on the language:
# - Compiled: just the binary
# - Interpreted: built output + runtime dependencies + minimal config
COPY --from=builder <build-outputs> ./
COPY --from=builder <runtime-dependencies> ./

# PATTERN: Set ownership to non-root user
RUN chown -R <user>:<group> /app

# Switch to non-root user BEFORE exposing ports or setting CMD
USER <non-root-user>

# Only if port was verified during analysis
EXPOSE <port>

# PATTERN: Use exec form for proper signal handling
# The command depends on how this application runs
CMD ["<executable>", "<args>"]

Runtime 阶段检查清单:

  • 最小化基础镜像(根据需要选择 alpine/slim/distroless/scratch)
  • 创建非 root 用户(UID 10001+)
  • 只从 builder 复制运行时所需的产物
  • 不包含源代码、测试、构建工具或开发依赖
  • 设置正确的所有权
  • 在 CMD 之前设置 USER 指令
  • 仅在分析中确认过端口时才使用 EXPOSE
  • CMD 使用 exec 格式(JSON 数组)
系统软件包安装模式

需要安装系统软件包时,请使用适用于基础镜像的包管理器。原则始终相同:只安装所需内容,并在同一层中清理缓存。

常见示例(根据基础镜像的包管理器调整):

# apt-get (Debian, Ubuntu)
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        package1 \
        package2 && \
    rm -rf /var/lib/apt/lists/*

# apk (Alpine)
RUN apk add --no-cache \
        package1 \
        package2

# yum/dnf (RHEL, Fedora, CentOS)
RUN yum install -y \
        package1 \
        package2 && \
    yum clean all && \
    rm -rf /var/cache/yum

软件包安装检查清单:

  • 使用适用于基础镜像的包管理器
  • 在可用时使用跳过可选/推荐软件包的标志
  • 按字母顺序排列软件包,便于维护
  • 在同一个 RUN 命令中清理缓存
  • 只安装应用实际需要的软件包
步骤 3:创建或改进 .dockerignore

如果没有现有的 .dockerignore → 根据 Dockerfile 生成一个最简文件。

如果找到现有的 .dockerignore → 根据 Dockerfile 的 COPY 命令进行检查:

  1. 移除多余的排除项(Dockerfile 本来就不会复制的目录)
  2. 添加缺失的安全排除项(被复制目录中的机密文件)
  3. 保持精简(约 10-15 行)

根据 Dockerfile 生成一个最精简的 .dockerignore 文件。

由于 Dockerfile 使用的是显式 COPY 命令(而非 COPY . .),.dockerignore 的作用有限:

  1. 安全性 - 排除可能存在于被复制目录中的机密文件模式
  2. 性能 - 排除会拖慢构建上下文传输的大型目录
流程
  1. 检查 Dockerfile 的 COPY 命令——它会复制哪些目录?
  2. 找出这些目录中的安全风险(可能意外存在的机密文件)
  3. 找出项目中会拖慢上下文传输的大型目录(>1MB)
  4. 仅排除这些项目
不应排除的内容

不要排除 Dockerfile 不会复制的目录!

如果 Dockerfile 不会复制某个目录,在 .dockerignore 中排除它就是多余的。

目标大小

最多约 10-15 行。 如果 .dockerignore 超过 20 行,很可能添加了不必要的排除项。

第 4 步:构建、测试和迭代

目的:在向用户展示前验证 Dockerfile 是否有效。只有通过验证后,Dockerfile 才算完成。

4.1 构建

构建镜像,以验证 Dockerfile 语法和指令是否正确:

docker build -t [project-name]-validation .
  • 如果构建成功 → 继续运行
  • 如果构建失败 → 分析错误,修复 Dockerfile,然后重试
4.2 运行

启动容器,以验证应用是否运行:

docker run -d --name [project-name]-test [project-name]-validation
sleep 5  # Allow startup time

检查容器状态:

docker inspect --format='{{.State.Status}}' [project-name]-test
docker inspect --format='{{.State.ExitCode}}' [project-name]-test

预期行为取决于应用类型(在第 1 步中确定):

  • 服务(Web 服务器、API、工作进程):容器应继续运行
  • CLI 工具 / 一次性命令:容器应已退出,退出代码为 0

如果容器崩溃或意外退出 → 继续分析日志,了解原因。

4.3 日志分析

收集并分析容器日志:

docker logs [project-name]-test 2>&1

根据你在第 1 步中了解的项目情况分析日志。 你知道:

  • 项目使用的语言和框架
  • 应用应执行的任务
  • 应用所需的依赖项
  • 这类应用成功启动时的表现

根据这些背景判断日志是否表明:

  • 应用已正确启动,或者
  • 存在问题(错误、崩溃、缺少依赖项、权限问题等)

如果日志表明存在问题 → 找出根本原因,修复 Dockerfile 或 .dockerignore,然后重试。

4.4 Lint 检查(如可用)

如果已安装 hadolint,运行它以发现 Dockerfile 最佳实践方面的问题:

hadolint Dockerfile
  • 如果未安装 hadolint → 跳过此检查
  • 如果 hadolint 报告问题 → 评估每个问题,酌情修复,然后重试
  • 某些 hadolint 警告可能是有意为之(请结合项目背景自行判断)
4.5 安全扫描(如可用)

如果已安装 trivy,扫描已构建的镜像以查找漏洞:

trivy image --severity HIGH,CRITICAL [project-name]-validation
  • 如果未安装 trivy → 跳过此检查
  • 如果 trivy 在基础镜像中报告 HIGH/CRITICAL 漏洞 → 考虑更换基础镜像版本或变体是否有帮助
  • 如果漏洞存在于应用依赖项中 → 告知用户,但不要因此阻止交付(更新依赖项不属于 Dockerfile 的范围)
4.6 迭代

如果任何验证步骤失败:

  1. 分析具体的错误消息或行为
  2. 找出根本原因——常见问题包括:
    • 缺少文件 → COPY 命令不正确,或 .dockerignore 规则过于宽泛
    • 缺少依赖项 → 未安装系统软件包
    • 权限被拒绝 → 所有权或 USER 指令有问题
    • 找不到模块 → 构建步骤未完成,或复制了错误的文件
    • Hadolint 警告 → Dockerfile 最佳实践方面的问题
  3. 修复相应文件(Dockerfile 或 .dockerignore)
  4. 从第 4.1 步开始重试

最多迭代 5 次。 如果尝试 5 次后仍然失败:

  • 停止并向用户展示当前状态
  • 说明失败之处以及已尝试的修复方法
  • 请求用户指导
4.7 清理

验证后务必清理,无论验证是否成功:

docker stop [project-name]-test 2>/dev/null || true
docker rm [project-name]-test 2>/dev/null || true
docker rmi [project-name]-validation 2>/dev/null || true

只有在以下条件满足后,才能继续向用户展示 Dockerfile:

  • 所有验证步骤均已通过,并且
  • 已完成清理

输出格式

对于新 Dockerfile(不存在现有文件)

向用户提供这两个文件:

  1. Dockerfile,包含清晰的注释,说明各个部分
  2. .dockerignore,包含分类清晰的部分

生成后,请提供:

  • 对设计选择的简要说明(基础镜像、构建阶段、安全措施)
  • 构建命令:docker build -t [project-name] .
  • 运行命令:docker run -p [port]:[port] [project-name]
  • 预期镜像大小
改进 Dockerfile(已找到现有文件)

展示改进后的文件,并附上更改摘要:

  1. Dockerfile - 改进后的版本
  2. 所做更改 - 简要列出更改内容及原因:
    • 安全修复(例如:“添加非 root 用户——原先以 root 身份运行”)
    • 优化改进(例如:“添加多阶段构建以减小镜像体积”)
    • 最佳实践更新(例如:“将 CMD 改为 exec 形式,以便处理信号”)
  3. 保留内容 - 说明保留的自定义内容
  4. .dockerignore - 如需更改,则提供改进后的版本
两种情况均适用

建议的后续步骤(Dockerfile 已通过验证):

  • 集成到 CI/CD 流水线
  • 提交到版本控制系统

成功标准

Dockerfile 检查清单
  • 构建成功且无错误
  • 使用多阶段构建(builder → runtime)
  • 以非 root 用户运行(UID 10001+)
  • 使用固定版本标签(不使用 :latest)
  • 使用精简基础镜像(alpine/slim/distroless)
  • 在复制源代码前先复制依赖清单(利用层缓存)
  • 使用显式 COPY(不使用 COPY . .)
  • 使用 && 合并 RUN 命令
  • 在同一层清理软件包管理器缓存
  • 使用 --no-install-recommends(如果使用 apt-get)
  • 使用 exec 形式的 CMD(["executable", "arg"])
  • 除非确有需要,否则不包含调试工具
  • 不嵌入密钥或凭据
.dockerignore 检查清单
  • 文件大小精简(约 10-15 行)
  • 排除已复制目录中的密钥
  • 排除体积较大的非必需目录
  • 不排除 Dockerfile 未复制的目录
验证检查清单(步骤 4)
  • 镜像构建成功
  • 容器启动后未崩溃
  • 日志中没有表明应用程序故障的错误
  • Hadolint 检查通过(如果已安装)
  • Trivy 未发现基础镜像中的严重漏洞(如果已安装)
  • 测试容器和镜像已清理

在所有验证检查均通过之前,不要向用户展示 Dockerfile。


工作流示例

新建 Dockerfile(不存在现有文件)
  1. 检查:“未找到现有 Dockerfile。将生成一个新文件。”
  2. 探索:“让我查找依赖清单……找到了 <manifest-file>。正在读取以了解所用技术生态。”
  3. 识别:“这是一个使用 <framework/tool> 的 <language> 项目。依赖清单表明版本为 <X>。”
  4. 追踪:“入口点是 <file>。正在追踪导入项,以了解运行时需求。”
  5. 规划结构:“多阶段构建:builder 阶段需要 <build-tools>,runtime 阶段只需要 <runtime-artifacts>。”
  6. 依赖项:“正在搜索外部二进制文件的使用情况……找到了 <binary>。需要将其加入 runtime 镜像。”
  7. 生成:“创建 Dockerfile 和 .dockerignore。根据最佳实践检查清单进行检查。”
  8. 构建与测试:“正在构建镜像……正在运行容器……正在检查日志……”
  9. 迭代(如有需要):“构建因缺少软件包而失败。正在将其添加到 Dockerfile 并重试……”
  10. 清理并展示:“验证通过。正在移除测试产物。这是你的 Dockerfile。”
改进现有 Dockerfile
  1. 检查:“发现现有 Dockerfile。正在读取并分析……”
  2. 分析项目:与上文相同,探索项目以了解 Dockerfile 应实现的功能。
  3. 评估:“正在根据最佳实践清单检查现有 Dockerfile……”
    • “❌ 以 root 身份运行——没有 USER 指令”
    • “❌ 使用 :latest 标签,而不是固定版本”
    • “✅ 已采用多阶段构建”
    • “✅ 优先复制了依赖清单”
  4. 保留:“保留自定义 ENV 变量和特定端口配置——这些设置看起来是有意为之。”
  5. 改进:“添加非 root 用户,并固定映像版本以匹配项目要求。”
  6. 构建并测试:“正在构建改进后的映像……运行容器……检查日志……”
  7. 迭代(如有需要):“容器崩溃——日志显示权限错误。正在修复所有权并重试……”
  8. 清理并展示:“验证通过。正在移除测试产物。以下是改进内容。”

核心思路:调查实际项目,而不是套用模板。每个项目都各不相同。验证通过后再展示。

评论

支持 Markdown