Skip to content

refactor(template): key resources by Dev Container instance (plan 004 Phase A) - #65

Closed
alexanderilyin wants to merge 1 commit into
mainfrom
feat/template-per-instance
Closed

alexanderilyin wants to merge 1 commit into
mainfrom
feat/template-per-instance

Conversation

@alexanderilyin

Copy link
Copy Markdown
Member

Plan 004 Phase A: the template becomes per-instance, as a list of one (main), with no behavior change.

What changed

  • local.instances = { main = { image, registry, name, tag } }, built from devcontainerbuilder_build.workspace (image, resolved_registry, resolved_name, resolved_tag). Phase B swaps this for devcontainerbuilder_build.workspace.images, which has the same fields. local.started_instances is the start_count-gated subset.
  • for_each over instances: data.devcontainerbuilder_devcontainer.workspace, coder_agent.main, the 3 coder_scripts, the 7 coder_envs, coder_app.forwarded_port (keyed "<instance>/<slot>"), module.vscode_web, module.vscode_desktop, kubernetes_persistent_volume_claim_v1.data, kubernetes_deployment_v1.main.
  • Runtime-mapping locals are maps keyed by instance, with the logic unchanged (a mechanical rewrite: local.x becomes local.x[inst]). Resources read them through local.rt[each.key]. The checks aggregate across instances, and their messages are identical for main.
  • Kubernetes: main keeps coder-<ws> and coder-<ws>-data, and all of its labels and its selector (unchanged, because selectors are immutable). Any other instance gets -<id> in its names and in app.kubernetes.io/instance, plus com.deepspacecartel.devcontainer-builder/instance=<id>. Without the app.kubernetes.io/instance change, main's selector would also match their pods. The Deployment's labels, selector and pod labels share one local.deployment_labels.
  • App slugs: main keeps port-<n>, and other instances get <id>-port-<n> (Coder requires slugs to be unique across agents).
  • moved blocks for every old address. Terraform >= 1.1 is needed; the template already requires >= 1.5.

Deviation: the agent is not renamed to dev

Coder names an agent after its Terraform resource name, not a name argument or the for_each key: provisioner/terraform/resources.go ConvertState sets Name: tfResource.Name and errors duplicate agent name when two share it. Renaming the resource to coder_agent.dev would rename every existing workspace's agent to "dev". It stays coder_agent.main.

This blocks Phase B as planned: a for_each over coder_agent with two or more keys fails in Coder with duplicate agent name: main. Running one agent per image needs a different shape, such as statically declared agent slots or coder_devcontainer sub-agents. The per-instance PVC, Deployment, scripts and apps carry over to either shape. The vscode-web and vscode-desktop module slugs would also collide across agents. This is written up in plan 004's status.

Verification (offline, mock providers)

I used a scratch terraform test harness, not committed. It has mock_provider blocks for coder, kubernetes and devcontainerbuilder, and a rich devcontainerbuilder_devcontainer fixture with mounts (including one that collides), ports, customizations.kubernetes, hostRequirements, capAdd and a missing localEnv. For each scenario:

  1. Apply origin/main's main.tf.
  2. Plan this branch against the same state (state_key).
  3. Apply, then plan again.
scenario plan of this branch over origin/main's state re-plan after apply
running workspace 26 moves, 0 to add, 0 to change, 0 to destroy No changes
stopped workspace 9 moves (agent, 7 envs, PVC), 0/0/0 No changes

The plan has no value changes and no sensitivity-mark changes: local.dc keeps one(...), so marks collapse as before. With no value diff, a real provider can't plan a replacement either. Mock providers never report RequiresReplace themselves, which is why the zero-change result is the meaningful one.

A second scratch run with a hypothetical extra backend instance applied cleanly. It got coder-<ws>-backend and coder-<ws>-backend-data, the instance label on its selector only, slugs backend-port-N, and the image …/app-backend:<tag>.

terraform fmt -check and terraform validate pass.

Live check still needed

  1. Push this branch's template as a scratch template version: coder templates push <scratch-template> -d templates/coder-kubernetes, with your usual -vars.
  2. Open an existing workspace on the previous version (running), choose Update, and check the build log's plan:
    • Every line should read has moved to …["main"] (…["main/N"] for ports).
    • The plan should be Plan: 0 to add, 0 to change, 0 to destroy.
    • No must be replaced, and no will be destroyed.
  3. Check that the PVC and the pod survive. kubectl -n <ns> get pvc coder-<ws-id>-data keeps its age. The pod is not recreated, unless Coder's update does stop then start itself; even then the PVC must stay.
  4. The agent is still named main and connects. The apps work: VS Code Web, VS Code Desktop, and forwarded ports.
  5. Restart: stop and start work. Repeat step 2 on a stopped workspace: 9 moves only.

If the template's max_forwarded_ports is above 10, slots 10 and up are recreated rather than moved. That only re-registers the apps in Coder.

🤖 Generated with Claude Code

Plan 004 Phase A: a list of one, with no behavior change. The agent, its
scripts, apps and env, the vscode modules, the PVC, the Deployment and
the devcontainer data source are for_each over local.instances, which is
`main` built from devcontainerbuilder_build.workspace's image and
resolved_* attributes. The runtime-mapping locals are maps keyed by
instance, read through local.rt[each.key]; their logic is unchanged.

The agent stays coder_agent.main: Coder names an agent after its
Terraform resource name, so renaming it would rename existing agents.
`main` keeps its Kubernetes names, labels and selector. moved blocks map
every old address to ["main"]; with mock providers, origin/main's state
plans as moves only, for a running and a stopped workspace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 7, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 03ee0d74-82f6-45d0-8c11-3b93068f7f67
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@alexanderilyin

Copy link
Copy Markdown
Member Author

Abandoned: multiple Dev Container configurations are dropped before 1.0 (see the revert of #60).

@alexanderilyin
alexanderilyin deleted the feat/template-per-instance branch October 8, 2026 01:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant