Files
claude-code/README.md
T
claude 1bd0fec23a
Helm Chart Release / release-chart (push) Successful in 12s
Build Session Image / build-push (push) Successful in 2m15s
feat: Alpine ベースの Claude Code リモート実行 Helm チャート初版 (v2.1.259)
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 検証済み
2026-09-03 08:10:12 +09:00

372 lines
24 KiB
Markdown
Raw 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-code
**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 |