feat: Alpine ベースの Claude Code リモート実行 Helm チャート初版 (v2.1.259)
Helm Chart Release / release-chart (push) Successful in 12s
Build Session Image / build-push (push) Successful in 2m15s

gateway(nginx) + manager(python 標準ライブラリ) + セッションごとの使い捨て Pod +
reaper CronJob の構成。ブラウザ(PC/スマホ)からアクセスし、セッション単位で
独立した Alpine コンテナに Git リポジトリ(GitHub/Gitea など)をチェックアウトして
編集・検証・プッシュする。無操作が続いたセッションは Pod ごと自動破棄。

- セキュリティ: セッション NS 分離 / restricted PodSecurity / RBAC はセッション NS の
  pods,services のみの Role / セッション Pod は SA トークン非マウント・非 root・
  readOnlyRootFilesystem・drop ALL caps・seccomp / NetworkPolicy で egress を
  DNS+HTTPS+SSH に限定 / Git ホスト allow-list / ResourceQuota+LimitRange
- ライフサイクル: idleTimeout(Pod 内ウォッチドッグ + manager 回収) / maxLifetime
  (activeDeadlineSeconds) / maxSessions / 予備の孤児掃除 CronJob
- 認証: token(既定) / basic / forward(外部SSO) / none。WebSocket は Cookie トークン
- Claude 認証: ANTHROPIC_API_KEY または CLAUDE_CODE_OAUTH_TOKEN
- CI: helm-release.yaml(未リリース版のみ tag+release+publish) /
  image-update-and-release.yaml(週次 npm 追従) / session-image.yaml(multi-arch build)
- files/ 実体を .Files.Get で ConfigMap 化。helm lint / template 検証済み
This commit is contained in:
2026-09-03 08:10:12 +09:00
parent 457a81a17f
commit 1bd0fec23a
39 changed files with 3745 additions and 1 deletions
+369 -1
View File
@@ -1,3 +1,371 @@
# claude-code
Alpine based container designed for running Claude Code remotely.
**Alpine ベースの軽量コンテナで Claude Code をリモート実行する Helm チャート。**
ブラウザ(PC / スマートフォン)からアクセスし、**セッションごとに独立した使い捨て Pod** の中で
Git リポジトリ(GitHub / Gitea など互換 Git 全般)をチェックアウト → 編集 → 検証 → プッシュします。
一定時間アイドルなセッションは Pod ごと自動破棄され、リソースを占有し続けません。
Raspberry Pi などの ARM ベアメタル Kubernetes を主な対象にしています。
> **設計目標** — Claude Code は本来ローカルで動かすものだが、これをクラスタにデプロイすることで、
> Git 管理された複数プロジェクトを PC からもスマホからも横断的に、安全に触れるようにする。
- 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>`
---
## 目次
- [アーキテクチャ](#アーキテクチャ)
- [セッションのライフサイクル](#セッションのライフサイクル)
- [セキュリティモデル](#セキュリティモデル)
- [インストール](#インストール)
- [使い方](#使い方)
- [values リファレンス](#values-リファレンス)
- [image](#image)
- [gateway / manager](#gateway--manager)
- [sessionsNamespace](#sessionsnamespace)
- [auth — アクセス認証](#auth--アクセス認証)
- [anthropic — Claude Code 認証情報](#anthropic--claude-code-認証情報)
- [git — 接続先と認証アイデンティティ](#git--接続先と認証アイデンティティ)
- [session — 使い捨てセッション](#session--使い捨てセッション)
- [networkPolicy](#networkpolicy)
- [ingress / service](#ingress--service)
- [セッションイメージ](#セッションイメージ)
- [運用](#運用)
- [トラブルシューティング](#トラブルシューティング)
- [リリースフロー](#リリースフロー)
- [バージョン履歴](#バージョン履歴)
---
## アーキテクチャ
```
┌──────────── リリース NS ────────────┐
ブラウザ (PC/スマホ) │ Deployment: claude-code │
│ HTTPS/WSS │ ┌──────────┐ ┌───────────────┐ │
▼ │ │ gateway │──▶│ manager │ │
Ingress / LB ──────────▶│ │ (nginx) │ │ (python stdlib)│ │
│ │ 認証 │ │ - Web UI │ │
│ │ WS proxy │ │ - Session API │ │
│ └────┬─────┘ │ - 回収ループ │ │
│ │ └───────┬────────┘ │
│ │ ttyd(WS) │ K8s API │
└───────┼─────────────────┼───────────┘
▼ ▼ (Role: pods/services)
┌───────── セッション NS (restricted PSA) ──────────┐
│ Pod claude-sess-ab12cd34ef Pod claude-sess-… │
│ ┌───────────────────────┐ │
│ │ alpine + node + git │ git clone │
│ │ + ttyd + claude-code │ → claude (ttyd) │
│ │ 非root / roFS / netpol│ → claude-verify/push │
│ └───────────────────────┘ アイドルで自壊 │
└────────────────────────────────────────────────┘
```
| コンポーネント | イメージ | 役割 |
|---|---|---|
| **gateway** | `nginxinc/nginx-unprivileged:*-alpine` | 単一入口。`auth.mode` に応じた認証、`/s/<id>/` をセッション Pod の `ttyd` へ WebSocket リバースプロキシ、リクエスト毎にアクティビティ時刻を更新 |
| **manager** | `python:3.x-alpine`(標準ライブラリのみ・追加 pip 不要) | モバイル対応 Web UI、セッション作成/一覧/破棄 API、アイドル/寿命の回収ループ。in-cluster ServiceAccount で Kubernetes API を直接操作 |
| **session** | `git.cafepieters.com/helmchart/claude-code/session`(既定)または任意の node:alpine 系 | セッションごとに作られる **使い捨て Pod**。`git clone` → `claude` を `ttyd` でブラウザに提供 |
| **reaper** | manager と同じイメージ(`--reap-once`) | manager 障害時の保険となる孤児掃除 CronJob |
manager / gateway / session-entrypoint の実体は `files/` にあり、`.Files.Get` で ConfigMap 化されます。
## セッションのライフサイクル
1. **作成** — UI か `POST /api/sessions` に `repo` / `ref` / `identity` を渡す。manager は
- リポジトリ URL の形式と **Git ホスト allow-list**(`git.allowedHosts`)を検証
- 同時セッション数(`session.maxSessions`)を確認
- セッション NS に Pod(`claude-sess-<10hex>`)と Service を作成
2. **ブート**(`files/session-entrypoint.sh`, 非 root)
- マウントされた SSH 鍵 / HTTPS トークンで git 認証を構成(`known_hosts` 必須、TOFU 無効)
- リポジトリを `session.workspaceDir` に `clone`(`--filter=blob:none`)
- `claude` が無ければ `$HOME` に非 root で npm インストール
- `ttyd` を起動(`session.autoStartClaude: true` なら `claude` を自動起動)
3. **利用** — `/s/<id>/` 経由でブラウザ内ターミナルに接続。`claude-verify` / `claude-push` が使える
4. **破棄** — 次のいずれかで Pod ごと消滅(Service も回収)
- **アイドル**: `ttyd` への接続が `session.idleTimeoutSeconds` 秒間ゼロ → Pod 内ウォッチドッグが自壊
- **アイドル(保険)**: manager の回収ループが `last-activity` アノテーションを見て削除
- **最大寿命**: `session.maxLifetimeSeconds`(Pod の `activeDeadlineSeconds`)到達で強制終了
- **手動**: UI の「破棄」/ `DELETE /api/sessions/<id>`
- **孤児掃除**: 予備 CronJob(`session.reaper.cronjob`)
## セキュリティモデル
| 層 | 対策 |
|---|---|
| **入口** | すべて gateway 経由。`auth.mode`= `token`(既定)/ `basic` / `forward`(外部 SSO へ委譲)/ `none`。WebSocket は Cookie トークンで認証(ブラウザは WS に Authorization ヘッダを付けられないため) |
| **制御プレーン RBAC** | manager はセッション NS の `pods` / `services` のみ操作する **Role**(ClusterRole 不使用)。他 NS・他リソースには触れない |
| **セッション Pod** | `automountServiceAccountToken: false`(**API サーバー到達不可**)、`runAsNonRoot` / `readOnlyRootFilesystem` / `capabilities.drop: [ALL]` / `seccompProfile: RuntimeDefault`。書き込み可能なのは emptyDir(`/workspace`, `$HOME`, `/tmp`)のみ |
| **ネットワーク** | NetworkPolicy でセッションの ingress は gateway からのみ。egress は DNS + HTTPS(443, git/Anthropic) + SSH(22)。`networkPolicy.blockedEgressCIDRs`(既定でクラウドメタデータ IP `169.254.169.254/32`)を egress の `except` に指定。自クラスタの Pod/Service CIDR を追加すると内部 SSRF も遮断できる |
| **Git 到達先** | `git.allowedHosts` の allow-list。既定は allow-list 外を拒否(`allowArbitraryRepos: true` で解除) |
| **認証情報** | `ANTHROPIC_API_KEY` / SSH 鍵 / トークンは Kubernetes Secret。`values.yaml` に平文で書かず `--set` / `--set-file` / `existingSecret` で注入。git HTTPS トークンはセッション内で `credential.helper store` の 0600 ファイルに限定し、プロセス環境に残さない |
| **PodSecurity** | セッション NS に `pod-security.kubernetes.io/enforce: restricted` を付与(`sessionsNamespace.create: true` 時) |
| **ブラスト半径** | `ResourceQuota`(Pod / Service 数)+ `LimitRange`(コンテナ CPU/メモリ上限)+ `session.maxSessions` |
| **自動 push** | 既定 **無効**。有効時もデフォルト/保護ブランチ(`autoPush.protectedBranches`)への push と `--force` は不可。`branchPrefix` 配下の作業ブランチにのみ push |
> **注意** — `values.yaml` に API キーや秘密鍵を書いてコミットしないでください。`helm get values` /
> CI ログ / Git 履歴に残ります。`existingSecret` か CI からの `--set` を使ってください。
## インストール
### 前提
- Kubernetes 1.25+(PodSecurity admission)、NetworkPolicy 対応 CNI(Calico / Cilium など)
- Ingress コントローラー(外部公開する場合。WebSocket を通すため read/send timeout を延長)
- `ANTHROPIC_API_KEY`(または `claude setup-token` で発行した OAuth トークン)
### Helm リポジトリから
```bash
helm repo add cafepieters https://git.cafepieters.com/api/packages/helmchart/helm
helm repo update
helm upgrade --install claude-code cafepieters/claude-code \
-n claude-code --create-namespace \
-f my.values.yaml \
--set anthropic.apiKey="$ANTHROPIC_API_KEY"
```
### ローカルチャートから(GitHub 公開リポジトリだけ触る最小構成)
```bash
helm upgrade --install claude-code ./claude-code \
-n claude-code --create-namespace \
-f examples/minimal.values.yaml \
--set anthropic.apiKey="$ANTHROPIC_API_KEY"
```
### Gitea(SSH) + GitHub(HTTPS) 両対応
```bash
helm upgrade --install claude-code ./claude-code \
-n claude-code --create-namespace \
-f examples/gitea-and-github.values.yaml \
--set anthropic.apiKey="$ANTHROPIC_API_KEY" \
--set-file git.identities.gitea-ssh.sshPrivateKey=P:/Claude/.ssh/id_claude \
--set-file git.identities.gitea-ssh.knownHosts=./known_hosts.gitea \
--set git.identities.github-https.token="$GITHUB_PAT"
```
`known_hosts` は事前に取得します:
```bash
ssh-keyscan 192.168.9.65 > known_hosts.gitea
```
## 使い方
1. アクセス(Ingress 無効ならポートフォワード):
```bash
kubectl -n claude-code port-forward svc/claude-code 8080:80
```
2. `auth.mode: token` の場合、トークンを取得して UI に貼り付け(または `?token=` で開く):
```bash
kubectl -n claude-code get secret claude-code-auth \
-o jsonpath='{.data.token}' | base64 -d ; echo
```
3. UI で **リポジトリ URL** / **ブランチ** / **認証 identity** を指定して「セッション作成」。
4. 一覧の「開く」でブラウザ内ターミナル(Claude Code)に接続。
5. セッション内の補助コマンド:
- `claude-verify` … `session.verifyCommand`(例 `npm test`)を実行
- `claude-push` … 検証 → `claude/<branch>` へ push(保護ブランチ / `--force` 不可)
6. 無操作 `session.idleTimeoutSeconds` 秒でセッション(Pod)は自動的に消えます。
## values リファレンス
### image
| キー | 既定 | 説明 |
|---|---|---|
| `image.gateway.*` | `nginxinc/nginx-unprivileged:1.29.1-alpine` | 受付 nginx(非 root 版) |
| `image.manager.*` | `library/python:3.13-alpine` | 制御プレーン(標準ライブラリのみ) |
| `image.session.*` | `library/node:22-alpine` | セッション。既定はブート時に `apk`/`npm` を実行するため初回起動が遅い。[セッションイメージ](#セッションイメージ)参照 |
| `imagePullSecrets` | `[]` | プライベートレジストリ用 |
### gateway / manager
| キー | 既定 | 説明 |
|---|---|---|
| `gateway.replicaCount` | `1` | 制御プレーン Deployment のレプリカ数 |
| `gateway.port` | `8080` | gateway コンテナ待受ポート(Service / Ingress バックエンド) |
| `manager.logLevel` | `info` | `debug` / `info` / `warning` / `error` |
| `gateway.resources` / `manager.resources` | 控えめ | それぞれの resources |
### sessionsNamespace
| キー | 既定 | 説明 |
|---|---|---|
| `sessionsNamespace.name` | `claude-code-sessions` | セッション Pod を隔離する NS(空 = リリース NS) |
| `sessionsNamespace.create` | `true` | この NS を作成し PodSecurity ラベルを付与するか。既存 NS を使うなら `false` にして手動でラベル付与 |
| `sessionsNamespace.podSecurityLevel` | `restricted` | 付与する PodSecurity `enforce` レベル |
| `sessionsNamespace.resourceQuota.enabled` | `true` | セッション NS の `ResourceQuota`(既定は Pod/Service 数の抑制のみ。compute 集計上限は `hard` で明示) |
| `sessionsNamespace.resourceQuota.hard` | `{}` | 指定するとそのまま `spec.hard` |
| `sessionsNamespace.limitRange.*` | max 4CPU/4Gi | セッション NS のコンテナ既定値・上限(`LimitRange`) |
### auth — アクセス認証
| キー | 既定 | 説明 |
|---|---|---|
| `auth.mode` | `token` | `token` / `basic` / `forward` / `none` |
| `auth.token.value` | `""` | 空なら install 時に自動生成(`lookup` で再 install 間も安定)。運用では `existingSecret` 推奨 |
| `auth.token.existingSecret` / `existingSecretKey` | `""` / `token` | 既存 Secret からトークンを読む |
| `auth.basic.users` | `[]` | `htpasswd -nbB user pass` の出力を 1 行以上 |
| `auth.basic.existingSecret` / `existingSecretKey` | `""` / `htpasswd` | 既存 htpasswd Secret |
| `auth.forward.url` | `""` | `auth_request` の転送先(例: oauth2-proxy の `/oauth2/auth`) |
| `auth.forward.signInUrl` | `""` | 未認証時のサインイン URL(任意) |
`token` モードでは UI のログインフォームで一度トークンを入力すると、`HttpOnly` Cookie に保存され
以降の `/s/<id>/`(WebSocket 含む)に自動的に付与されます。
### anthropic — Claude Code 認証情報
| キー | 既定 | 説明 |
|---|---|---|
| `anthropic.authMode` | `apiKey` | `apiKey`(`ANTHROPIC_API_KEY`)/ `oauth`(`CLAUDE_CODE_OAUTH_TOKEN`) |
| `anthropic.apiKey` / `anthropic.oauthToken` | `""` | `--set` / `--set-file` で注入 |
| `anthropic.existingSecret` | `""` | 既存 Secret を使う(キー名は `existingSecretKeyApiKey` / `existingSecretKeyOauthToken`) |
| `anthropic.extraEnv` | `{}` | 全セッションへ渡す追加 env(例 `ANTHROPIC_BASE_URL`、Bedrock/Vertex 切替など) |
Secret は **セッション NS** に作成され、セッション Pod へ `envFrom` で注入されます。
### git — 接続先と認証アイデンティティ
| キー | 既定 | 説明 |
|---|---|---|
| `git.allowedHosts` | GitHub/GitLab/Gitea | clone を許可するホスト allow-list |
| `git.allowArbitraryRepos` | `false` | allow-list を無効化し任意 URL を許可(非推奨) |
| `git.defaultAuthorName` / `Email` | `Claude` / `claude@cafepieters.com` | コミット author 既定 |
| `git.identities.<name>.type` | — | `ssh` / `https-token` |
| `…ssh.sshPrivateKey` / `knownHosts` | — | PEM 秘密鍵 / `ssh-keyscan` 出力(**`knownHosts` 必須**) |
| `…https-token.username` / `token` | `x-access-token` / — | HTTPS ベーシック(GitHub PAT は username 任意) |
| `…existingSecret` ほか | — | 既存 Secret 参照(キー名は `existingSecretKey*` で調整) |
GitHub でも Gitea でも GitLab でも、SSH か HTTPS トークンで認証できる Git ホストなら同じ仕組みで扱えます。
セッション作成時に identity 名を選ぶと、その Secret だけがそのセッション Pod にマウントされます。
### session — 使い捨てセッション
| キー | 既定 | 説明 |
|---|---|---|
| `session.autoStartClaude` | `true` | ブート後に `claude` を自動起動(`false` はログインシェル) |
| `session.workspaceDir` | `/workspace` | clone 先 |
| `session.ttydPort` | `7681` | `ttyd` 待受(Pod 内のみ) |
| `session.extraApkPackages` | `[]` | 追加 apk(事前ビルドイメージなど root 権限がある場合のみ有効) |
| `session.claudeCodeVersion` | `""` | インストールする `@anthropic-ai/claude-code` バージョン(空 = チャート `appVersion`) |
| `session.resources` | 100m/256Mi 〜 2CPU/2Gi/4Gi(eph) | セッション Pod の resources |
| `session.idleTimeoutSeconds` | `1800` | 無通信での破棄しきい値 |
| `session.maxLifetimeSeconds` | `43200` | Pod の `activeDeadlineSeconds` |
| `session.reaper.intervalSeconds` | `60` | manager 回収ループ間隔 |
| `session.reaper.cronjob.enabled` / `schedule` | `true` / `*/15 * * * *` | 予備の孤児掃除 CronJob |
| `session.maxSessions` | `10` | 同時セッション数上限(manager が enforce) |
| `session.verifyCommand` | `""` | `claude-verify` / `claude-push` が実行するコマンド |
| `session.autoPush.enabled` | `false` | `claude-push` を許可するか |
| `session.autoPush.branchPrefix` | `claude/` | push 先ブランチのプレフィックス |
| `session.autoPush.protectedBranches` | `[main, master, develop, release]` | push 禁止ブランチ |
| `session.podLabels` / `podAnnotations` / `nodeSelector` / `tolerations` / `priorityClassName` | — | セッション Pod へのメタデータ / スケジューリング |
### networkPolicy
| キー | 既定 | 説明 |
|---|---|---|
| `networkPolicy.enabled` | `true` | NetworkPolicy を作成するか(CNI が対応必須) |
| `networkPolicy.dnsNamespaceSelector` | `kube-system` | DNS を許可する NS セレクタ |
| `networkPolicy.allowInternetHttps` | `true` | セッションの 443/tcp 外向きを許可(git HTTPS + Anthropic API) |
| `networkPolicy.allowSshGit` | `true` | セッションの 22/tcp 外向きを許可(SSH git) |
| `networkPolicy.blockedEgressCIDRs` | `[169.254.169.254/32]` | egress `except`。自クラスタの Pod/Service CIDR を足すと内部 SSRF を遮断 |
| `networkPolicy.sessionEgressExtra` | `[]` | 追加許可(社内ミラー / プロキシ)。`{cidr, ports[]}` |
完全にインターネットを遮断したい場合は `allowInternetHttps: false` にして egress プロキシ
(例: 許可リスト付き Squid)を `sessionEgressExtra` で通してください。
### ingress / service
`ingress.enabled: true` で Ingress を作成。WebSocket 用に `proxy-read-timeout` /
`proxy-send-timeout` を既定 `3600` に設定します(`ingress.annotations` で上書き可)。
`service.type` は `ClusterIP` 既定。
## セッションイメージ
既定の `image.session` は CI(`session-image.yaml`)がビルドする **事前ビルドイメージ**
`git.cafepieters.com/helmchart/claude-code/session:<appVersion>` です。
`git` / `openssh-client` / `ttyd` / `bash` / `node` / `@anthropic-ai/claude-code` を同梱し、
非 root(uid 10001)で動作するため、`restricted` PodSecurity / `readOnlyRootFilesystem` 下でも
確実に起動し、コールドスタートも数秒です。
`session-image.yaml` は `files/Dockerfile.session` 等の変更 push、または
`image-update-and-release.yaml` による `Chart.yaml` 更新で発火し、`linux/amd64,linux/arm64` の
2 アーキテクチャでビルドして Gitea Container Registry へ push します。手動ビルドは:
```bash
docker buildx build --platform linux/amd64,linux/arm64 \
--build-arg CLAUDE_CODE_VERSION=2.1.259 \
-f files/Dockerfile.session \
-t git.cafepieters.com/helmchart/claude-code/session:2.1.259 --push .
```
### 事前ビルドを使わない場合
`image.session` に素の `node:22-alpine` などを指定することもできます。この場合ブート
スクリプトが `$HOME` に非 root で `@anthropic-ai/claude-code` を npm インストールします
(初回数十秒)。ただし **`ttyd` は非 root では `apk add` できない** ため、`ttyd` を含まない
イメージでは起動に失敗します。`ttyd` 入りの独自イメージを用意するか、事前ビルドイメージを
使ってください。
## 運用
- **セッション一覧**: `kubectl -n <sessionsNamespace> get pods -l app.kubernetes.io/component=session`
- **セッションのログ**: `kubectl -n <sessionsNamespace> logs claude-sess-<id>`
- **強制破棄**: UI から、または `kubectl -n <sessionsNamespace> delete pod,svc claude-sess-<id>`
- **回収の確認**: manager のログに `reaping session <id> (idle|max-lifetime|phase=...)`
- **トークンのローテーション**: `auth.token.existingSecret` の値を更新し、Deployment を再起動
- **アップグレード**: `helm upgrade`。`files/*` の変更は checksum アノテーションで自動ローリング
## トラブルシューティング
| 症状 | 原因と対処 |
|---|---|
| UI が 502 / セッションを開くと 502 | セッション Pod がまだ Ready でない(初回は `npm i` に時間)。数十秒待つ。恒久対策は事前ビルドイメージ |
| セッション作成が `許可されていない Git ホスト` | `git.allowedHosts` に対象ホストを追加(IP と FQDN は別物) |
| clone が `Host key verification failed` | identity の `knownHosts` が対象ホストの鍵と不一致。`ssh-keyscan <host>` で取り直す |
| clone が `terminated ... could not read Username` | HTTPS の場合 `git.identities.<name>` 未指定 or token 無効。SSH の場合は identity の type/秘密鍵を確認 |
| WebSocket がすぐ切れる | Ingress の `proxy-read-timeout` を延長。`auth.mode: token` で Cookie 未設定なら一度 UI からログイン |
| セッションが破棄されない | manager の RBAC / ログを確認。予備 CronJob(`session.reaper.cronjob`)が有効か |
| `apk` エラーがログに出る | 既定イメージ + `readOnlyRootFilesystem` の制約。事前ビルドイメージを使う |
| manager が全リクエストを 401 | `auth.mode: token` でトークンが空。`auth.token.value` か `existingSecret` を設定 |
## リリースフロー
`Chart.yaml` の `version` / `appVersion` は **Claude Code CLI(`@anthropic-ai/claude-code` npm 最新版)と同一**。
- **`helm-release.yaml`** — `main` push 時に Gitea Package Registry へチャートを publish(全リポジトリ共通)。
- **`image-update-and-release.yaml`** — 毎週月曜 3:00 JST。
- npm の Claude Code 最新版に追従。**主アプリ更新時のみ** `Chart.yaml` 更新 → セッションイメージ
multi-arch ビルド/push → Git タグ `v<ver>` → Gitea リリース → チャート publish。
- `nginx` / `python` の Alpine タグのみ更新の場合は `values.yaml` を更新してコミットするだけ
(**リリースなし**)。
- **手動リリース(臨時)** — バージョン末尾にアルファベットを付与(`2.1.259` → `2.1.259-a`)。
対応する `CHANGELOG-<version>.md` を追加する。
必要な Gitea Secrets: `GITEA_TOKEN` / `REGISTRY_USER` / `REGISTRY_TOKEN`。
### ワークフロー一覧
| ファイル | トリガー | 動作 |
|---|---|---|
| `helm-release.yaml` | `main` への push / 手動 | `helm lint`。`Chart.yaml` の version が未リリース(Gitea リリース・Package Registry 双方に無い)なら タグ + Gitea リリース + チャート publish。リリース済みなら lint のみ |
| `image-update-and-release.yaml` | 毎週月曜 3:00 JST / 手動 | npm の `@anthropic-ai/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` ほかの変更 / 手動 | セッションイメージ(`.../claude-code/session`)を `linux/amd64,linux/arm64` でビルドし、`Chart.yaml` の `appVersion` タグ + `latest` で Gitea Container Registry へ push |
## バージョン履歴
| バージョン | Claude Code | 変更内容 |
|---|---|---|
| 2.1.259 | 2.1.259 | 初版。gateway + manager + 使い捨て session Pod + reaper、GitHub/Gitea 対応、アイドル自動破棄、NetworkPolicy / RBAC 最小化 / restricted PodSecurity |