Repository navigation
VS Code Server(~/.vscode-server)をコンテナごとのボリュームに重ねて持ち、更新のたびに旧版が溜まる #463
Description
何を見つけたか
devbase_vscode_{project}_{index} はコンテナ 1 つに 1 本で、VS Code Server の本体(bin/<commit>)を各ボリュームが別々に持つ。VS Code の更新のたびに新しい版が入り、古い版が残るため、ボリュームが溜まっていく。
手元の端末で測った値(2026-10-12):
| 項目 | 値 |
|---|---|
devbase_vscode_* の合計 |
約 40GB(17 本) |
うち bin/ の旧版(各ボリュームの最も新しい 1 版を除いたもの) |
約 21GB。bin/ に 8 版を持つボリュームが 3 本、7 版が 1 本 |
extensionsCache/ |
約 3.4GB |
| 同じ拡張の旧版の重複 | 例: anthropic.claude-code が 3 版、openai.chatgpt が 2 版(各 0.9GB) |
コンテナごとに分けているのは、VS Code Server が「1 マシン 1 セット」の状態(data/Machine/.connection-token-<commit> など)を持ち、同時に書くと接続トークンを奪い合うためとされている(docs/user/container-operations.md の「VS Code Server の永続化」)。この奪い合いを実機で確かめた記録は無い。版ごとに中身が変わらない bin/<commit> には、この理由はそもそも当たらない。
案
~/.vscode-server を丸ごと全コンテナ共通の 1 本のボリュームにする。共有して困る理由として挙げてきた「接続トークンの奪い合い」が実際に起きるかは確かめていない(下の 7〜10)。問題が出た部分だけをコンテナごとに戻す。戻す順は data/ → extensions/ で、bin/ は最後まで共有する。
| 置き場 | 中身 | 共有 |
|---|---|---|
bin/<commit> |
サーバーの本体。版ごとに不変 | 共有する(案) |
extensions/ |
拡張。extensions.json を各サーバーが書き換える |
共有する(案。4〜6 を確かめる) |
data/ |
接続トークン・マシンの設定・ログ・User/ の状態(SQLite) |
共有する(案。7〜10 を確かめる) |
実機で確かめること
- 2 つのコンテナで初めて同時に attach し、同じ版の
bin/<commit>を同時にダウンロード・展開しても壊れないか(片方が展開途中の版を使わないか) - VS Code Server が使わなくなった古い版を
bin/から消すとき、別のコンテナが使っている版まで消さないか - 既存の
devbase_vscode_*からの移り方(既存のbin/・extensions/を共通のボリュームへ寄せるか、捨てて取り直すか) - 2 つのコンテナで拡張のインストール・更新・アンインストールが同時に起きたとき、
extensions/extensions.jsonが壊れたり片方の書き込みが失われたりしないか - 拡張の自動更新が旧版に
.obsoleteの印を付けて消すとき、別のコンテナがまだ読み込んでいる旧版まで消さないか - サーバーの版が違うコンテナ同士(片方だけ VS Code を更新した状態)で同じ
extensions/を使えるか(拡張は対応するエンジンの版で入る版が変わる) - 接続トークン
data/Machine/.connection-token-<commit>: 既にあれば読み、無ければ作る作りか。2 つのコンテナで初めて同時に起動したとき、両方が書いて後勝ちになり、先に起動した側の接続が切れるか(今の文書の「奪い合う」が実際に起きるか) data/User/globalStorage・data/User/workspaceStorageのstate.vscdb(SQLite)を複数のサーバーが同時に開いたとき、ロックの待ちや書き込みの失敗が出ないかdata/logs/が起動ごとに別のディレクトリになり、ぶつからないかdata/Machine/settings.jsonをコンテナ間で同じにして困る設定が devbase の使い方にあるか
どこで見つけたか
スプリント m8a(#368 の受け入れ条件 9 の確認)で、ホストのディスクが満杯になった後に空きを作る作業で docker system df -v を見たとき。このときは各ボリュームの bin/ の旧版・extensionsCache/・extensions.json に無い拡張の旧版を手で消し、約 40GB から約 12GB にした。
なぜこの変更の範囲外なのか
スプリント m8a の課題(#455 #368)はスナップショットの除外と補完のテストで、VS Code Server のボリュームの構成を含まない。devbase_vscode_* はスナップショットの対象外でもある。
確かめた範囲で減る量の見込み
今回の手元では、bin/ の旧版が約 21GB、拡張の旧版の重複と extensionsCache/ で数 GB。丸ごと共有すると、同じ版をプロジェクトとインスタンスの数だけ重ねて持つことが無くなり、合計は 1 本分(今回の最大のボリュームで約 2GB)に近づく。拡張を一度入れれば全コンテナで使える。
直さないと何が起きるか
VS Code の更新のたびに、各ボリュームへ 1 版(約 0.6GB)ずつ溜まり続ける。プロジェクトとインスタンスの数だけ同じ版を重ねて持つため、ホストのディスクを圧迫する。手で消さない限り減らない。
由来
スプリント m8a の作業中の利用者との会話(2026-10-12)
依頼(原文)
#463。人へ問わずに進め、決められない点は前提か未決として課題の本文へ書く。(中略)課題の「案」(~/.vscode-server を丸ごと全コンテナ共通の 1 本にし、問題が出た部分だけコンテナごとに戻す。戻す順は data → extensions、bin は最後まで共有)を出発点にする。利用者の見立ては「data も事実上問題ない」。共有の単位(全体で 1 本か、グループごとか)、既存の devbase_vscode_* からの移り方と後片付け、コンテナの entrypoint(containers/base/entrypoint.sh の devbase_setup_vscode_server_dir)・lib/devbase/volume/compose.py・manager.py の変更、文書(docs/user/container-operations.md の「VS Code Server の永続化」)を決める。課題の「実機で確かめること」10 項目は、項目ごとに確かめ方を決める。(中略)実の VS Code からの attach が要る項目は、マージ前の手動確認として利用者か conductor へ回すと書く。
(書き手: AI の起動指示、日付: 2026-10-13。中略した部分は作業の制約(ボリュームを写さない・devbase up を打たない・base を建て直さない)で、要求の中身を含まない)
data も事実上問題ない
(書き手: 利用者(上の起動指示が引いた見立て)、日付: 不明。2026-10-12〜13 の会話と推す)
~/.vscode-serverを丸ごと全コンテナ共通の 1 本のボリュームにする。(中略)問題が出た部分だけをコンテナごとに戻す。戻す順はdata/→extensions/で、bin/は最後まで共有する。
(書き手: 起票者(この課題の「案」の節)、日付: 2026-10-12。利用者の指示の原文としては扱わない)
(a)
data/はボリュームにせず、コンテナの書き込みレイヤーに残す。コンテナごとの VS Code Server の状態のボリューム(devbase_vscode-data_*)は作らない。(b) 共有するのはbin/だけ。共通の VS Code Server ボリューム 1 本を~/.vscode-server/binに付ける。extensions/・extensionsCache/・data/はコンテナの書き込みレイヤーに残り、devbase upの作り直し(down → up)で消える。docker restart・端末の再起動では消えない。
(書き手: 利用者の決定(承認ゲート 1)を伝えた conductor の起動指示、日付: 2026-10-14。失うものを conductor が動いているコンテナ 2 つで測り、利用者がそれを見て受け入れた。測った値は前提 7)
起票者の推定
| # | 条件 | 推した出所 | この要求での扱い |
|---|---|---|---|
| S1 | ~/.vscode-server を丸ごと全コンテナ共通の 1 本にする |
この課題の「案」 | 一部を採る。共有するのは bin/ だけにし、extensions/・extensionsCache/・data/ はどのボリュームにも置かず、コンテナの書き込みレイヤーに残す(前提 1。利用者の決定、2026-10-14)。bin/・extensions/・extensionsCache/ は共有し、data/ はコンテナごとに戻す |
| S2 | 問題が出た部分だけをコンテナごとに戻し、戻す順は data/ → extensions/、bin/ は最後まで共有する |
この課題の「案」 | 採らない(2026-10-14 に変更)。問題が出た部分を戻す順で決めず、利用者が承認ゲート 1 で共有を bin/ に絞った(前提 1)。data/ を戻した |
| S3 | 「接続トークンの奪い合い」は確かめておらず、起きるかが分からない | この課題の「何を見つけたか」 | 確かめた。奪い合いは起きない(「実機で確かめることの扱い」の 7)。文書の記述を直す(受け入れ条件 14) |
| S4 | 共有すると合計は 1 本分(約 2GB)に近づく | この課題の「確かめた範囲で減る量の見込み」 | 採らない。共有しても VS Code の更新ごとに版が溜まるため、残す版の数で上限を決める(受け入れ条件 7・8) |
| S5 | 拡張を一度入れれば全コンテナで使える | この課題の「確かめた範囲で減る量の見込み」 | 採らない(2026-10-14、利用者の決定。拡張は共有しない)。 |
| S6 | devbase_vscode_* はスナップショットの対象外 |
この課題の「なぜこの変更の範囲外なのか」 | 含まない(スナップショットの対象を変えない。受け入れ条件 13) |
目的
- VS Code Server の本体を、プロジェクトとインスタンスの数だけ重ねて持たず、全コンテナで 1 組にする
- VS Code の更新のたびに本体の旧版が溜まり続けることを止め、手で消さなくてもホストのディスクを使う量に上限がある状態にする
- 窓のタイトル・接続の再開は、今と同じくコンテナごとに分かれたまま働く
前提
- 前提 1(共有の範囲): 共有するのは
~/.vscode-server/binだけで、共通の VS Code Server ボリューム 1 本を~/.vscode-server/binに付ける。extensions/・extensionsCache/・data/とその他の直下の置き場はどのボリュームにも置かず、コンテナの書き込みレイヤーに残る。docker restartと端末の再起動では残り、devbase upの作り直し(down → up)で消える。利用者が承認ゲート 1(2026-10-14)で決めた。(2026-10-13 の版。bin/・extensions/・extensionsCache/を共通のボリュームに置き、data/はコンテナごとのボリュームに置くdata/Machineを共有すると.devportとwindow.titleが後勝ちになることは「実機で確かめることの扱い」の 7・10 で確かめたが、data/を書き込みレイヤーに残せばコンテナごとに分かれるため当たらない) - 前提 2(共有の単位): 共通の VS Code Server ボリュームは端末に 1 本で、アカウントグループで分けない。置くのはサーバーの本体だけで、認証の情報・拡張・拡張の保存する状態を持たない
- 前提 3(移り方): 旧形式の VS Code Server ボリュームの中身は、新しいボリュームへ写さない。本体は最初の attach で取り直す(約 215MB、約 55 秒)。
extensions/とdata/も引き継がない(前提 7)。写すと、ボリュームの丸写しでホストのディスクが埋まる落とし穴(AGENTS.md)に当たる - 前提 4(後片付け): devbase は旧形式の VS Code Server ボリュームを消さない(C4)。
devbase upが見つけたときに名前と消し方を案内し、消すのは利用者が行う - 前提 5(本体の旧版の片付け): Dev Containers 拡張(0.469.0 で確かめた)は、devbase の attach の形では
bin/の旧版を消さない(「実機で確かめることの扱い」の 2)。devbase のコンテナの起動で、bin/の版を新しい順に一定の数だけ残して古い版を消す。残す数は設計で決め、3 版以上とする - 前提 6(片付けの置き場): 本体の旧版の片付けと、権限の用意は、コンテナの entrypoint(
devbase_setup_vscode_server_dir)に置く。entrypoint の変更は base を建て直すまで効かない(AGENTS.md の落とし穴)。この課題で base の道具とその版は変えない(P1 に当たらない) - 前提 7(作り直しで失うもの):
devbase upの作り直しのたびに、コンテナの書き込みレイヤーにある次のものが消える。利用者が承認ゲート 1(2026-10-14)で、conductor が動いているコンテナ 2 つで測った値を見て受け入れたdata/User/History(ローカル履歴、約 300KB)data/User/globalStorageとdata/User/workspaceStorage(拡張のリモート側の状態。Copilot Chat など、約 250KB)data/logs(約 16MB。消えるため溜まらなくなる)- 手で入れたリモート側の設定(
data/Machine/settings.jsonのwindow.title以外)と、手で入れた拡張。Dev Containers の既定の拡張は.installExtensionsMarkerが消えるため、作り直しの後の attach で入り直す - 接続トークンと
.devportは作り直される。window.titleはdevbase upが毎回書き直す
前提 7(拡張の集まり): 拡張は全コンテナで同じ集まりになる。(以下略)(2026-10-14 に削除。拡張を共有しないため当たらない)
対象範囲
含む:
- 共通の VS Code Server ボリュームを作る・dev インスタンスの
~/.vscode-server/binへ付ける(lib/devbase/volume/manager.py・lib/devbase/volume/compose.py) - コンテナの起動で
~/.vscode-serverと~/.vscode-server/binを開発ユーザーが書ける形にし、bin/の旧版と同時の展開の残りを片付ける(containers/base/entrypoint.shのdevbase_setup_vscode_server_dir) devbase upが旧形式の VS Code Server ボリュームを見つけたときの案内- 文書(
docs/user/container-operations.mdの「VS Code Server の永続化」とボリュームの表)、CHANGELOG.mdの[Unreleased] - 上の振る舞いのテスト(
tests/volume/・tests/containers/)
含まない:
- 旧形式の VS Code Server ボリュームを devbase が消す・写す・付けること
extensions/・extensionsCache/・data/を作り直しをまたいで残すこと(前提 1・7。利用者の決定)- 拡張の版の選び方・自動更新の振る舞いを変えること(VS Code と Dev Containers 拡張の持ち物)
extensionsCache/とextensions/の旧版の片付け(書き込みレイヤーにあり、devbase upの作り直しで消える)- スナップショットの対象を変えること
- Cursor など
~/.vscode-server以外のサーバーの置き場(~/.cursor-serverなど) - base イメージに入れる道具とその版の変更(P1)
実機で確かめることの扱い
担当が確かめたのは、新しく作った空の作業用ボリューム issue463-scratch-vscs と手元の devbase-base:latest(sha256:2bf59f64…、作成 2026-10-12T17:19:13Z、arm64、macOS の Docker Desktop)の docker run --rm で、VS Code Server 1.140.0(commit 07f806f9)と 1.139.0 を動かした範囲である(2026-10-13)。Dev Containers 拡張の手順は、手元の ms-vscode-remote.remote-containers-0.469.0 の dist/extension/extension.js を読んで写した。実の VS Code からの attach はしていない。4〜10 は extensions/ と data/ を共有する案のために確かめたもので、2026-10-14 に共有を bin/ に絞ったため、確認は要らなくなった。結果は記録として残す。
| # | 確かめること | 確かめ方 | 結果 | 残る確認 |
|---|---|---|---|---|
| 1 | 本体の同時のダウンロード・展開 | 拡張の手順(test -d bin/<commit> が偽なら bin/<commit>_<ミリ秒> へ展開し、mv -n <一時>/* bin/<commit> && rmdir <一時>)を 2 つのコンテナで同じ時刻に始めた。3 回 |
展開途中の版を使うことは無い(bin/<commit> は mv の 1 回の改名で現れる)。ただし、3 回のうち 2 回は遅れた側の中身が bin/<commit>/vscode-server-linux-arm64/ に入れ子で残り(bin/<commit> が 1.2GB)、1 回は一時の名前のミリ秒が同じになり片方の mv が失敗した(実の attach なら片方の接続が失敗し、やり直しで繋がる) |
入れ子の残りを片付ける(受け入れ条件 8)。VS Code の更新の後に窓を一度に復元する場面は手動確認(リリース後)の M5 |
| 2 | 古い版を消すとき、ほかのコンテナの版まで消すか | 拡張のコードを読んだ | Dev Containers 拡張が bin/ の旧版を消すのは、拡張の共有の置き場(sharedInstallFolder)を使う形だけで、最終の使用時刻の新しい順に 9 版を残す。devbase の attach の形では消さない。課題の「bin/ に 8 版」と合う |
消すのは devbase の役目になる(前提 5、受け入れ条件 7)。版の違う窓が並ぶ場面は手動確認(リリース後)の M4 |
| 3 | 既存の devbase_vscode_* からの移り方 |
決めることとして扱った | 写さずに取り直す(前提 3・4) | 無し |
| 4 | 拡張の同時のインストール・更新・アンインストールで extensions.json が壊れるか |
2 つのコンテナで code-server --install-extension / --uninstall-extension を同じ時刻に始めた。インストールどうし 1 回、インストールとアンインストール 6 回 |
7 回とも extensions.json は正しい JSON で、両方の結果が残った。アンインストールは .obsolete に印を付け、ディレクトリを残した |
拡張を共有しないため要らない(2026-10-14) |
| 5 | 自動更新で .obsolete の付いた旧版を、ほかのコンテナが読み込んでいる間に消すか |
片方で .obsolete の印を付けたあと、別のコンテナでサーバーを --start-server で起動した |
起動した側のサーバーが、印の付いた版のディレクトリと .obsolete を消した。別のコンテナでその版を読み込んだ拡張ホストが動いていても消える |
拡張を共有しないため要らない(2026-10-14) |
| 6 | 版の違うサーバーで同じ extensions/ を使えるか |
1.140.0 で入れた拡張を 1.139.0 で一覧し、1.139.0 で拡張を入れて 1.140.0 で一覧した | どちらの向きでも読めた。対応するエンジンの版で入る版が変わる拡張は試していない | 拡張を共有しないため要らない(2026-10-14) |
| 7 | 接続トークンを奪い合うか | 拡張の手順(cat <token> 2>/dev/null || (umask 377 && echo <uuid> > <一時> && mv -n <一時> <token> && …))と同じ引数でサーバーを 2 つのコンテナで同じ時刻に起動し、両方へトークン付きで /version を引いた |
奪い合わない。あれば読み、無ければ mv -n で作るため、2 つとも同じトークンを読み、両方が 200 を返した。一方 data/Machine/.devport-<commit> は後から書いた側の値になった(A の 33627 が残り、B の 39925 が消えた)。拡張は窓の再接続でこの値を読み、同じコンテナのサーバーの口として使う |
data/ を共有しないため要らない(2026-10-14) |
| 8 | state.vscdb(SQLite)の同時の利用 |
2 つのコンテナから同じファイルへ同時に 2000 件ずつ書いた(待ち 0.2 秒) | コンテナをまたいでもロックが効き、待ちを超えた書き込み 6 件が失敗し、ファイルは壊れなかった(integrity_check は ok) |
data/ を共有しないため要らない |
| 9 | data/logs/ がぶつかるか |
7 と同じ起動で見た | ログのディレクトリの名前は起動の秒(20261013T000042)で、同じ秒に起動した 2 つは同じディレクトリへ書いた |
data/ を共有しないため要らない |
| 10 | data/Machine/settings.json を同じにして困る設定 |
コードを読んだ | devbase の devbase up は、コンテナごとに違う window.title(コンテナ名で始まる)をこのファイルへ書く(lib/devbase/editor/window_title.py)。共有すると、最後に書いたコンテナの名前がすべての窓のタイトルになる |
data/ を共有しないため要らない(2026-10-14) |
ドメインイベント
| # | イベント | 引き金 | 失敗したとき | 順序の前提 |
|---|---|---|---|---|
| E1 | 共通の VS Code Server ボリュームを用意した | devbase up / devbase scale |
作れなければ今のボリュームと同じく DockerError で止まる |
— |
| E2 | 生成した compose が、共通の VS Code Server ボリュームを dev インスタンスの ~/.vscode-server/bin へ付けた |
E1 の後の compose の生成 | プロジェクトが ~/.vscode-server か ~/.vscode-server/bin を自分で付けていれば、devbase は何も足さない |
E1 |
| E3 | entrypoint が ~/.vscode-server と ~/.vscode-server/bin を開発ユーザーが書ける形にした |
コンテナの起動 | 書ける形にできなければ attach が失敗する。この課題より前の base から建てたイメージでも E3 が欠けないこと(受け入れ条件 10) | E2 |
| E4 | entrypoint が bin/ の旧版と、同時の展開の入れ子の残りを片付けた |
コンテナの起動 | 消せなくても起動を止めず、WARNING を出す | E3 |
| E5 | VS Code の attach が本体を bin/<commit> に置いた(無いときだけ) |
利用者の attach | 同時の展開で片方が失敗すれば、その窓の接続が失敗し、やり直しで繋がる(「実機で確かめることの扱い」の 1) | E3 |
| E6 | VS Code Server が接続トークンと .devport を、書き込みレイヤーの data/Machine に書いた |
E5 の後のサーバーの起動 | — | E5 |
| E7 | devbase up が window.title を data/Machine/settings.json に書いた |
devbase up の起動の後の処理 |
今と同じ(警告して続ける) | E3 |
| E8 | 拡張を書き込みレイヤーの extensions/ に入れた・更新した・消した |
利用者の操作・自動更新・Dev Containers の既定の拡張の導入 | — | E5 |
.obsolete の付いた拡張の版を消した |
— | — | 2026-10-14 に削除(拡張を共有しない) | |
| E10 | devbase up が旧形式の VS Code Server ボリュームを見つけ、名前と消し方を案内した |
devbase up |
ボリュームの一覧が取れなければ案内を出さずに続ける | E1 |
| E11 | 利用者が旧形式の VS Code Server ボリュームを消した | 利用者の操作 | 使っているコンテナが残っていれば docker volume rm が断る |
E10 |
| E13 | devbase up の作り直しで、書き込みレイヤーの extensions/・extensionsCache/・data/ が消えた |
devbase up(down → up) |
— | — |
用語
| 用語 | 意味 |
|---|---|
| 共通の VS Code Server ボリューム | すべての dev コンテナが ~/.vscode-server/bin に付ける 1 本のボリューム。本体の版(bin/<commit>)だけを持つ |
| コンテナごとの VS Code Server の状態 | ~/.vscode-server のうち bin/ 以外(extensions/・extensionsCache/・data/)。どのボリュームにも置かず、コンテナの書き込みレイヤーに残る。devbase up の作り直しで消える |
| 旧形式の VS Code Server ボリューム | この課題より前の devbase_vscode_<project>_<index>。~/.vscode-server を丸ごと持つ |
受け入れ条件
ボリュームと compose:
- 1.
devbase up/devbase scaleは、共通の VS Code Server ボリュームが無ければ 1 本作り、あれば作らない。プロジェクト・インスタンス・アカウントグループが違っても同じ 1 本である - 2. 生成した compose の dev インスタンスは、どれも共通の VS Code Server ボリュームを
/home/ubuntu/.vscode-server/binに付け、/home/ubuntu/.vscode-serverと/home/ubuntu/.vscode-server/dataにはボリュームを付けない 2. 生成した compose の dev インスタンスは、どれも共通の VS Code Server ボリュームを→ 上の 2 へ変更(2026-10-14、利用者の決定)/home/ubuntu/.vscode-serverに付け、インスタンスごとに違うボリュームを/home/ubuntu/.vscode-server/dataに付ける- 3. 共通の VS Code Server ボリュームの名前は、どのプロジェクト名・インスタンス番号の旧形式の VS Code Server ボリュームの名前(
devbase_vscode_<project>_<index>)とも重ならず、旧形式の案内が旧形式として選ばない 3. コンテナごとの VS Code Server の状態のボリュームの名前は、プロジェクトとインスタンス番号で決まり、どのプロジェクト名でも、旧形式の VS Code Server ボリュームの名前とも共通の VS Code Server ボリュームの名前とも重ならない→ 上の 3 へ変更(2026-10-14、コンテナごとのボリュームを作らない)- 4. 前提: コンテナ A とコンテナ B(別のプロジェクト)が共通の VS Code Server ボリュームを付けている。操作: A で本体を
bin/<commit>に置く。結果: B から~/.vscode-server/bin/<commit>/bin/code-server --versionが通る 4. (A の→ 上の 4 へ変更(2026-10-14、拡張を共有しない)code-serverで拡張を入れると、B のcode-server --list-extensionsにその拡張が出る)- 5. プロジェクトの compose が
/home/ubuntu/.vscode-serverか/home/ubuntu/.vscode-server/binを自分で付けているとき、devbase はボリュームを足さない 5. プロジェクトの compose が→ 上の 5 へ変更(2026-10-14、マウント先が/home/ubuntu/.vscode-serverを自分で付けているとき、devbase は~/.vscode-serverにも~/.vscode-server/dataにもボリュームを足さない(今と同じ)binになった)- 6. 生成した compose に、旧形式の VS Code Server ボリュームが現れない
コンテナの起動:
- 7. 前提: 共通の VS Code Server ボリュームの
bin/に、残す数より多い版がある。操作: コンテナを起動する。結果: 新しい順に残す数の版だけが残り、それより古い版のディレクトリが無い - 8. 前提:
bin/<commit>/の中に、同時の展開で残った入れ子の本体(vscode-server-linux-*など、product.jsonを持つディレクトリ)がある。操作: コンテナを起動する。結果: 入れ子の本体が無く、bin/<commit>/bin/code-serverは残っている - 9. 片付けで消せないもの(権限が無い・ほかのコンテナが先に消した)があっても、コンテナの起動は止まらず、消せなかったパスを WARNING の行に出す(ほかのコンテナが先に消したときは出さない)
- 10. 空のボリュームを
~/.vscode-server/binに付けて起動すると、~/.vscode-serverと~/.vscode-server/binは開発ユーザーが書ける。この課題より前の entrypoint を持つイメージ(建て直す前の base と、その上の派生イメージ)でも、devbase upの起動の後の処理の後には~/.vscode-server/binを開発ユーザーが書ける 10. 空のボリュームを付けて起動すると、→ 上の 10 へ変更(2026-10-14、マウント先が~/.vscode-serverと~/.vscode-server/dataは開発ユーザーが書ける。この課題より前の entrypoint を持つイメージでも、~/.vscode-server/dataは開発ユーザーが書けるbinになった)
移り方と後片付け:
- 11. 前提: 旧形式の VS Code Server ボリュームが 1 本以上ある。操作:
devbase up。結果: 旧形式のボリュームの名前と、消すコマンドが案内に出る。devbase はそのボリュームを消さず、付けず、中身を読まない - 12. 前提: 旧形式の VS Code Server ボリュームが無い。操作:
devbase up。結果: 案内は出ない - 13. スナップショットの対象は変わらない(共通の VS Code Server ボリュームは対象外)
文書:
- 14.
docs/user/container-operations.mdの「VS Code Server の永続化」とボリュームの表が、共有するのはbin/だけであること、共有する理由、extensions/・extensionsCache/・data/はコンテナの書き込みレイヤーにありdevbase upの作り直しで消えdocker restartと端末の再起動では消えないこと、作り直しで失うもの(前提 7 の項目。Dev Containers の既定の拡張は入り直すこと)、移ったあとの最初の attach で本体を取り直すこと、旧形式のボリュームの消し方、bin/に残す版の数を書いている。「接続トークンを奪い合う」という記述が無い 14. (共有する置き場とコンテナごとの置き場、→ 上の 14 へ変更(2026-10-14、利用者の決定)data/を分ける理由(.devportとwindow.title)、手で入れた拡張を入れ直すことを書く)- 15.
CHANGELOG.mdの[Unreleased]に、ボリュームの構成が変わること、最初の attach で本体を取り直すこと、拡張とリモート側の設定・状態がdevbase upの作り直しのたびに消えるようになること、旧形式のボリュームを利用者が消すことを書いている 15. (ボリュームの構成が変わること、最初の attach で取り直すこと、旧形式のボリュームを利用者が消すこと)→ 上の 15 へ変更(2026-10-14、作り直しで消えるものが増えた)
非機能の条件
| 大項目 | 条件 |
|---|---|
| 性能・拡張性 | 共通の VS Code Server ボリュームの bin/ に残る版の数は、コンテナの数・プロジェクトの数・VS Code の更新の回数に依らず、残す数(前提 5)を超えない。コンテナの起動の後に、入れ子の本体が残らない |
| 移行性 | 移る対象は無い(写さない)。切り戻し: devbase をこの課題より前の版へ戻すと、消していない旧形式の VS Code Server ボリュームを前と同じように付ける。共通の VS Code Server ボリュームは残るだけで害が無い |
| セキュリティ | 共通の VS Code Server ボリュームに、本体のほかのもの(接続トークン・拡張・拡張の保存する状態・マシンの設定)が入らない |
| システム環境 | macOS の Docker Desktop と Linux の Docker で同じ振る舞いになる。新しい Compose のオプションを使うなら、要る Compose の版と、それより前の版での扱いを設計で決める(AGENTS.md の落とし穴) |
影響
| 対象 | 影響 |
|---|---|
| 公開インタフェース | CLI の引数と出力は変わらない(devbase up の案内の行が増える)。生成する compose のボリュームの構成が変わる。旧形式の VS Code Server ボリュームを使い続ける経路は持たない(互換なし。ただし中身は VS Code が取り直せるもので、切り戻しで元へ戻る) |
| データ | 旧形式の VS Code Server ボリュームは使わなくなり、残る。移行はしない(前提 3) |
| 既存の振る舞い | 移った後の最初の attach で本体(約 215MB)を取り直す。これまで作り直しをまたいで残っていた拡張・リモート側の設定・ローカル履歴・拡張のリモート側の状態が、devbase up の作り直しのたびに消える(前提 7)。作り直しの後の attach で Dev Containers の既定の拡張を入れ直す時間がかかる |
検証手段
| 項目 | 手段 |
|---|---|
| テスト | env -u DEVBASE_ROOT uv run --locked pytest tests/ -q(compose の生成は tests/volume/test_compose_vscode.py、ボリュームの用意は tests/volume/test_manager_vscode.py、entrypoint の関数は tests/containers/test_entrypoint_vscode_server.py の形) |
| 静的解析 | uvx ruff check --select=E9,F63,F7,F82 lib、python3 .github/scripts/proper_term_check.py、devbase-base:latest の shellcheck で containers/base/entrypoint.sh |
| 実機(担当が打てる範囲) | 受け入れ条件 4・7〜10 は、空の作業用ボリュームと手元の devbase-base:latest の docker run --rm で確かめる。受け入れ条件 10 の「この課題より前の entrypoint」は、建て直していない今の devbase-base:latest がそれに当たる。新しい entrypoint はイメージを建てずに、関数をボリュームを付けたコンテナの中で走らせて確かめる。devbase up は打たない |
| 手動確認(マージ前) | M1。新しい devbase で devbase up が要るため、conductor が P3 の承認を取ってから打つか、利用者が行う。担当は打たない |
| 手動確認 | M4・M5。リリース後テストで確かめる |
手動確認の項目:
- M1(マージ前): 別のプロジェクトの 2 つのコンテナへ VS Code を attach する。2 つ目の attach が本体を取り直さず、共通の VS Code Server ボリュームの
bin/<commit>で繋がる。両方の窓が使え、窓のタイトルがそれぞれのコンテナ名で始まり、片方の窓の「ウィンドウの再読み込み」で同じコンテナへ繋がり直す。片方のプロジェクトでdevbase upを打ち直した後に attach し直すと、Dev Containers の既定の拡張が入り直して使える M2(マージ前): 拡張の同時のインストール・更新(2026-10-14 に削除。拡張を共有しない)M3(マージ前):(2026-10-14 に削除。拡張を共有しない).obsoleteの消去と動いている窓- M4(リリース後): 片方の端末の VS Code だけを更新し、版の違う 2 つの窓が同じ共通の VS Code Server ボリュームの
bin/を使う。どちらの窓も使え、コンテナの起動の片付けがどちらの版も消さない - M5(リリース後): VS Code の更新の後、複数の窓を一度に開き直す。その後にコンテナを起動し直すと、
bin/<新しい commit>/に入れ子の本体が残っていない
前提とする取り決め
| 項目 | 参照先 / 決めたこと |
|---|---|
| プロジェクト構造 | AGENTS.md の「このリポジトリ」。projects/* はプラグインのリポジトリで、触らない |
| コーディング規約 | 周りのコードに合わせる。lib/ は ruff の CI の規則、entrypoint.sh は ShellCheck |
| テスト戦略 | compose の生成とボリュームの用意は単体のテストで、entrypoint の片付けは関数を一時のディレクトリで走らせるテストで担保する。実の Dev Containers 拡張からの attach は手動確認で担保する |
境界
| 区分 | 内容 |
|---|---|
| 常に行う | 全体のテスト・lint・固有の語の検査を push の前に打つ。実機の記録は中立の名前(proj-a など)で書く。作業用のボリュームは記録を書いたら消す |
| 確認してから行う | 前提 1(共有を bin/ に絞る)・前提 3(写さずに取り直す)・前提 7(作り直しで失うもの)は、承認ゲート 1(2026-10-14)で利用者が決めた。生成する compose のボリュームの構成の変更は承認ゲート 2 で人が見る |
| 行わない | 旧形式の VS Code Server ボリュームを消す・写す・付ける。担当が devbase up を打つ(作業用のプロジェクトも含む)。base イメージを建て直す。base の道具とその版を変える |
未決
| 項目 | 誰が決めるか | 期限 |
|---|---|---|
bin/ に残す版の数(3 版以上) |
設計 | 承認ゲート 1 |
| 共通の VS Code Server ボリュームの名前 | 設計 | 承認ゲート 1 |
旧形式の VS Code Server ボリュームの案内を devbase up のたびに出すか、出す回数を絞るか |
設計 | 承認ゲート 1 |
data/ を付ける形(入れ子のマウントか、別の置き場への symlink か) |
— | 2026-10-14 に解消(data/ をボリュームに置かない) |
extensions/ もコンテナごとに戻すか |
— | 2026-10-14 に解消(拡張を共有しない) |
MVV との突き合わせ
Value 2(作り直しで失わない)に反する疑いがある。手で入れたリモート側の設定・手で入れた拡張・ローカル履歴・拡張のリモート側の状態が、devbase up の作り直しで消える(前提 7)。利用者が承認ゲート 1(2026-10-14)で、測った量を見て受け入れた。共通原則の優先順位で、利用者の承認はプロジェクトの MVV より上にある。ほかは反する疑いが無い。根拠: Value 1(本体を取り直すのは移った後の最初の 1 回だけ。既定の拡張は作り直しの後に入り直す)、Value 2(上のとおり)、Value 3(共有するのは本体だけで、プロジェクトの設定・機密・データ・拡張を共有しない)、C4(旧形式のボリュームを devbase が消さない)、P1(base の道具とその版を変えない)、P3(マージ前の手動確認の devbase up は承認を取ってから打つ)。
進行
モード: —
- 要求と受け入れ条件 — 2026-10-13 08:57
- 作業場所の用意 — 2026-10-14 09:42
- 設計 — 2026-10-13 09:09
- 素材の収集と出典の確定
- ドキュメント再構成
- ドキュメントレビュー
- 計画 — 2026-10-14 09:42
- 実装 — 2026-10-14 09:42
- 構造改善 — 2026-10-14 10:18
- 実装レビュー — 2026-10-14 10:36
- 完了判定 — 2026-10-14 09:53
- Pull Request — 2026-10-14 09:57
- 確定仕様化 — 2026-10-14 12:38
- 後片付け
- 配布 — 2026-10-14 13:52
- 体裁レビュー
- リリース後テスト — 2026-10-14 13:53
- 振り返り — 2026-10-14 13:58
- 棚卸し — 2026-10-15 13:18
振り返り: #488 (comment)
Activity
[-]VS Code Server の本体(bin/<commit>)をコンテナごとのボリュームに重ねて持ち、更新のたびに旧版が溜まる[/-][+]VS Code Server の本体と拡張(bin/・extensions/)をコンテナごとのボリュームに重ねて持ち、更新のたびに旧版が溜まる[/+][-]VS Code Server の本体と拡張(bin/・extensions/)をコンテナごとのボリュームに重ねて持ち、更新のたびに旧版が溜まる[/-][+]VS Code Server(~/.vscode-server)をコンテナごとのボリュームに重ねて持ち、更新のたびに旧版が溜まる[/+]design(#463): 不変条件 I1 を最終の構成の条件にし、I2 の data だけ宣言と両立させる
design(#463): I1 に ~/.vscode-server だけを付けたときはどちらも足さないことを明記する
design(#463): 承認ゲート 1 の利用者の決定に合わせ、共有を bin/ だけにする
Merge pull request #484 from devbasex/design/issue-463
Merge pull request #485 from devbasex/feat/issue-463-m8d
Merge pull request #489 from devbasex/docs/spec-m8d