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 形式表を追加
12 KiB
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.refresherCronJob (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_FILEenv。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 を実装。
対象ファイル: 全ファイル(初期コミット)