mcpField
I
infra-ci-cd-docker

infra-ci-cd-docker

github.com/agents-inc云与 DevOps2660 次安装2 天前更新
代码仓库

关于 infra-ci-cd-docker

面向 Node.js/TypeScript 项目的 Docker 容器化技能,涵盖开发环境与生产镜像构建。重点介绍多阶段构建、缓存优化及容器安全实践。

主要功能

  1. 01Node.js/TypeScript 多阶段构建
  2. 02Docker Compose 开发环境
  3. 03BuildKit 缓存与层优化
  4. 04非 root 用户及密钥安全
  5. 05健康检查与优雅关闭

适用场景

  1. 01制作精简的生产容器镜像
  2. 02配置本地多容器开发环境
  3. 03优化依赖安装与 CI/CD 构建
  4. 04加固容器运行安全

安装

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

$npx skills add https://github.com/agents-inc/skills --skill infra-ci-cd-docker

安装后在 Claude Code 中输入/infra-ci-cd-docker确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

metadata.yaml
reference.md
examples/
compose.md
core.md
production.md

详细介绍

Docker 容器化模式

**快速指南:**使用 Docker 和 BuildKit 对 Node.js/TypeScript 应用进行容器化。使用多阶段构建生成最小化的生产镜像(从 1GB 缩减至不足 100MB)。使用 Docker Compose v2 搭建开发环境。使用 BuildKit 缓存挂载,将依赖安装速度提升 10 倍。通过非 root 用户、健康检查和机密挂载保障生产环境安全。追求体积小可选 Alpine,追求兼容性可选 Debian slim。


<critical_requirements>

关键:使用此技能前

所有代码都必须遵循项目在 CLAUDE.md 中的约定(kebab-case、命名导出、导入排序、import type、命名常量)

(生产镜像必须使用多阶段构建——绝不能在生产镜像中包含开发依赖、TypeScript 编译器或源文件)

(容器必须以非 root 用户运行——绝不能让生产容器以 root(默认用户)身份运行)

(必须使用 CMD ["node", "server.js"](exec 形式)——绝不能在 CMD 中使用 npm start 或 shell 形式)

(构建时必须使用 BuildKit 机密挂载来处理敏感数据——绝不能将 ARG 或 ENV 用于机密信息)

(必须先复制 package.json/锁文件,再复制源代码——绝不能在 npm ci 之前执行 COPY . .(这会破坏层缓存))

</critical_requirements>


示例


**自动检测:**Dockerfile、docker-compose、compose.yaml、Docker、容器、多阶段构建、BuildKit、.dockerignore、Docker Compose、docker build、docker run、HEALTHCHECK、Docker Scout、docker init、容器化、容器镜像、Docker 网络、Docker 卷

适用场景:

  • 为 Node.js/TypeScript 应用创建 Dockerfile
  • 设置多阶段构建以缩小生产镜像体积
  • 配置 Docker Compose,用于本地开发环境
  • 优化 Docker 层缓存和 BuildKit 缓存挂载
  • 实现容器安全(非 root、机密信息、只读文件系统)
  • 为容器编排设置健康检查
  • 构建用于构建并推送 Docker 镜像的 CI/CD 管道
  • 团队需要在不同操作系统平台间保持开发环境一致
  • 微服务架构需要隔离服务及其依赖项

不适用场景:

  • 不使用容器的无服务器部署(AWS Lambda、Vercel Functions)
  • 没有服务器运行时的静态网站托管(Netlify、Vercel、Cloudflare Pages)
  • 通过 npm 分发的简单脚本或 CLI 工具
  • 无需容器化的本地开发
  • 增加的复杂性超过隔离带来的收益
  • Kubernetes 专用编排模式(请使用 Kubernetes 技能)

涵盖的关键模式:

  • 用于 Node.js/TypeScript 的多阶段 Dockerfile(构建器模式)
  • Docker Compose v2 开发环境
  • BuildKit 缓存挂载和层优化
  • 容器安全(非 root、机密信息、能力、只读)
  • 生产容器的健康检查
  • 用于优化构建上下文的 .dockerignore
  • 卷挂载(命名卷、绑定挂载、tmpfs)
  • Docker 网络(bridge、host、overlay)
  • CI/CD 集成(GitHub Actions build-push)
  • 信号处理(使用 tini 实现平滑关闭)

## 理念

容器可提供可复现、相互隔离的环境,消除“在我的机器上能运行”的问题。Docker 是将 Node.js/TypeScript 应用打包为可移植轻量级镜像的标准工具。

核心原则:

  1. 精简生产镜像 - 仅包含应用运行所需内容(编译后的 JS、生产依赖、运行时)
  2. 优化层缓存 - 组织 Dockerfile,使未更改的层可以重复使用,从而加快重建速度
  3. 默认安全 - 使用非 root 用户、镜像中不包含密钥、尽量缩小攻击面
  4. 开发环境与生产环境保持一致 - Docker Compose 在本地模拟生产环境的拓扑结构

核心模式

模式 1:用于 Node.js/TypeScript 的多阶段 Dockerfile

多阶段构建会在构建阶段编译 TypeScript,然后仅将编译后的 JS 和生产依赖复制到精简的运行时镜像中。这样可将镜像大小从 1GB 以上缩减至 100MB 以下。

生产环境的 Dockerfile 使用三个阶段:

  1. deps - 仅安装生产依赖
  2. builder - 安装所有依赖并编译 TypeScript
  3. runner - 将编译后的输出和生产依赖复制到精简镜像中
# Stage 1: Production dependencies
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci --omit=dev --no-audit --no-fund

# Stage 2: Build TypeScript
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci --no-audit --no-fund
COPY tsconfig.json ./
COPY src/ ./src/
RUN npm run build

# Stage 3: Production runtime
FROM node:22-alpine AS runner
WORKDIR /app
RUN apk add --no-cache tini
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 --ingroup appgroup appuser
COPY --from=deps --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --chown=appuser:appgroup package.json ./
USER appuser
EXPOSE 3000
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "dist/server.js"]

优点: 三阶段构建可分离各项职责,BuildKit 缓存挂载可加快 npm ci,使用非 root 用户和 tini 处理信号,最终镜像仅包含生产所需文件

完整的 Dockerfile(包括 Bun 和单仓库变体)请参阅 examples/core.md。


模式 2:使用 Docker Compose 进行开发

Docker Compose v2 用于定义多容器开发环境。使用 compose.yaml(而非 docker-compose.yml),并使用 docker compose 命令(中间不加连字符)。

# compose.yaml
services:
  app:
    build:
      context: .
      target: builder
    volumes:
      - .:/app:cached
      - /app/node_modules
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:17-alpine
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dev"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:

优点: 依赖项使用 condition: service_healthy 进行健康检查,绑定挂载使用 :cached 提升 macOS 性能,匿名卷可保护 node_modules,命名卷可持久保存数据库数据

包含 Redis、网络和卷模式的完整开发环境请参阅 examples/compose.md。


模式 3:BuildKit 缓存挂载

BuildKit(自 Docker Engine 23+ 起默认启用)提供缓存挂载,可在多次构建之间保留包管理器缓存,将安装时间缩短 10 倍甚至更多。

# npm
RUN --mount=type=cache,target=/root/.npm \
    npm ci --no-audit --no-fund

# pnpm
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
    pnpm install --frozen-lockfile

层顺序规则: 固定基础镜像版本 > 复制依赖清单 > 安装依赖 > 复制源代码 > 构建/编译。这样可最大限度地命中缓存。

npm、Bun、pnpm 和 apt 的缓存挂载模式请参阅 examples/core.md。


模式 4:容器安全
非 root 用户
RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 --ingroup appgroup appuser
COPY --chown=appuser:appgroup --from=builder /app/dist ./dist
USER appuser
密钥挂载(构建时)
# Secret is ephemeral - never persisted in image layers
RUN --mount=type=secret,id=npm_token,env=NPM_TOKEN \
    npm ci --no-audit --no-fund
# Build: docker build --secret id=npm_token,env=NPM_TOKEN .
运行时加固
services:
  app:
    read_only: true
    tmpfs: [/tmp]
    security_opt: [no-new-privileges:true]
    cap_drop: [ALL]

完整的生产环境 Compose 配置、密钥管理和 CI/CD 流水线请参阅 examples/production.md。


模式 5:健康检查

健康检查使编排工具能够检测无响应的容器并自动重启它们。

HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=30s \
    CMD ["node", "-e", "fetch('http://localhost:3000/health').then(r => { if (!r.ok) process.exit(1) }).catch(() => process.exit(1))"]

优点: 使用 Node.js 内置的 fetch(Alpine 中无需安装 curl),启动宽限期可留出应用启动时间,检查专用健康端点,而不仅仅是根路径

健康检查端点的实现和 Compose 健康检查模式请参阅 examples/production.md。


模式 6:.dockerignore
node_modules
dist
.git
.env
.env.*
!.env.example
Dockerfile*
compose.yaml
__tests__
*.test.ts
coverage
.github

优点: 排除 node_modules(以便确定性地重新安装)、.env 文件(防止密钥泄露)和 .git(避免缓存失效),同时保持较小的构建上下文

全面的 .dockerignore 文件请参阅 examples/core.md。


模式 7:信号处理与优雅关闭

Node.js 作为 PID 1 运行时,无法正确处理 SIGTERM/SIGINT。使用 tini 作为 init 系统。

RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "dist/server.js"]

优点: Tini 会将信号转发给 node 进程、回收僵尸进程,并确保在执行 docker stop 时优雅关闭

完整的 TypeScript 优雅关闭实现请参阅 examples/core.md。


性能优化

镜像体积缩减
技术影响
多阶段构建从 1GB 缩减至不足 100MB(减少 90% 以上)
Alpine 基础镜像135MB,而完整镜像为 1GB,精简版为 200MB
npm ci --omit=dev从生产环境中移除开发依赖
.dockerignore缩小构建上下文,加快传输速度
构建速度优化
技术影响
BuildKit 缓存挂载依赖安装速度提升 10 倍
图层排序(先安装依赖,再复制源代码)仅源代码发生变化时可命中缓存
.dockerignore 排除 node_modules避免向守护进程发送数 GB 的数据
--no-audit --no-fund 标志跳过不必要的 npm 检查
并行多阶段构建BuildKit 并发构建互相独立的阶段
CI/CD 构建缓存
# GitHub Actions - Cache Docker layers
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v7
  with:
    cache-from: type=gha
    cache-to: type=gha,mode=max

优势: GitHub Actions 缓存(type=gha)会在 CI 运行期间持久保存图层,mode=max 会缓存所有图层(而非仅缓存最终图层)

完整的 CI/CD 流水线示例请参阅 examples/production.md。


<decision_framework>

决策框架

基础镜像选择
Which base image?
  |
  +-- Need smallest image? --> Alpine (node:22-alpine, ~135MB)
  |     +-- musl libc compatibility issues? --> Use Debian slim instead
  |
  +-- Need maximum compatibility? --> Debian slim (node:22-slim, ~200MB)
  |     +-- Native extensions work out of the box
  |
  +-- Need debugging tools? --> Full image (node:22, ~1GB)
  |     +-- Development only, never for production
  |
  +-- Maximum security? --> Distroless (gcr.io/distroless/nodejs22-debian12)
        +-- No shell, no package manager, smallest attack surface
Compose 与 Dockerfile 目标的选择
How to manage dev vs prod?
  |
  +-- Multi-stage Dockerfile with targets
  |     +-- `docker compose build --target builder` for dev
  |     +-- Final stage for production
  |
  +-- Separate compose files
        +-- compose.yaml (base)
        +-- compose.override.yaml (dev - auto-loaded)
        +-- compose.prod.yaml (production)
卷策略
What data needs to persist?
  |
  +-- Source code (dev hot reload) --> Bind mount with :cached
  +-- Database files --> Named volume
  +-- Temporary/cache data --> tmpfs
  +-- Secrets at runtime --> Docker secrets or tmpfs
  +-- node_modules in dev --> Anonymous volume (protect from host)

</decision_framework>


集成指南

Docker 生态系统工具:

  • Docker Scout:使用 docker scout cves 在 CLI 和 CI 中扫描漏洞
  • BuildKit:自 Docker Engine 23+ 起为默认构建引擎,可启用缓存挂载、机密挂载和多平台构建

CI/CD 集成:

Docker 镜像可集成到任何 CI/CD 流水线中。构建和推送模式及漏洞扫描工作流示例请参阅 examples/production.md。

容器编排:

生产镜像适用于任何容器编排器。无论使用何种平台,都必须配置健康检查(HEALTHCHECK 指令)并使用非 root 用户。

替代方案:

  • 基于 VM 的开发环境(Docker Compose 提供更轻量的隔离)
  • 手动配置服务器(Dockerfile 将环境设置过程编入代码)
  • 容器中的 Node 版本管理器(Dockerfile 通过基础镜像标签固定确切的 Node 版本)

<red_flags>

重大风险

高优先级问题:

  • 以 root 身份运行生产容器(默认行为——务必添加 USER 指令)
  • 在 ARG/ENV/COPY 中存放机密信息(会保留在镜像层中——请使用 --mount=type=secret)
  • 使用单阶段构建,将开发依赖和源代码一并打包到生产环境
  • 使用 npm start 作为 CMD(npm 会吞掉 SIGTERM——请使用 CMD ["node", "dist/server.js"])
  • 没有 .dockerignore 文件(node_modules 会发送给守护进程,机密信息会泄漏到镜像中)
  • 基础镜像使用 :latest 标签(构建结果不确定)

中优先级问题:

  • 在 npm ci 之前执行 COPY . .(任何文件变更都会使依赖缓存失效)
  • 未定义健康检查(编排器无法检测无响应的容器)
  • docker-compose.yml 中包含 version: 键(已弃用——请改用不含 version 的 compose.yaml)
  • depends_on 未设置 condition: service_healthy(依赖项就绪前容器便会启动)
  • 在 Dockerfile 中使用 npm install 而不是 npm ci(构建结果不确定,速度更慢)

常见错误:

  • 开发环境中忘记为 node_modules 添加匿名卷(/app/node_modules),导致主机覆盖容器中的模块
  • 在 macOS 上未对绑定挂载使用 :cached(会显著影响性能)
  • 在最终阶段而非构建阶段安装构建工具(gcc、make、python)
  • 在生产环境的 Compose 中将数据库端口暴露给主机(仅开发环境需要)

易错点与边缘情况:

  • Alpine 使用 musl libc——某些带有原生 C 绑定的 npm 包(bcrypt、sharp、canvas)可能会失败;请使用 npm rebuild 或改用 Debian slim
  • Node.js 的 fetch() 从 Node 18+ 起可用(在 Alpine 上的健康检查中无需使用 curl)
  • BuildKit 缓存挂载需要 # syntax=docker/dockerfile:1,或使用默认启用 BuildKit 的 Docker Engine 23+
  • docker compose down -v 会移除具名卷(导致数据丢失)——请使用不带 -v 的 docker compose down 来保留数据
  • macOS/Windows 上的 Docker Desktop 文件系统性能与 Linux 不同——绑定挂载速度更慢
  • COPY --chown 比 COPY + RUN chown 更高效(一层而不是两层)
  • 在 Alpine 上必须显式安装 tini(apk add --no-cache tini)——node:alpine 镜像默认不包含它
  • node_modules/.cache 目录在开发过程中可能变得很大——请将其添加到 .dockerignore

</red_flags>


<critical_reminders>

重要提醒

所有代码都必须遵循项目在 CLAUDE.md 中的约定(kebab-case、命名导出、导入顺序、import type、命名常量)

(生产镜像必须使用多阶段构建——绝不能在生产环境中打包开发依赖、TypeScript 编译器或源文件)

(容器必须以非 root 用户身份运行——绝不能以 root 身份运行生产容器(默认行为))

(必须使用 CMD ["node", "server.js"](exec 格式)——绝不能使用 npm start 或 shell 格式的 CMD)

(构建时必须使用 BuildKit 机密挂载来处理敏感数据——绝不能将 ARG 或 ENV 用于机密信息)

(必须先复制 package.json/lockfile,再复制源代码——绝不能在 npm ci 之前执行 COPY . .(这会破坏层缓存))

不遵循这些规则会导致镜像臃肿(1GB+)、安全漏洞(root 访问权限、机密信息泄漏)、优雅关闭失效(部署时丢失请求)以及 CI 构建缓慢(没有层缓存)。

</critical_reminders>

评论

支持 Markdown