Communitygithub.com

Docker 模式

本地开发、加固 CLI 安装程序、容器安全、网络、卷和多服务编排的 Docker 与 Docker Compose 模式。用于创建或审查 Dockerfile 和 Compose 服务、跨 Linux 发行版测试安装程序,或规划准确的本地 macOS 和 Windows 验证。

Docker 模式 是什么?

该技能提供了 Docker 和 Docker Compose 的全面最佳实践集,涵盖本地开发、容器安全、网络、卷管理和多服务编排。它包含了标准 Web 应用栈和开发与生产 Dockerfile 的详细 YAML 配置示例,以及用于调试和性能优化的常见模式。该技能还特别强调了跨平台兼容性,提供了在 Linux、macOS 和 Windows 环境下正确测试 CLI 安装程序的指导,包括加固的 Docker 容器化测试流程。它通过清晰的规则(如不可变镜像摘要、只读挂载和隔离开关)强制执行隔离合约,并支持 ECC 插件设置等工具的无网络测试。整体而言,该技能帮助开发者和 AI 代理避免常见反模式,构建更安全、可移植和可维护的容器化工作流。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/docker-patterns

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Docker 模式 是做什么的?

容器化开发的 Docker 和 Docker Compose 最佳实践。

用于本地开发的 Docker Compose

标准 Web 应用栈

# docker-compose.yml
services:
  app:
    build:
      context: .
      target: dev                     # 使用多阶段 Dockerfile 的 dev 阶段
    ports:
      - "3000:3000"
    volumes:
      - .:/app                        # 用于热重载的绑定挂载
      - /app/node_modules             # 匿名卷 -- 保留容器依赖
    environment:
      - DATABASE_URL=postgres://postgres:postgres@db:5432/app_dev
      - REDIS_URL=redis://redis:6379/0
      - NODE_ENV=development
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    command: npm run dev

  db:
    image: postgres:16-alpine
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: app_dev
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redisdata:/data

  mailpit:                            # 本地邮件测试
    image: axllent/mailpit
    ports:
      - "8025:8025"                   # Web UI
      - "1025:1025"                   # SMTP

volumes:
  pgdata:
  redisdata:

开发与生产 Dockerfile

# 阶段:依赖
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

# 阶段:开发(热重载,调试工具)
FROM node:22-alpine AS dev
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]

# 阶段:构建
FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build && npm prune --production

# 阶段:生产(最小镜像)
FROM node:22-alpine AS production
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001
USER appuser
COPY --from=build --chown=appuser:appgroup /app/dist ./dist
COPY --from=build --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=build --chown=appuser:appgroup /app/package.json ./
ENV NODE_ENV=production
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]

覆盖文件

# docker-compose.override.yml(自动加载,仅用于开发设置)
services:
  app:
    environment:
      - DEBUG=app:*
      - LOG_LEVEL=debug
    ports:
      - "9229:9229"                   # Node.js 调试器

# docker-compose.prod.yml(显式用于生产)
services:
  app:
    build:
      target: production
    restart: always
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
# 开发(自动加载覆盖)
docker compose up

# 生产
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

网络

服务发现

同一 Compose 网络中的服务通过服务名解析:

# 从 "app" 容器中:
postgres://postgres:postgres@db:5432/app_dev    # "db" 解析到 db 容器
redis://redis:6379/0                             # "redis" 解析到 redis 容器

自定义网络

services:
  frontend:
    networks:
      - frontend-net

  api:
    networks:
      - frontend-net
      - backend-net

  db:
    networks:
      - backend-net              # 只能从 api 访问,不能从 frontend 访问

networks:
  frontend-net:
  backend-net:

仅暴露所需端口

services:
  db:
    ports:
      - "127.0.0.1:5432:5432"   # 仅从宿主机可访问,不能从网络访问
    # 生产环境完全省略 ports —— 仅在 Docker 网络内可访问

卷策略

volumes:
  # 命名卷:跨容器重启持久化,由 Docker 管理
  pgdata:

  # 绑定挂载:将宿主机目录映射到容器中(用于开发)
  # - ./src:/app/src

  # 匿名卷:保留容器生成的内容,防止被绑定挂载覆盖
  # - /app/node_modules

常见模式

services:
  app:
    volumes:
      - .:/app                   # 源代码(用于热重载的绑定挂载)
      - /app/node_modules        # 保护容器内的 node_modules 不受宿主机影响
      - /app/.next               # 保护构建缓存

  db:
    volumes:
      - pgdata:/var/lib/postgresql/data          # 持久化数据
      - ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql  # 初始化脚本

容器安全

Dockerfile 加固

# 1. 使用特定标签(绝不使用 :latest)
FROM node:22.12-alpine3.20

# 2. 以非 root 用户运行
RUN addgroup -g 1001 -S app && adduser -S app -u 1001
USER app

# 3. 丢弃能力(在 compose 中)
# 4. 尽可能使用只读根文件系统
# 5. 镜像层中不包含密钥

Compose 安全

services:
  app:
    security_opt:
      - no-new-privileges:true
    read_only: true
    tmpfs:
      - /tmp
      - /app/.cache
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE          # 仅当绑定到小于 1024 的端口时需要

密钥管理

# 好的做法:使用环境变量(运行时注入)
services:
  app:
    env_file:
      - .env                     # 切勿将 .env 提交到 git
    environment:
      - API_KEY                  # 从宿主机环境继承

# 好的做法:Docker 密钥(Swarm 模式)
secrets:
  db_password:
    file: ./secrets/db_password.txt

services:
  db:
    secrets:
      - db_password

# 坏的做法:硬编码在镜像中
# ENV API_KEY=sk-proj-xxxxx      # 绝不要这样做

加固 CLI 安装程序

使用容器测试安装程序在可丢弃的项目副本上的行为,而不允许测试修改源代码检出。

尊重平台边界

  • 为 Linux 发行版(如 Debian 和 Ubuntu)运行真实的容器。
  • macOS 不能作为 Docker 容器运行,因为 Docker 共享 Linux 内核。在 macOS 本地运行相同的无 shell 测试入口点。
  • Windows 容器需要 Windows Docker 引擎。在原生 Windows CI 运行器上运行平台无关的逻辑,并将 Windows 容器保留给 Windows 宿主机。
  • 保留原生 Ubuntu/macOS/Windows CI 矩阵,用于特定于宿主机的路径、命令 shim、引号和文件系统行为。

不要声称 Linux 容器验证了 macOS 或 Windows 的行为。

强制执行隔离合约

  • 按不可变摘要固定基础镜像,并固定安装的 CLI 版本。
  • 当发行版帐户名不同时,以非 root 数字 UID/GID 运行。
  • 以只读方式挂载仓库和源项目。
  • 在进行任何修改之前,将源项目复制到可写的 tmpfs 工作区中。
  • 使用 noexec、UID/GID 1000 和 mode=0700 挂载 /workspace,以便只有容器用户可以检查项目数据。
  • 将 npm 和 npx 的可执行缓存保留在 NPM_CONFIG_CACHE=/tmp/npm-cache 的可执行 /tmp 挂载点上。其默认大小为 2 GiB,可通过 ECC_TMPFS_SIZE 调整;ECC_WORKSPACE_SIZE 单独控制私有工作区挂载。
  • 设置 read_only: true、no-new-privileges:true、cap_drop: [ALL] 和一个有限的 pids_limit。
  • 将默认的真实 CLI 服务保留在 network_mode: none 上。仅通过一个明确命名的选择加入服务(用于经过身份验证的提供程序会话)添加网络访问;切勿使其成为意外的环境驱动默认值。
  • 仅创建工具所需的可写临时路径。
  • 默认情况下不要将宿主机凭据传递到容器中。
  • 默认进行空运行,仅将显式的 dry-run、install、plugin 和 shell 模式列入白名单。
  • 对跨平台运行器使用参数数组或 spawnSync(..., { shell: false })。切勿将项目路径插入 shell 命令。

使用 ECC 插件设置

使用 docker/plugin-setup/compose.yaml 作为参考实现。它提供:

  • fixture-tests 用于聚焦的安装清单、目标和执行器套件。
  • real-cli 用于固定的基于 Debian 的通用 Linux 镜像。
  • real-cli-ubuntu 用于固定的 Ubuntu 镜像。

在构建前验证 Compose 模型:

docker compose -f docker/plugin-setup/compose.yaml config --quiet

构建两个真实的 Linux 镜像:

docker compose -f docker/plugin-setup/compose.yaml \
  build real-cli real-cli-ubuntu

在每个镜像中运行安全的默认流程:

docker compose -p ecc-plugin-debian-test \
  -f docker/plugin-setup/compose.yaml \
  run --rm -T real-cli dry-run

docker compose -p ecc-plugin-ubuntu-test \
  -f docker/plugin-setup/compose.yaml \
  run --rm -T real-cli-ubuntu dry-run

空运行执行当前的公共命令合约:

ecc install --profile core --target claude-project --dry-run --json

在该命令运行之前,容器使用 npm pack --ignore-scripts 从只读检出创建本地打包的 npm 工件。它将自创建的 tarball 提取到 /tmp 下,验证 ecc-universal 包名、必需的安装清单和受限的 package.json bin.ecc 映射,然后调用提取的 ecc 可执行文件。运行时保持在 network_mode: none 上,不执行包生命周期脚本,不依赖宿主机 node_modules;其精确固定的生产依赖已存在于镜像中。

该框架拒绝空计划、非 claude-project 目标、/workspace/project/.claude 之外的任何操作,或创建目标目录的任何空运行。install 执行两次隔离的 apply、检查其管理的安装状态、列出已安装的目标并运行 doctor。

启动、打开、重新连接和清理命名会话

启动一个不带 --rm 的后台容器,以便离开终端不会删除会话:

docker compose -p ecc-plugin-session \
  -f docker/plugin-setup/compose.yaml \
  run --detach --name ecc-plugin-shell real-cli shell

容器将只读固定装置复制到稳定的私有目录 /workspace/project。确认它正在运行,然后发出终端开启器 v1 数据合约的 Docker 部分:

docker inspect --format '{{.State.Running}}' ecc-plugin-shell
node docker/plugin-setup/interactive-plan.js \
  --container ecc-plugin-shell \
  --workdir /workspace/project \
  --json \
  -- bash

JSON 结果仅包含一个 executable 和 argv 边界(加上 contractVersion: 1):可执行文件是 docker,argv 以 exec、-it 和 -w 开头。当单独的终端开启器技能安装后,将这些数据传递给它。此 Docker 框架有意不导入终端适配器、插入 shell 命令或管理宿主机 GUI 进程。在此之前,直接在当前的宿主机终端中打开相同的 PTY:

docker exec -it -w /workspace/project ecc-plugin-shell bash

退出 shell 而不停止后台容器。使用相同的 docker exec -it 命令重新连接。完成后,删除确切命名的容器及其 Compose 项目资源:

docker rm --force ecc-plugin-shell
docker compose -p ecc-plugin-session \
  -f docker/plugin-setup/compose.yaml \
  down --remove-orphans

默认情况下缺少宿主机凭据,并且从不挂载凭据目录。默认服务也没有网络访问权限。当经过身份验证的提供程序会话确实需要网络时,首先构建 real-cli,然后使用 docker compose --profile networked run real-cli-networked shell 显式选择加入。更喜欢在该一次性会话中进行身份验证。如果 CI 运行必须继承宿主机环境凭据,请在调用时使用显式的 Compose --env NAME 标志使其选择加入,了解该值可被检查,并可在容器生命周期内被泄露,并立即移除确切命名的容器。

在宿主机上本地运行相同的聚焦套件:

npm run test:plugin-setup-platform

在信任镜像之前检查生成的身份和环境:

docker image inspect ecc-plugin-setup:debian ecc-plugin-setup:ubuntu

清理每个命名的测试项目,而不删除无关的卷或镜像:

docker compose -p ecc-plugin-debian-test \
  -f docker/plugin-setup/compose.yaml down --remove-orphans
docker compose -p ecc-plugin-ubuntu-test \
  -f docker/plugin-setup/compose.yaml down --remove-orphans

.dockerignore

node_modules
.git
.env
.env.*
dist
coverage
*.log
.next
.cache
docker-compose*.yml
Dockerfile*
README.md
tests/

调试

常用命令

# 查看日志
docker compose logs -f app           # 跟踪 app 日志
docker compose logs --tail=50 db     # db 的最后 50 行

# 在运行的容器中执行命令
docker compose exec app sh           # 进入 app 的 shell
docker compose exec db psql -U postgres  # 连接到 postgres

# 检查
docker compose ps                     # 正在运行的服务
docker compose top                    # 每个容器中的进程
docker stats                          # 资源使用情况

# 重新构建
docker compose up --build             # 重新构建镜像
docker compose build --no-cache app   # 强制完全重新构建

# 清理
docker compose down                   # 停止并移除容器
docker compose down -v                # 也移除卷(破坏性操作)
docker system prune                   # 移除未使用的镜像/容器

调试网络问题

# 检查容器内的 DNS 解析
docker compose exec app nslookup db

# 检查连接
docker compose exec app wget -qO- http://api:3000/health

# 检查网络
docker network ls
docker network inspect <project>_default

反模式

# 不好:使用 :latest
# 注意:以上示例中,"# 注意:" 部分用于说明,但反模式列表通常以具体示例形式给出。为保持一致性,此处保留原始结构,但您可以根据需要调整文本。
# BAD: Hardcoded secrets in Dockerfile
# 不好:硬编码密钥在 Dockerfile 中
# ENV API_KEY=sk-proj-xxxxx      # 绝不要这样做
# BAD: Using root user
# 不好:使用 root 用户
# USER root  # 省略此行或使用 USER appuser

最佳实践摘要

  • 使用特定镜像标签(绝不使用 :latest)。
  • 以非 root 用户运行应用程序。
  • 对多阶段构建使用开发和生产目标。
  • 使用 Compose 覆盖文件分离开发和生产配置。
  • 为健康检查、重启策略和资源限制配置服务。
  • 使用自定义网络进行服务隔离。
  • 使用命名卷进行持久化数据,使用绑定挂载进行开发。
  • 保护容器免受权限升级和凭据泄露的影响。
  • 使用 .dockerignore 减小构建上下文大小并防止敏感文件被复制。

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

相关技能