Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,21 @@
**更新後の最初の `devbase up` の自動スナップショットは、系列ごとに新しい世代(フル)を作ります。**
除外の一覧が違う世代を `devbase snapshot create --name` で指定すると、差分を作らずに終了コード 1 で止まります。
既存の世代はそのまま一覧・復元できます。
- **VS Code Server の本体(`~/.vscode-server/bin`)だけを全コンテナ共通の 1 本のボリューム `devbase_vscode-server-bin` に
置くようにしました(#463)。** これまではコンテナ 1 つに 1 本の `devbase_vscode_<プロジェクト>_<番号>` が
`~/.vscode-server` を丸ごと持ち、VS Code の更新のたびに約 0.6GB の版が各ボリュームへ溜まっていました。
今は本体の版をプロジェクトとインスタンスの数だけ重ねて持たず、コンテナの起動が `bin/` の版を新しい順に 5 つまで残し、
同時の展開で残った入れ子の本体と古い展開の途中のディレクトリも消します(この片付けは base と派生イメージを
建て直した後から効きます)。
**拡張機能・リモート側の設定(`data/Machine/settings.json`)・ローカル履歴・拡張機能がリモート側に保存する状態は、
ボリュームに置かずコンテナの書き込みレイヤーに残るため、`devbase up` でコンテナを作り直すたびに消えるようになります。**
手で入れた拡張機能は入れ直しになり、Dev Containers の既定の拡張機能は作り直しの後の attach で入り直します。
`window.title` は `devbase up` が毎回書き直します。`docker restart` と端末の再起動では消えません。
移った後の最初の attach で本体(約 215MB)を取り直します。以前の `devbase_vscode_<プロジェクト>_<番号>` は付けず、
中身も引き継がず、devbase は消しません。残っている間は `devbase up` の最後に名前と消すコマンドが出るので、
利用者が `docker volume rm` で消してください([使わなくなった VS Code Server ボリュームを消す](docs/user/container-operations.md#使わなくなった-vs-code-server-ボリュームを消す))。
建て直す前のイメージでも attach できるよう、`devbase up` / `scale` / `project post-start` の起動の後の処理が
`~/.vscode-server/bin` を開発ユーザーが書ける形に揃えます。

### Fixed
- **接続先 URL が手元のサーバ(`http://127.0.0.1:8200` など `http` の loopback)のとき、`devbase up` したコンテナの中の
Expand Down
99 changes: 94 additions & 5 deletions containers/base/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -603,17 +603,106 @@ devbase_keep_replaced_link() {
}

# ===================================================================
# PLAN36: VS Code Server の永続ディレクトリ
# PLAN36 / #463: VS Code Server の本体の置き場
# ===================================================================
# ~/.vscode-server にはコンテナ 1 つにつき 1 本の named volume が割り当てられる
# (devbase_vscode_<project>_<index>)。空のボリュームは root 所有で作られるため、
# そのままでは開発ユーザーが VS Code Server をインストールできない。
# ~/.vscode-server/bin には全コンテナ共通の named volume (devbase_vscode-server-bin)
# が付く。本体の版 (bin/<commit>) だけを持ち、extensions/・data/ などはコンテナの
# 書き込みレイヤーに残る。空のボリュームは root 所有で付き、マウント先の親
# ~/.vscode-server も Docker が root 所有で作るため、そのままでは開発ユーザーが
# VS Code Server を置けない。
#
# マウントが無い構成でもディレクトリを作るだけで済み、VS Code の動作は変わらない。

# bin/ に残す本体の版の数 (#463)。1 版は約 0.6GB。VS Code はおおむね月に 1 版のため、
# 別の端末の VS Code が数か月更新されずに古い版で attach していても消しにくい数にする
DEVBASE_VSCODE_SERVER_KEEP=5

# 展開の途中のディレクトリ (bin/<commit>_<ミリ秒>) を残りと見なすまでの分数。
# 展開に 60 分かかることは無いため、動いている展開を消さない
DEVBASE_VSCODE_SERVER_STALE_MINUTES=60

devbase_setup_vscode_server_dir() {
local home_root="$1" owner="${2:-${USERNAME:-ubuntu}}"

devbase_ensure_persistent_root "${home_root}/.vscode-server" "$owner"
devbase_ensure_persistent_root "${home_root}/.vscode-server/bin" "$owner"
devbase_prune_vscode_server_bin "${home_root}/.vscode-server/bin"
}

# ファイルの更新時刻 (UNIX 秒)。GNU / uutils の stat と BSD の stat の両方で読む。
devbase_file_mtime() {
stat -c %Y "$1" 2>/dev/null || stat -f %m "$1" 2>/dev/null
}

# 片付けの 1 つのパスを消す。消せずに残ったときだけ WARNING を出す。
#
# ほかのコンテナの片付けが同時に同じパスを消すことがある。そのとき rm が途中で
# 失敗しても、パスが無くなっていれば WARNING を出さない。終了コードは常に 0。
devbase_remove_vscode_server_path() {
local path="$1" err

err=$(rm -rf -- "$path" 2>&1) && return 0
# ほかのコンテナが消している途中なら、もう一度で消え切る
if [ -e "$path" ] || [ -L "$path" ]; then
err=$(rm -rf -- "$path" 2>&1) && return 0
fi
if [ -e "$path" ] || [ -L "$path" ]; then
echo "WARNING: VS Code Server の片付けで消せなかった: ${path} (${err%%$'\n'*})" >&2
fi
return 0
}

# 共通のボリュームの bin/ を片付ける (#463)。消すのは次の 3 種だけで、bin/ のほかの
# もの・~/.vscode-server の bin 以外には触らない。終了コードは常に 0。
#
# 1. 残す版の数を超えた古い版。版は 40 桁の 16 進の名前で product.json を持つ
# ディレクトリ。product.json の更新時刻の新しい順 (同じなら名前の順) に並べる。
# product.json は片付けが書き換えないため、同時に走る片付けどうしで並びが同じに
# なり、残る版が残す数より減らない (ディレクトリの更新時刻では減った)
# 2. 残った版の直下の入れ子の本体 (product.json を持つディレクトリ)。本体の同時の
# 展開で、遅れた側の中身が bin/<commit>/vscode-server-linux-<arch>/ に残ったもの
# 3. 60 分より古い展開の途中のディレクトリ bin/<commit>_<数字>
devbase_prune_vscode_server_bin() {
local bin="$1" keep="${2:-$DEVBASE_VSCODE_SERVER_KEEP}"
local entry name mtime listing="" count=0 kept=() nested

[ -d "$bin" ] || return 0

for entry in "$bin"/*; do
name="${entry##*/}"
[[ "$name" =~ ^[0-9a-f]{40}$ ]] || continue
[ -d "$entry" ] && [ -f "$entry/product.json" ] || continue
mtime=$(devbase_file_mtime "$entry/product.json") || continue
listing+="${mtime} ${name}"$'\n'
done

while read -r mtime name; do
[ -n "$name" ] || continue
count=$((count + 1))
if [ "$count" -le "$keep" ]; then
kept+=("$name")
else
devbase_remove_vscode_server_path "${bin}/${name}"
fi
done < <(printf '%s' "$listing" | LC_ALL=C sort -k1,1nr -k2,2)

for name in "${kept[@]}"; do
for nested in "${bin}/${name}"/*/; do
nested="${nested%/}"
[ -d "$nested" ] && [ ! -L "$nested" ] || continue
[ -f "${nested}/product.json" ] || continue
devbase_remove_vscode_server_path "$nested"
done
done

while IFS= read -r entry; do
name="${entry##*/}"
[[ "$name" =~ ^[0-9a-f]{40}_[0-9]+$ ]] || continue
devbase_remove_vscode_server_path "$entry"
done < <(find "$bin" -mindepth 1 -maxdepth 1 -type d \
-mmin "+${DEVBASE_VSCODE_SERVER_STALE_MINUTES}" 2>/dev/null)

return 0
}

# ===================================================================
Expand Down Expand Up @@ -781,7 +870,7 @@ USERNAME="${USERNAME:-ubuntu}"
devbase_setup_cloud_config_dirs "$USERNAME"
devbase_setup_gcp_credentials "/home/${USERNAME}"

# 1.5. VS Code Server の永続ディレクトリ (PLAN36)
# 1.5. VS Code Server の本体の置き場と片付け (PLAN36 / #463)
devbase_setup_vscode_server_dir "/home/${USERNAME}" "$USERNAME"

# 2. Setup Git configuration
Expand Down
5 changes: 3 additions & 2 deletions docs/specifications/compose-profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ subcommand より前に置く。`<サービス...>` はプロファイル X に

起動の待ちの後、`cmd_scale` は増やしたインスタンス(`current + 1` から `new`)のうち起動できたものを
後処理の対象にして、`up` と共有する起動の後の処理の段(`_run_post_start`)を呼ぶ。順は
不足リポジトリの報告 → `./deploy` → bao の token → 窓のタイトルの設定で、`up` と同じである。
不足リポジトリの報告 → `./deploy` → bao の token → VS Code Server の `bin` の所有者の直し(#463)→
窓のタイトルの設定で、`up` と同じである。
起動できなかったインスタンスがあると、起動の待ちは `ContainerStartupError`(起動できた番号と、
起動できなかった番号ごとの理由)を投げる。`cmd_scale` はそれを受け、対象へ後処理を行った後に
`Scale failed` と起動できなかった全部の名前・理由・補う手順(`devbase project post-start <name>`)を
Expand Down Expand Up @@ -442,7 +443,7 @@ TUI では、復元境界が機密の注入履歴も戻すため、別プロジ
`os.environ` を変えないこと。起動の非 0 で `Failed to start new containers` と 1 になり例外を
出さないこと。プロファイルのサービスを起動の対象に入れないこと。正常系の順序
(グループの検査 → `write_scale` → ボリューム → network → 生成 → `default_services` → 起動 →
ready 待ち → 不足リポジトリの報告 → `./deploy` → bao の token → 窓のタイトル)、bao と `./deploy` の
ready 待ち → 不足リポジトリの報告 → `./deploy` → bao の token → VS Code Server の `bin` → 窓のタイトル)、bao と `./deploy` の
範囲が `current + 1` から `new` までであること、停止を呼ばないこと
(`tests/commands/test_container_scale_order.py`)。起動できなかったインスタンスがあるときの
後処理の対象と出力(`tests/commands/test_container_post_start.py`)
Expand Down
Loading
Loading