claude@host:path のような SSH ユーザー違いの URL が「形式が不正」で弾かれ 原因が分かりにくかった。Gitea/GitHub の SSH ユーザーは常に git。 - REPO_RE を ssh://<user>@host/… / <user>@host:path / host:path も受理するよう緩和 (// 始まりは拒否、ホスト allowlist は全形式に適用) - URL 形式エラーで受理形式と「SSH ユーザーは常に git」を明記、 ホスト不許可で許可済み一覧を併記 - UI のリポジトリ URL 入力欄にヒントを追加、README に URL 形式表を追加
166 lines
12 KiB
Markdown
166 lines
12 KiB
Markdown
# 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`。
|
||
|
||
## 改修履歴
|
||
|
||
### リポジトリ URL バリデーション緩和 + エラーメッセージ具体化(2026-09-09, v2.1.263-e)
|
||
|
||
**症状**: `claude@192.168.9.65:...`(SSH ユーザーをアカウント名にした URL)が
|
||
`リポジトリ URL の形式が不正です` で弾かれ、原因が分かりにくい。Gitea/GitHub の SSH
|
||
ユーザーは常に `git`。
|
||
|
||
**修正内容**: `manager.py` の `REPO_RE` を `ssh://<user>@host/…` / `<user>@host:path` /
|
||
`host:path` も受理するよう緩和(`//` 始まりは拒否、ホスト allowlist は全形式に適用)。
|
||
URL 形式エラーで受理形式と「SSH ユーザーは常に `git`」を明記、ホスト不許可で許可済み
|
||
一覧を併記。UI 入力欄にヒント追加。README の git セクションに URL 形式表を追加。
|
||
|
||
**対象ファイル**: `files/manager.py`, `README.md`, `Chart.yaml`, `CHANGELOG-2.1.263-e.md`
|
||
|
||
### 失敗セッションの調査性改善(終了 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 を実装。
|
||
|
||
**対象ファイル**: 全ファイル(初期コミット)
|