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
- •Existing Compose? Prefer Compose for multi-service or dev orchestration.
- •Single service? Dockerfile-only is acceptable if no orchestration is needed.
- •Need dev tooling, volumes, ports, envs? Compose is usually better.
- •Ambiguous? Default to Compose with a minimal Dockerfile.
Local vs remote (Cloudflare)
- •Rebuild and restart (
docker compose build,docker compose up,docker compose downthenup) 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--localflag applies migrations to the local D1 database thatwrangler devuses (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--localmigrations with deployment.
Step-by-Step Workflows
1. Dockerfile / Compose Creation
- •Identify entrypoint, ports, and runtime (Node, .NET, Python, etc.) and any system/dependency requirements.
- •Choose base image: use an official image and pin major/minor version when possible.
- •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.
- •Optional Compose: If using Compose, create
compose.yaml(ordocker-compose.yml) with explicitservices,ports,volumes, andenvironment; use bind mounts for source in dev and named volumes for data. - •Secrets and env: Keep secrets out of images; use
.envand provide.env.examplein repo; document required variables. - •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
- •Canonical config in repo: Keep
Dockerfileandcompose.yaml(ordocker-compose.yml) as the source of truth in the repo. - •Local overrides: Use
.envfor local values; track.env.examplein repo with documented defaults and required vars. - •Compose overrides: Use
compose.override.yamlfor local-only changes (extra ports, debug env, etc.); add it to.gitignore. - •Document: Record all defaults and override behavior in README or a dedicated dev doc.
- •Checklist:
- • Repo has
compose.yamland/orDockerfile; no secrets in committed files. - •
.env.examplecommitted;.envandcompose.override.yamlgitignored. - • Defaults and override strategy documented.
- • Repo has
3. Execution (Build and Run)
- •Build: From project root, run
docker build -t app-dev .ordocker compose build. - •Run:
docker run --rm -p HOST:CONTAINER app-devfor a single image, ordocker compose upfor Compose. - •Verify: Hit a health endpoint or run a minimal CLI command to confirm the app starts.
- •Optional: Use
docker compose up -dfor 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.
- •Named container: The API service must use container name
win-podiums-com-containerincompose.yamlso the same name is used everywhere and can be torn down reliably. - •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. - •Compose down: Run
docker compose downso this project’s stack (network, etc.) is removed. Usedocker compose down --volumesonly when you want to wipe local data (e.g. D1 state). - •Then: Run
docker compose build(ordocker compose build SERVICE) and thendocker compose up(ordocker compose up -d). - •Document: In any "prepare fresh environment" or runbook, include: "Run
docker rm -f win-podiums-com-container, thendocker 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.
- •Start: Run
docker compose up -d(ordocker 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. Usedocker compose up(foreground) only if the user explicitly wants logs in the terminal. - •Verify: Optionally hit the health endpoint (e.g.
GET /api/health) to confirm the service is ready. - •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.
- •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).
- •Build: From repo root, run
dotnet build apps/plugin/WinPodiums.Plugin/WinPodiums.Plugin.csproj --configuration Release(or Debug). - •Deploy: Copy the built DLL from
apps/plugin/WinPodiums.Plugin/bin/Release/net48/WinPodiums.Plugin.dll(andNewtonsoft.Json.dllfrom the same folder if the plugin needs it) toC:\Program Files (x86)\SimHub\(SimHub install root; the only deploy path this repo supports). Copying to Program Files usually requires running PowerShell as Administrator. - •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.
- •Find SimHub process(es): On Windows, run
Get-Process -Name "SimHub*" -ErrorAction SilentlyContinueand, if the executable path is available,Get-Process | Where-Object { $_.Path -like "*SimHub*" }to catch any process running from the SimHub install folder. - •Stop them: For each process found, run
Stop-Process -Id <id> -Force(orStop-Process -Name "SimHub*" -Force). Be aggressive—close SimHub so the DLL is not locked. - •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.
- •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
- •Shell: Attach a shell with
docker compose exec SERVICE sh(orbashif available). - •Logs: Stream logs with
docker compose logs -f SERVICE(ordocker logs -f CONTAINER). - •Environment: Inspect env with
docker compose exec SERVICE env(ordocker exec CONTAINER env). - •Networks: List networks with
docker network ls; inspect withdocker network inspect NETWORK. - •State: Use
docker ps -ato see all containers and their status.
5. Monitoring
- •Resource usage: Run
docker statsfor live CPU/memory. - •Container state: Use
docker ps -afor status and exit codes. - •Disk usage: Run
docker system dfto see space used by images, containers, volumes. - •Cleanup: For dev,
docker compose down --volumesonly 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):
- •Before building: Close SimHub completely. If SimHub is running, it may lock plugin DLLs and cause build or copy issues.
- •Build: From repo root, run
dotnet build apps/plugin/WinPodiums.Plugin/WinPodiums.Plugin.csproj(or use your IDE). - •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).
- •Deploy: Once SimHub is verified closed, copy the built DLL (e.g. from
apps/plugin/WinPodiums.Plugin/bin/Release/net48/orDebug/net48/) andNewtonsoft.Json.dllif needed toC:\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. - •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.exampleprovided.
Dockerfile
- • Official base, pinned version; minimal layers; non-root when feasible; healthcheck if applicable.
Compose
- •
compose.yamlordocker-compose.yml; explicit services, ports, volumes, environment; container_name: win-podiums-com-container for the API service; bind mounts for source in dev;profilesfor 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-pullwhen images are cached and pinned.
Stack-specific
- •.NET: Run
dotnet testinside the built container to match runtime. - •Cloudflare Workers: Run
npm testorwrangler testin 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
.envorcompose.override.yamlwith secrets or machine-specific values. - •Do not run production-only workflows (e.g. full K8s) unless the user asks.
Additional Resources
- •Official Docker best practices and curated links: reference.md
- •Common templates and examples: examples.md