Files
claude-code/CLAUDE.md
T
claude 1b74e230ad
Helm Chart Release / release-chart (push) Successful in 7s
Build Session Image / build-push (push) Successful in 2m3s
feat: 失敗セッションの調査性を改善(終了Pod保持 + ログAPI + UI)(v2.1.263-d)
セッション Pod がブート失敗で Failed になると reaper が即削除し kubectl logs で
死因を追えなかった。「開く」で 502 になるだけで原因不明だった。

- session.reaper.terminatedRetentionSeconds(既定 900): 終了済み Pod を
  finishedAt からこの秒数は回収しない。manager 回収ループと reaper CronJob 両方が尊重
- GET /api/sessions/<id>/log: セッション Pod のログを text で返す(pods/log get のみ、追加権限なし)
- UI: 「ログ」ボタン、状態の色分け、Failed 行に reason/exitCode/message 併記、
  Running 以外は「開く」非表示
- session-entrypoint.sh: URL スキームと identity 型の不一致を警告。
  git clone を --progress ... 2>&1 にして git/ssh の出力を Pod ログへ
- helm lint / template 検証済み
2026-09-08 21:14:56 +09:00

153 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md — claude-code Helm Chart
> **共通ルール(要約)** — 詳細は `P:\Claude\CLAUDE.md`(全体共通)と `P:\Claude\HelmChart\CLAUDE.md`(Helm チャート共通: リリースフロー・ワークフロー・Gitea Secrets)を参照。
> 作業前に pull / 機能変更時は README 更新 / 作業単位ごとに commit → push まで / コミットに AI クレジットを付けない / pull で入った変更を revert しない / Helm はローカル実行不可(Python のみ可)。
## リポジトリ概要
Alpine Linux ベースの軽量コンテナで **Claude Code をリモート実行** するための Helm チャート。
ブラウザ(PC / スマートフォン)からアクセスし、**セッションごとに独立した使い捨て Pod** で
Git リポジトリ(GitHub / Gitea など互換 Git 全般)をチェックアウト・編集・検証・プッシュする。
一定時間アイドルなセッション Pod は自動破棄される。Raspberry Pi などの ARM ベアメタル運用を想定。
- **Gitea リポジトリ**: `ssh://git@192.168.9.65/helmchart/claude-code`
- **Helm リポジトリ**: `https://git.cafepieters.com/api/packages/helmchart/helm`
- **セッションイメージ**: `git.cafepieters.com/helmchart/claude-code/session:<appVersion>`(CI で publish)
> **注意**: セッション Pod は Gitea からリポジトリ単体を clone するため、`P:\Claude` の上位階層 CLAUDE.md は届かない。各リポジトリの CLAUDE.md 先頭に「共通ルール(要約)」を置く理由はこれ。
## アーキテクチャ(要点)
| コンポーネント | 実体 | 役割 |
|---|---|---|
| `gateway` | `nginxinc/nginx-unprivileged:alpine` | 単一入口。認証(token/basic/forward)、WebSocket リバースプロキシ、アクティビティ計測 |
| `manager` | `python:3.x-alpine`(標準ライブラリのみ) | セッション CRUD API、Web UI、アイドル/寿命回収ループ。in-cluster SA で K8s API を直接操作 |
| `session` | Alpine + node + git + ttyd + claude-code | セッションごとに作られる使い捨て Pod。`git clone` → `claude`(ttyd) → `claude-verify`/`claude-push` |
| `reaper` CronJob | `manager` イメージ `--reap-once` | manager 障害時の保険となる孤児掃除 |
- 制御プレーンはリリース NS、セッション Pod は専用 NS(`sessionsNamespace.name`)に分離。
- manager の RBAC はセッション NS の `pods` / `services` に限定した Role のみ(ClusterRole 不使用)。
- セッション Pod は **API サーバー到達不可**(`automountServiceAccountToken: false`)、
非 root / `readOnlyRootFilesystem` / drop ALL caps / seccomp RuntimeDefault、
egress は DNS + git ホスト + `api.anthropic.com` のみ(NetworkPolicy)。
- ファイル実体は `files/`(`.Files.Get` で ConfigMap 化): `manager.py` / `session-entrypoint.sh`
/ `gateway.conf.template` / `gateway-entrypoint.sh` / `Dockerfile.session`。
## README 更新時の追加事項
- values の新設キー、挙動変更、セキュリティ影響は README の該当セクションと values リファレンス表へ反映する。
- 手動リリース(`-a` 等)時は対応する `CHANGELOG-<version>.md` を追加し、README の「バージョン履歴」にも 1 行追加する(このリポジトリの慣行)。
## リリースフロー(組織ルールとの差分)
- **バージョン番号**: `Chart.yaml` の `version` / `appVersion` は
**主アプリ = Claude Code CLI(`@anthropic-ai/claude-code` の npm 最新版)と同一**にする。
- **ワークフロー(3 本)**
- `helm-release.yaml` — `main` への push で発火。`helm lint` の後、`Chart.yaml` の version が
未リリース(Gitea リリース・Package Registry 双方に存在しない)なら タグ + Gitea リリース +
チャート publish。リリース済みなら lint のみで終了(再 publish しない)。
- `image-update-and-release.yaml` — 毎週月曜 3:00 JST。npm の Claude Code 最新版と
base image(nginx / python)の最新 Alpine タグを確認。Claude Code 更新時は
`values.yaml` / `Chart.yaml` / README 履歴を更新しコミット → タグ + リリース + publish。
base image のみ更新時は `values.yaml` を更新してコミットのみ(**リリースなし**)。
- `session-image.yaml` — `files/Dockerfile.session` 等の変更、または上記による `Chart.yaml`
更新で発火。セッションイメージを `linux/amd64,linux/arm64` でビルドして
Gitea Container Registry(`helmchart/claude-code/session:<appVersion>` + `latest`)へ push。
- **手動リリース(臨時)**: 例 `2.1.259` → `2.1.259-a` → `2.1.259-b`。
## 改修履歴
### 失敗セッションの調査性改善(終了 Pod の保持 + ログ API + UI)(2026-09-08, v2.1.263-d)
**症状**: セッション Pod がブート失敗で `Failed` になると reaper が即削除し、`kubectl logs` で
死因を追えない。UI では「開く」で 502 になるだけ。
**修正内容**:
- `session.reaper.terminatedRetentionSeconds`(既定 900)を追加。終了済み Pod を
`finishedAt` からこの秒数は残す。`manager.py` の `reap_once` と reaper CronJob の両方が尊重。
- `GET /api/sessions/<id>/log`(`k8s_text` で pods/log を text 取得。追加 RBAC 不要)。
- UI: 「ログ」ボタン、状態の色分け、`Failed` 行に reason/exitCode/message 併記、
`Running` 以外は「開く」非表示。
- `session-entrypoint.sh`: URL スキームと identity 型の不一致を警告。`git clone` を
`--progress ... 2>&1` にして git/ssh 出力を Pod ログへ。
**対象ファイル**: `files/manager.py`, `files/session-entrypoint.sh`, `values.yaml`,
`values.schema.json`, `templates/deployment.yaml`, `templates/cronjob-reaper.yaml`,
`README.md`, `Chart.yaml`, `CHANGELOG-2.1.263-d.md`
### gateway nginx クラッシュループ修正(location 正規表現のクォート)(2026-09-08, v2.1.263-c)
**症状**: gateway コンテナが起動直後に
`nginx: [emerg] pcre2_compile() failed: missing closing parenthesis in "^/s/(?<sid>[a-f0-9]"`
で終了し、CrashLoopBackOff。
**原因**: `files/gateway.conf.template` の
`location ~ ^/s/(?<sid>[a-f0-9]{10})(?<rest>/.*)?$ { ... }` で、正規表現中の `{10}` の
`{` `}` を nginx の設定パーサーがブロック区切りと解釈し、`location` の regex が
`^/s/(?<sid>[a-f0-9]` で切れていた(nginx は `{` `}` `;` を含む正規表現のクォートを必須とする)。
**修正内容**: `location ~ "^/s/(?<sid>[a-f0-9]{10})(?<rest>/.*)?$" { ... }` と
正規表現全体をダブルクォートで囲んだ。envsubst の対象は `${...}` の 6 変数のみで
`{10}` には影響しないことを確認済み。
**対象ファイル**: `files/gateway.conf.template`, `README.md`, `Chart.yaml`, `CHANGELOG-2.1.263-c.md`
### 認証情報の credentials モード + トークン自動リフレッシュ(2026-09-08, v2.1.263-b)
**背景**: サブスクリプションのアクセストークンは定期的に失効・ローテーションする。単発
トークン注入では失効のたびに `helm upgrade` が必要だった。
**症状**: あわせて、一部の Helm バージョンで `values.schema.json` の
`$schema: https://json-schema.org/draft-07/schema#` が
`no schema with key or ref ...` エラーになる不具合。
**修正内容**:
- `anthropic.authMode: credentials`(新既定): `~/.claude/.credentials.json` 全体を Secret に
格納 →(a)セッション Pod にファイルとしてマウントし `$HOME/.claude` へコピー、セッション内
`claude` が `refreshToken` で自己更新。(b)`anthropic.refresher` CronJob
(`files/token-refresher.py`、専用 SA + `resourceNames` 限定 Role で該当 Secret の get/patch のみ)
がクラスタ内で `accessToken` を定期更新し Secret を書き戻す。`tokenUrl` / `clientId` は
Claude Code CLI の非公式値で values 上書き可。
- `manager.py` の `build_pod`: credentials モードは `envFrom` を使わずファイルマウント +
`SEED_CREDENTIALS_FILE` env。apiKey/oauth は従来どおり `envFrom`。
- Secret に `helm.sh/resource-policy: keep`(credentials 時)。
- `values.schema.json` の `$schema` 行を削除(他チャートと同じ。Helm は draft-07 で検証)。
**対象ファイル**: `values.yaml`, `values.schema.json`, `templates/secret-anthropic.yaml`,
`templates/deployment.yaml`, `templates/configmap-manager.yaml`, `templates/token-refresher.yaml`(新規),
`templates/NOTES.txt`, `files/manager.py`, `files/session-entrypoint.sh`,
`files/token-refresher.py`(新規), `examples/loadbalancer-oauth.values.yaml`, `README.md`,
`Chart.yaml`, `CHANGELOG-2.1.263-b.md`
### Service の LoadBalancer 対応 + サブスクリプション認証手順の明文化(2026-09-08, v2.1.263-a)
**背景**: Ingress を張らずに、ローカルネットワークの LB(kube-vip 等)から払い出した IP で
管理画面へアクセスしたい、という運用要望。あわせて「Claude の API 課金を使わず、ローカルの
Claude Code と同様にサブスクリプションで使いたい」という確認があった。
**修正内容**:
- `templates/service.yaml` を書き換え、`service.type: LoadBalancer` を既定化。
`service.annotations`(kube-vip の `kube-vip.io/loadbalancerIPs` / `vipHost` 等)、
`loadBalancerIP` / `loadBalancerClass` / `loadBalancerSourceRanges` /
`externalTrafficPolicy` / `nodePort` / `labels` を追加。Ingress 機能は変更なし(併用可)。
- `values.yaml` の `service:` ブロック拡張、`values.schema.json` に対応プロパティ追加。
- `templates/NOTES.txt` に LoadBalancer の EXTERNAL-IP 案内を追加。
- `examples/loadbalancer-oauth.values.yaml` を追加(Ingress 無効 + LB + source range +
`authMode: oauth`)。
- README に「Claude 認証(API 課金なし / サブスクリプション)」「管理画面へのアクセス
(LoadBalancer / Ingress)」セクションを追加。サブスクリプション認証は
`claude setup-token` → `anthropic.authMode: oauth`(`CLAUDE_CODE_OAUTH_TOKEN` を
セッション Pod に注入)で、ローカル実行の Claude Code と同一挙動。
**対象ファイル**: `templates/service.yaml`, `values.yaml`, `values.schema.json`,
`templates/NOTES.txt`, `examples/loadbalancer-oauth.values.yaml`, `README.md`, `Chart.yaml`,
`CHANGELOG-2.1.263-a.md`
### 初版(2026-09-03, v2.1.259)
チャート新規作成。gateway + manager + 使い捨て session Pod + reaper CronJob の構成で、
ブラウザからの Claude Code リモート実行、GitHub/Gitea 両対応、アイドル自動破棄、
NetworkPolicy / RBAC 最小化 / restricted PodSecurity を実装。
**対象ファイル**: 全ファイル(初期コミット)