AgentSkillsCN

docker-dev-environment

采用官方 Docker 最佳实践,标准化基于 Docker 的开发环境。当用户提及 Docker、Dockerfile、Docker Compose、容器化开发环境、本地/仓库一致性、准备环境、清理环境、“让 API 正常运行”、compose up/down、win-podiums-com-container,或请求 Docker 测试自动化、搭建、管理、调试、监控,或在本地及 CI 中验证开发容器时,可使用此功能。

SKILL.md
--- frontmatter
name: docker-dev-environment
description: Standardizes Docker-based development environments using official Docker best practices. Use when the user mentions Docker, Dockerfile, Docker Compose, containerized dev environment, local/repo parity, prepare env, tear down, "get the API running", compose up/down, win-podiums-com-container, or requests Docker test automation, set up, manage, debug, monitor, or validate dev containers locally and in CI.

Docker Dev Environment

Quick Start

Use this skill when the user asks to create or standardize a Docker or Docker Compose setup, achieve local/repo parity for a containerized dev environment, or to debug, monitor, or validate dev containers locally and in CI.

Flow: (1) Detect existing Docker artifacts. (2) Choose minimal setup (Dockerfile-only vs Compose). (3) Ensure local and repo config stay in parity. (4) When preparing env or running build/up: tear down all Docker API envs first—remove the named container win-podiums-com-container (from any worktree), then docker compose down, then build and up so only one API container runs (see §3a). (5) Prepare env also includes building and deploying the SimHub plugin (see §3c): actively stop SimHub (Stop-Process), verify it is closed (Get-Process; do not proceed until zero SimHub processes), then build and copy the plugin to the SimHub install root. (6) Use container name win-podiums-com-container in Compose so the same name is used everywhere. (7) Provide run/debug/monitor workflows and verify them. (8) Define local and CI tests for Docker stability.

ContextStream (when available): Before changing Docker/Compose, use ContextStream search for "Docker", "compose", "wrangler", "Worker" to find existing setup and parity decisions. After Docker/parity decisions, capture in ContextStream (event_type=decision) with path to Dockerfile, compose.yaml, or docs/guides/development.md.

Scope

  • In scope: Dockerfile and Docker Compose creation, local/repo config parity, execution (build/run), debugging (shell, logs, env, networks), monitoring (stats, state, disk, cleanup), and validation in CI.
  • Out of scope: Production orchestration (e.g. Kubernetes) unless the user explicitly asks; image registry publishing; non-Docker dev environments. For change control and secrets in repo config, see github-change-control skill.

Best-Practices Sources

When creating or updating Dockerfile and Compose files, consult official Docker documentation as the standard:

  • Docker: Dockerfile reference, best practices for writing Dockerfiles, and engine documentation at docs.docker.com.
  • Compose: Compose file specification and best practices at docs.docker.com/compose.

See reference.md for curated links to specific Docker and Compose docs. Do not invent patterns; align to official Docker best practices.

Decision Flow

  1. Existing Compose? Prefer Compose for multi-service or dev orchestration.
  2. Single service? Dockerfile-only is acceptable if no orchestration is needed.
  3. Need dev tooling, volumes, ports, envs? Compose is usually better.
  4. Ambiguous? Default to Compose with a minimal Dockerfile.

Local vs remote (Cloudflare)

  • Rebuild and restart (docker compose build, docker compose up, docker compose down then up) are entirely local. Nothing is deployed to Cloudflare.
  • Commands in the container CMD (e.g. wrangler d1 migrations apply DB_NAME --local) run inside the dev environment. The --local flag applies migrations to the local D1 database that wrangler dev uses (SQLite in the container). That does not create or update D1 on Cloudflare.
  • Deploying to Cloudflare is a separate step: e.g. wrangler deploy, and when you want the remote DB schema, wrangler d1 migrations apply DB_NAME --remote (run from host or CI, not necessarily from the dev container). Do not conflate container rebuild/restart or --local migrations with deployment.

Step-by-Step Workflows

1. Dockerfile / Compose Creation

  1. Identify entrypoint, ports, and runtime (Node, .NET, Python, etc.) and any system/dependency requirements.
  2. Choose base image: use an official image and pin major/minor version when possible.
  3. Dockerfile: Use multi-stage builds when build-only deps differ from runtime; minimize layers; copy dependency manifests before app code for cache; do not bake secrets into the image.
  4. Optional Compose: If using Compose, create compose.yaml (or docker-compose.yml) with explicit services, ports, volumes, and environment; use bind mounts for source in dev and named volumes for data.
  5. Secrets and env: Keep secrets out of images; use .env and provide .env.example in repo; document required variables.
  6. Checklist before finishing:
    • Official base image and pinned version.
    • Multi-stage used when appropriate; final image has no build-only deps.
    • WORKDIR set; only needed files copied; build cache leveraged.
    • Non-root user when feasible; healthcheck if the app has a stable local endpoint.

2. Local / Repo Config Parity

  1. Canonical config in repo: Keep Dockerfile and compose.yaml (or docker-compose.yml) as the source of truth in the repo.
  2. Local overrides: Use .env for local values; track .env.example in repo with documented defaults and required vars.
  3. Compose overrides: Use compose.override.yaml for local-only changes (extra ports, debug env, etc.); add it to .gitignore.
  4. Document: Record all defaults and override behavior in README or a dedicated dev doc.
  5. Checklist:
    • Repo has compose.yaml and/or Dockerfile; no secrets in committed files.
    • .env.example committed; .env and compose.override.yaml gitignored.
    • Defaults and override strategy documented.

3. Execution (Build and Run)

  1. Build: From project root, run docker build -t app-dev . or docker compose build.
  2. Run: docker run --rm -p HOST:CONTAINER app-dev for a single image, or docker compose up for Compose.
  3. Verify: Hit a health endpoint or run a minimal CLI command to confirm the app starts.
  4. Optional: Use docker compose up -d for detached mode; document how to stop (docker compose down).

3a. Prepare env — tear down all Docker API envs first

A running container (from this worktree, another worktree, or a manual run) can cause multiple API containers, port conflicts, or stale state. Always tear down all API envs before build/up so only one container runs.

  1. Named container: The API service must use container name win-podiums-com-container in compose.yaml so the same name is used everywhere and can be torn down reliably.
  2. Remove named container: Run docker rm -f win-podiums-com-container (ignore errors if the container does not exist). This stops and removes the container from any worktree or previous run.
  3. Compose down: Run docker compose down so this project’s stack (network, etc.) is removed. Use docker compose down --volumes only when you want to wipe local data (e.g. D1 state).
  4. Then: Run docker compose build (or docker compose build SERVICE) and then docker compose up (or docker compose up -d).
  5. Document: In any "prepare fresh environment" or runbook, include: "Run docker rm -f win-podiums-com-container, then docker compose down, then build and up."

When implementing prepare-env (e.g. in scripts or agent flows), always run in order: (1) docker rm -f win-podiums-com-container, (2) docker compose down, (3) build, (4) up (prefer up -d).

3b. Prepare env includes starting the stack

Prepare env means the user ends with a running dev environment. After down (if needed), secrets check, and build, start the stack so the app is up and reachable.

  1. Start: Run docker compose up -d (or docker compose up SERVICE -d) so containers run in the background; the user can then hit the health endpoint or use the app without keeping a terminal attached. Use docker compose up (foreground) only if the user explicitly wants logs in the terminal.
  2. Verify: Optionally hit the health endpoint (e.g. GET /api/health) to confirm the service is ready.
  3. Document: In "prepare fresh environment" or runbooks, state that the final step is starting the stack (docker compose up -d) so the env is ready to use.

When implementing prepare-env, the sequence is: tear down all API envs (docker rm -f win-podiums-com-container, then docker compose down) → secrets/config → build → up (prefer up -d so the env is running when done).

3c. Prepare env includes SimHub plugin (build and deploy)

Prepare env for this repo also means the SimHub plugin is built and deployed so the full dev environment (API + plugin) is ready.

  1. Stop SimHub first. If SimHub is not stopped, it locks the existing plugin DLL in the SimHub install folder and the copy will fail (cannot overwrite). Agents must actively stop SimHub and verify it is closed before deploy (see Agent implementation below).
  2. Build: From repo root, run dotnet build apps/plugin/WinPodiums.Plugin/WinPodiums.Plugin.csproj --configuration Release (or Debug).
  3. Deploy: Copy the built DLL from apps/plugin/WinPodiums.Plugin/bin/Release/net48/WinPodiums.Plugin.dll (and Newtonsoft.Json.dll from the same folder if the plugin needs it) to C:\Program Files (x86)\SimHub\ (SimHub install root; the only deploy path this repo supports). Copying to Program Files usually requires running PowerShell as Administrator.
  4. Verify: User can start SimHub and confirm the plugin appears in the plugin list and (when enabled) in the left feature menu.

When implementing prepare-env including the plugin, after Docker (tear down → build → up): ensure SimHub is stopped (stop process, then verify) → build plugin → deploy plugin DLL(s) to SimHub install root. Do not move on from the "SimHub stopped" step until it is verified closed.

Agent implementation (mandatory): Before running the plugin copy, you must ensure SimHub is closed and verify it. Do not proceed to the copy step until verification passes.

  1. Find SimHub process(es): On Windows, run Get-Process -Name "SimHub*" -ErrorAction SilentlyContinue and, if the executable path is available, Get-Process | Where-Object { $_.Path -like "*SimHub*" } to catch any process running from the SimHub install folder.
  2. Stop them: For each process found, run Stop-Process -Id <id> -Force (or Stop-Process -Name "SimHub*" -Force). Be aggressive—close SimHub so the DLL is not locked.
  3. Verify closed: Re-run the same Get-Process check. If any SimHub process still exists, do not run the copy. Tell the user: "SimHub is still running (process …). Close it manually (Task Manager if needed), then tell me and I'll run the deploy again." Do not move on from this step until the check shows zero SimHub processes.
  4. Only then deploy: When verification shows no SimHub process, run the Copy-Item to the SimHub install root.

Never run the copy first and then explain the lock error. The "SimHub stopped" step is blocking: you do not proceed to build/deploy the plugin copy until SimHub is verified closed.

4. Debugging

  1. Shell: Attach a shell with docker compose exec SERVICE sh (or bash if available).
  2. Logs: Stream logs with docker compose logs -f SERVICE (or docker logs -f CONTAINER).
  3. Environment: Inspect env with docker compose exec SERVICE env (or docker exec CONTAINER env).
  4. Networks: List networks with docker network ls; inspect with docker network inspect NETWORK.
  5. State: Use docker ps -a to see all containers and their status.

5. Monitoring

  1. Resource usage: Run docker stats for live CPU/memory.
  2. Container state: Use docker ps -a for status and exit codes.
  3. Disk usage: Run docker system df to see space used by images, containers, volumes.
  4. Cleanup: For dev, docker compose down --volumes only when data is disposable; document which volumes are safe to remove.

6. Local deployment — SimHub plugin (host-only)

When building and deploying the SimHub plugin DLL on the host (no Docker for the plugin):

  1. Before building: Close SimHub completely. If SimHub is running, it may lock plugin DLLs and cause build or copy issues.
  2. Build: From repo root, run dotnet build apps/plugin/WinPodiums.Plugin/WinPodiums.Plugin.csproj (or use your IDE).
  3. Before deploying: ensure SimHub is stopped and verified. Agents must actively stop SimHub (Stop-Process -Force), then re-check with Get-Process; do not run the copy until verification shows zero SimHub processes. See §3c Agent implementation for the exact steps (find → stop → verify → then deploy).
  4. Deploy: Once SimHub is verified closed, copy the built DLL (e.g. from apps/plugin/WinPodiums.Plugin/bin/Release/net48/ or Debug/net48/) and Newtonsoft.Json.dll if needed to C:\Program Files (x86)\SimHub\ (SimHub install root; the only SimHub deploy path this repo supports). Copying to Program Files usually requires running PowerShell as Administrator.
  5. Verify: Start SimHub and confirm the plugin appears in the plugin list and (when enabled) in the left feature menu.

Include this sequence in any local deployment setup or runbook that involves the SimHub plugin. When prepare env includes the plugin (see §3c), always ensure SimHub is stopped before deploy.


Implementation Checklist (Summary)

Repo Baseline

  • Entrypoint, ports, and runtime confirmed; dependencies and base image chosen.
  • Multi-stage used when appropriate; secrets not in images; .env.example provided.

Dockerfile

  • Official base, pinned version; minimal layers; non-root when feasible; healthcheck if applicable.

Compose

  • compose.yaml or docker-compose.yml; explicit services, ports, volumes, environment; container_name: win-podiums-com-container for the API service; bind mounts for source in dev; profiles for optional services; local overrides in gitignored file.

Testing Workflow

  • Before pushing to a remote branch: Run local tests; at least 80% of tests must pass. See Run tests before push and AGENTS.md. Block or warn on push if the threshold is not met.

Local (Docker environment validation)

  • Build image(s) and start container(s) cleanly.
  • Run a minimal smoke test (health endpoint or one CLI command).
  • Verify volumes and permissions on mounted paths.
  • Validate env defaults and required overrides.
  • Confirm graceful shutdown and clean teardown.

CI (e.g. GitHub Actions)

  • Use BuildKit and layer cache (cache-from/cache-to) to speed builds.
  • Reuse service containers where possible; avoid redundant builds.
  • Split fast smoke tests from slower integration tests; use path filters for workflows.
  • Use --no-pull when images are cached and pinned.

Stack-specific

  • .NET: Run dotnet test inside the built container to match runtime.
  • Cloudflare Workers: Run npm test or wrangler test in a Node-based image.
  • SimHub plugin (host): Close SimHub before building the plugin DLL; stop SimHub before deploying (if not stopped, SimHub locks the plugin DLL and the copy fails). See Local deployment — SimHub plugin and Prepare env includes SimHub plugin.
  • Use Compose-based integration tests only when dependencies are required.

Output Expectations

When making changes, provide:

  • A minimal Dockerfile and/or Compose file.
  • A short run/debug/monitor checklist (or pointer to the workflows above).
  • Local and CI test checklist for Docker stability.
  • Notes on local overrides and secrets handling.

If the user requests only guidance, provide docs and checklists without editing files.

Anti-Patterns

  • Do not bake secrets or long-lived credentials into images.
  • Do not skip official Docker best practices when writing Dockerfile or Compose.
  • Do not commit .env or compose.override.yaml with secrets or machine-specific values.
  • Do not run production-only workflows (e.g. full K8s) unless the user asks.

Additional Resources