Skip to content

refactor(devcontainer): Dockerfile-only + gitignored devcontainer.json for devpod compatibility#687

Merged
takaokouji merged 7 commits into
developfrom
fix/devcontainer-devpod-build-context
May 12, 2026
Merged

refactor(devcontainer): Dockerfile-only + gitignored devcontainer.json for devpod compatibility#687
takaokouji merged 7 commits into
developfrom
fix/devcontainer-devpod-build-context

Conversation

@takaokouji
Copy link
Copy Markdown

Summary

devpod で devpod up . を実行したとき以下のエラーで失敗する問題の修正:

target app: failed to solve: failed to compute cache key:
failed to calculate checksum of ref ... : "/entrypoint.sh": not found

Root cause

devpod は docker-compose ベースの devcontainer をビルドするとき、基底の docker-compose.ymlbuild: . 形式の context を正しく継承できず、.devcontainer/ 配下を build context と誤認する。結果として Dockerfile の COPY entrypoint.sh /app/entrypoint.sh が repo root の entrypoint.sh を見つけられず失敗する。

VS Code Dev Containers では同じ設定で問題なく動作するが、devpod は明示的に context を指定する必要があった。

Fix

.devcontainer/docker-compose.devcontainer.ymlapp サービスに build セクションを明示的に追加:

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile

docker compose の relative path 解決ルールでは、-f で指定された 最初 の compose ファイルの場所からの相対パスとして解釈される。基底 (docker-compose.yml) は repo root にあるため、context: . は repo root に解決される。これにより devpod / VS Code 両方で entrypoint.sh が正しく COPY される。

Test plan

  • ローカルで docker compose -f docker-compose.yml -f .devcontainer/docker-compose.devcontainer.yml config app を実行し、build.context が <repo root> に解決されることを確認
  • ローカルで docker compose ... build app を実行し、entrypoint.sh が正しく COPY されてビルドが成功することを確認
  • devpod で devpod up . が成功することを確認 (PR 提出者にて実施)
  • VS Code Reopen in Container が引き続き動作することを確認 (リグレッションなしの確認)

devpod は docker-compose に基づく devcontainer をビルドするとき、基底の
docker-compose.yml の build: . の context を正しく継承できず、
.devcontainer/ ディレクトリを context と誤認していた。結果 COPY 命令が
entrypoint.sh: not found で失敗する。

VS Code Dev Containers では同じ設定で動作するが、devpod では明示的に
context を指定する必要があった。

overlay 側で build.context: . を明示的に設定。compose の relative path 解決
ルールにより . は base compose file の場所 (= repo root) に解決され、
両ツールで同じ build context が使われる。

ローカルで docker compose build を実行して entrypoint.sh が正しく
COPY されることを確認済み。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

devcontainer features (claude-code, github-cli) を devpod の docker-compose
ベース devcontainer で使うと、features が生成する Dockerfile-with-features の
build context が壊れて COPY entrypoint.sh が \"/entrypoint.sh: not found\" で
失敗する。前段の build context 修正 (commit 8524937) は VS Code 側には
有効だが devpod ではまだ失敗していた。

VS Code Dev Containers では features がそのまま動くため、devpod 固有の
ラッパービルド処理に起因するバグと思われる。

回避策として features は使わず、post-create.sh で同等のインストールを行う:

- gh CLI: apt 経由で公式リポジトリから install (Debian bookworm 用 GPG 鍵登録)
- claude (Claude Code): npm install -g @anthropic-ai/claude-code

ローカルでコンテナに入って post-create.sh を実行し、gh 2.92.0 / Claude
Code 2.1.138 がインストールされることを確認済み。

副作用:
- devcontainer-lock.json は features 用なので不要、削除
- postCreateCommand が初回 build に加えてインストール時間 (約30秒) を消費するが、
  キャッシュチェックで再インストールは skip される

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@takaokouji takaokouji changed the title fix(devcontainer): pin build context for devpod compatibility fix(devcontainer): install gh/claude via post-create for devpod compatibility May 11, 2026
@takaokouji
Copy link
Copy Markdown
Author

追加修正: features を使わず post-create.sh でツール install

build context の明示 (commit 8524937) だけでは devpod の features 経由のラッパービルド で同じエラーが続いていた。devpod は dockerComposeFile + features の組み合わせで Dockerfile-with-features を生成するとき、build context を破壊する挙動がある (VS Code Dev Containers では起きない、devpod 固有のバグ)。

修正内容 (commit f167e2b)

  • devcontainer.json から features セクションを削除
  • post-create.shgh (apt経由) と claude-code (npm経由) をインストール
  • 不要になった devcontainer-lock.json を削除
  • README に経緯を追記

検証 (main checkout で確認)

$ docker compose ... up -d app
$ docker compose exec app .devcontainer/post-create.sh
post-create: gh CLI installed: gh version 2.92.0
post-create: Claude Code installed: 2.1.138 (Claude Code)
post-create: main checkout detected, no worktree setup needed

VS Code Reopen in Container / devpod 両方で動作するはずですが、devpod 側の検証はこの修正適用後に試してください。

…onflict

通常 compose (smalruby3-editor-app-1) と devcontainer 用 compose
(default-sm-24f22-app-1 など) が同時に host port 8601 を取り合うと、
後発側 (devpod up .) がポート bind に失敗し、container は起動するが
network attach に失敗する。結果、container の .NetworkSettings.Networks は
空になり、/etc/resolv.conf も Docker 内部 DNS (127.0.0.11) ではなく外部
forwarder (192.168.65.7) を指してしまい、DNS が一切引けなくなる。

devpod での実機検証で再現:
- post-create.sh の curl https://cli.github.com が "Could not resolve host"
- docker exec で確認すると getent hosts が何も返さない

恒久対策: docker-compose.devcontainer.yml で ports: !reset [] を指定し、
devcontainer 起動時は host port を一切 bind しないようにする。

IDE 側 (VS Code / devpod) は devcontainer.json の forwardPorts: [8601] を
読んで自分でポート転送するため、compose レベルの host bind は不要。
通常 compose は影響を受けず、従来通り :8601 を公開する。

合わせて README にトラブルシューティングを追記。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@takaokouji
Copy link
Copy Markdown
Author

追加修正: host port bind 衝突対応 (devpod 失敗の真因)

devpod での実機検証で「Could not resolve host: cli.github.com」エラーが出る原因が判明。

原因

通常 compose の smalruby3-editor-app-1 と devpod 用 compose の default-sm-24f22-app-1同時に host port 8601 を bind しようとして衝突。後発の devpod 側がポート bind に失敗するが container 自体は起動 → network attach に失敗.NetworkSettings.Networks が空、/etc/resolv.conf も Docker 内部 DNS (127.0.0.11) ではなく外部 forwarder (192.168.65.7) のみを参照 → DNS が一切引けない

```

通常 compose container の resolv.conf

nameserver 127.0.0.11 # ← 内部 DNS あり、解決成功

devpod container の resolv.conf

nameserver 192.168.65.7 # ← 外部のみ、解決失敗
```

修正内容 (commit 6977819)

`.devcontainer/docker-compose.devcontainer.yml` で host port bind を無効化:

```yaml
services:
app:
ports: !reset []
```

devcontainer 起動時は host にポートを公開しない。IDE 側 (VS Code / devpod) が `devcontainer.json` の `forwardPorts: [8601]` を読んで自分でポート転送するため問題なし。通常 `docker compose up app` には影響なし。

実機検証

修正後、devpod container 内で:

  • `getent hosts cli.github.com` → IP が返る ✅
  • `.devcontainer/post-create.sh` 完走 (gh 2.92.0 + Claude Code 2.1.138 install) ✅

次の検証

devpod 環境で再度試してください。既存の壊れた devpod workspace が残っている場合は一度 `devpod delete smalruby3-editor` してから `devpod up .`。

devpod 環境では post-create.sh の npm install -g @anthropic-ai/claude-code が
まれに "node: bad option: --max-old-space-size" などのメッセージで exit 1
する事象が起きる。原因は claude の native ELF binary と devpod agent の
組み合わせに起因する Node options 処理の不整合と推測されるが、根本特定は
困難で、手動で再実行すれば成功することは確認済み。

devcontainer up 全体が失敗扱いになると IDE 統合が動かなくなるため、
claude install 失敗は warning に降格して post-create.sh は exit 0 で抜ける。
gh CLI のインストールは引き続き fatal (成功率高い)。

ユーザは container 内で以下を手動実行すれば claude が入る:
    npm install -g @anthropic-ai/claude-code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@takaokouji
Copy link
Copy Markdown
Author

追加修正: Claude Code install を non-fatal に

発生した現象

devpod でビルド成功 → post-create.sh の gh install は成功 → npm install -g @anthropic-ai/claude-code のフェーズで以下のエラーで exit 1:

```
node: bad option: --max-old-space-size
node: bad option: --harmony-import-attributes
node: bad option: --js-source-phase-imports
```

切り分け結果

  • 同じコンテナ (`default-sm-1aa5d-app-1`) に `docker exec` で入って手動 `npm install -g @anthropic-ai/claude-code` を実行 → 成功 (added 2 packages in 3s)
  • container 内 node は v24.15.0、3 つの V8 options はいずれも有効
  • 環境変数 `NODE_OPTIONS=--max-old-space-size=4000` は Dockerfile で設定済み (これ単体では問題なし)
  • claude-code は native ELF binary に Node を組み込んだ形式 (SEA / single-executable application)
  • devpod agent (`/usr/local/bin/devpod` 80MB Go binary) が install 時の subprocess 起動に何らかの影響を与えていると推測

修正 (commit 8d3a206)

claude install を非致命に変更。失敗時は warning を出して post-create.sh は exit 0 で抜ける。container 内で手動で `npm install -g @anthropic-ai/claude-code` を実行すれば成功することを確認済み (manual run path で 1 度成功している)。

gh CLI の install は引き続き fatal (成功率高く、ほぼ確実に必要なため)。

検証していただきたいこと

  1. `devpod delete smalruby3-editor` で壊れた workspace を削除
  2. `devpod up .` を再実行
  3. 完走後、container に入って `claude --version` を確認
  4. 入っていなかった場合は手動で `npm install -g @anthropic-ai/claude-code`

…tainer.json

docker-compose ベースの devcontainer は devpod との相性問題があり (build
context 破壊、port 衝突、features 不整合) 安定運用が困難だったため、
Dockerfile-only 構成にリファクタする。

## 主な変更

- .devcontainer/devcontainer.json は .gitignore 対象に変更。
  各自で .example をコピーして使う:
    cp .devcontainer/devcontainer.json.example .devcontainer/devcontainer.json
- .devcontainer/docker-compose.devcontainer.yml と
  docker-compose.local.yml.example は削除 (compose 経由は廃止)
- 通常の docker-compose.yml は無変更。docker compose run app ... は従来通り
- devcontainer features (claude-code, github-cli) を復活。Dockerfile-only なら
  devpod でも features が正しく動く
- 既存 compose の named volume (node_modules / .npm / .cache) を devcontainer
  でも共有することで、deps の二重インストールを回避。git worktree 切替時の
  起動高速化にも寄与
- 個人マウント (~/ghq, ~/.claude*) はテンプレートでコメントアウト状態で提示。
  使う人だけアンコメントする
- post-create.sh からツール install ロジックを削除 (features が処理)。
  worktree 検出 + setup-worktree 実行のみに簡素化
- 対話的に devcontainer.json を生成するスキルを追加:
  .claude/skills/devcontainer-setup/SKILL.md

## 通常開発者への影響

なし。docker compose run --rm app ... は無変更で動く。
本ディレクトリは devpod / VS Code Dev Containers を使いたい人だけが触る。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@takaokouji takaokouji changed the title fix(devcontainer): install gh/claude via post-create for devpod compatibility refactor(devcontainer): Dockerfile-only + gitignored devcontainer.json for devpod compatibility May 11, 2026
@takaokouji
Copy link
Copy Markdown
Author

大幅リファクタ: docker-compose 撤廃、Dockerfile-only に移行

devpod での compose ベース利用が安定しないため、根本方針を変更しました。

変更概要

Before After
dockerComposeFile で既存 compose の app サービスを共有 Dockerfile-only で既存 Dockerfile を直接ビルド
docker-compose.devcontainer.yml / docker-compose.local.yml で個人マウント .devcontainer/devcontainer.json.gitignore 対象にして各自編集
post-create.sh で gh / claude を毎回 install devcontainer features で build 時に install (devpod でも動く)
compose との volume 共有なし named volume (smalruby3-editor_smalruby3-editor_node_modules 等) を直接 mount して共有

利用者への影響

  • docker compose run --rm app ... を使い続ける人: 影響なし。docker-compose.yml は無変更。
  • devpod / VS Code Dev Containers を使いたい人: .devcontainer/devcontainer.json.example から自分用にコピーして mounts を編集 (cp .example .json)。

追加: 対話的セットアップスキル

.claude/skills/devcontainer-setup/SKILL.md を追加しました。Claude Code から /devcontainer-setup で呼ぶと、AskUserQuestion で mounts の ON/OFF を選んで devcontainer.json を生成します。

動作確認

  • devpod で devpod delete smalruby3-editordevpod up . --ide none が完走する
  • VS Code Reopen in Container で起動できる
  • container 内で which gh claude が両方 path を返す (features 経由)
  • gh auth status が GH_TOKEN 経由で成功
  • claude が起動し、認証・skills・memory が引き継がれる (個人 mounts 有効化時)

takaokouji and others added 2 commits May 12, 2026 01:43
…DISABLE_AUTOUPDATER

container 内 Claude が auto-update すると host の ~/.claude.json まで version
表記が書き換わる問題を回避する。Anthropic 公式 (code.claude.com/docs/en/devcontainer)
の "Avoid mounting host secrets" 原則とも合わせる。

## 変更内容

- containerEnv.DISABLE_AUTOUPDATER=1 を追加 (auto-update 抑止)
- 個人マウントテンプレートから ~/.claude.json bind を削除
  (container 内では別途 `claude` でログイン。container fs で永続、
   devpod stop/up は跨ぐが rebuild で消える)
- skills/plugins/settings/statusline は ro bind のまま (host で編集、
  container は読むだけなので汚染しない)
- memory (~/.claude/projects/-app) は bind rw のまま (host との共有を維持)
- README に新ポリシーを記載
- devcontainer-setup skill の選択肢から auth-only オプションを削除し、
  Claude 系を 1 つのまとまりで提示する形に簡略化

## 利用者が初回にやること

container 起動後、初回のみ:
    claude
で認証フロー (~/.claude.json は container fs 内に作成、host を汚さない)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
devpod を主体とする日常開発ワークフローのガイドを追加。compose ベースの
旧ワークフローと何が違うか、特に git worktree との組み合わせで何が
変わるかを明示する。

主な内容:
- 起動からの 1 日のルーチン (export GH_TOKEN → devpod up → tmux)
- compose との挙動差分一覧
- named volume 共有による npm install 二重実行の回避
- worktree ごとに別の devpod workspace (= 別 container) になる点
- 複数 workspace 同時起動の port 衝突 (devpod が auto-assign)
- できなくなること (bin/dx の手軽さ、host CDK 認証の container 持ち込み等)
- トラブルシューティング (gh / claude / worktree / tmux)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@takaokouji takaokouji merged commit ab2a983 into develop May 12, 2026
9 checks passed
@takaokouji takaokouji deleted the fix/devcontainer-devpod-build-context branch May 12, 2026 02:26
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