Files
claude-code/README.md
T
claude cd7092be17
Helm Chart Release / release-chart (push) Successful in 7s
Build Session Image / build-push (push) Successful in 2m3s
feat: Service を LoadBalancer 対応にしローカル LB の IP で管理画面へアクセス可能に (v2.1.263-a)
- templates/service.yaml: service.type 既定を LoadBalancer に。annotations
  (kube-vip の VIP 指定等) / loadBalancerIP / loadBalancerClass /
  loadBalancerSourceRanges / externalTrafficPolicy / nodePort / labels を追加。
  Ingress 機能は変更なし(LoadBalancer と併用可)
- values.yaml / values.schema.json: service ブロックを拡張
- 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 注入)でローカル実行と同一挙動
- helm lint / template 検証済み
2026-09-08 14:01:34 +09:00

31 KiB
Raw Permalink Blame History

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>

目次


アーキテクチャ

                         ┌──────────── リリース 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 を使ってください。

Claude 認証(API 課金なし / サブスクリプション)

このチャートは Claude の API(従量課金)を使わずに、ローカルの Claude Code と同じ サブスクリプション認証(Pro / Max プラン) で動かせます。セッション内の claude の 挙動・機能はローカル実行と同一です(同じ CLI・同じログイン方式)。

  1. 手元の PC(Claude にログイン済み)で長期トークンを発行:

    claude setup-token
    

    ブラウザで承認すると CLAUDE_CODE_OAUTH_TOKEN として使える長期トークンが表示されます。

  2. それをチャートに渡す(authMode: oauth):

    helm upgrade --install claude-code cafepieters/claude-code -n claude-code --create-namespace \
      -f examples/loadbalancer-oauth.values.yaml \
      --set anthropic.oauthToken="<発行されたトークン>"
    

    Secret にしておく場合:

    kubectl -n claude-code-sessions create secret generic claude-oauth \
      --from-literal=CLAUDE_CODE_OAUTH_TOKEN="<トークン>"
    # values: anthropic.existingSecret=claude-oauth
    
方式 values 認証情報 課金
サブスクリプション(推奨) anthropic.authMode: oauth anthropic.oauthToken(claude setup-token) Claude プランの利用枠を消費(API 課金なし)
API キー anthropic.authMode: apiKey anthropic.apiKey(sk-ant-...) API 従量課金
  • トークンは セッション NS の Secret に保存され、セッション Pod へ環境変数 CLAUDE_CODE_OAUTH_TOKEN として注入されます(values.yaml に平文で書かない)。
  • 利用枠はローカルの Claude Code と共有です。複数セッションを同時に走らせると プランのレート上限に早く達する点に注意してください。
  • トークンには有効期限があります。失効したら claude setup-token で再発行し helm upgrade --set anthropic.oauthToken=...(または Secret 更新 + Pod 再起動)します。

管理画面へのアクセス(LoadBalancer / Ingress)

管理画面(gateway)への到達経路は 2 つあり、併用できます。既定は LoadBalancer です。

A. LoadBalancer でローカルネットワークの IP を使う(既定・Ingress 不要)

service.type: LoadBalancer(既定)にすると、クラスタの LB 実装 (kube-vip / MetalLB / Cilium LB-IPAM など)がローカルネットワークの IP を払い出します。 その IP をブラウザで開くだけでアクセスできます。ドメインも Ingress も TLS 終端も不要です。

ingress:
  enabled: false                 # Ingress は張らない
service:
  type: LoadBalancer
  port: 80
  annotations:
    kube-vip.io/loadbalancerIPs: "192.168.9.50"   # 払い出す VIP(空きアドレス)
    kube-vip.io/vipHost: "cpi11"
  loadBalancerSourceRanges:      # 接続元をローカルセグメントに限定(第一の防御線)
    - 192.168.9.0/24
  externalTrafficPolicy: Local   # 実クライアント IP を保持
kubectl -n claude-code get svc claude-code       # EXTERNAL-IP を確認
# → http://<EXTERNAL-IP>/ をブラウザで開く
キー 説明
service.type LoadBalancer(既定)/ ClusterIP / NodePort
service.port 待受ポート(既定 80)
service.annotations LB 実装へのヒント(kube-vip の VIP 指定、MetalLB のプール指定など)
service.loadBalancerIP 払い出す IP を直接指定(annotations 指定を推奨)
service.loadBalancerSourceRanges 接続を許可する CIDR。Ingress を張らない構成では必ず設定して接続元を絞る
service.loadBalancerClass 複数 LB 実装がある場合の指定
service.externalTrafficPolicy Local で実クライアント IP を保持
service.nodePort type: NodePort 時の固定ポート

セキュリティ — LoadBalancer は L3/L4 でネットワークに口を開けます。loadBalancerSourceRanges で接続元を絞り、auth.mode は token(既定)以上にしてください。VIP セグメントは ルーターの DHCP 範囲と重複させないこと。

B. Ingress でドメインアクセス(従来どおり維持)

ingress.enabled: true で Ingress を作成します。A と同時に有効化しても構いません。 WebSocket 用に proxy-read-timeout / proxy-send-timeout を既定 3600 に設定します (ingress.annotations で上書き可)。TLS は ingress.tls で設定します。

ingress:
  enabled: true
  className: nginx
  hosts:
    - host: claude-code.example.com
      paths: [{ path: /, pathType: Prefix }]
  tls:
    - secretName: claude-code-tls
      hosts: [claude-code.example.com]

インストール

前提

  • Kubernetes 1.25+(PodSecurity admission)、NetworkPolicy 対応 CNI(Calico / Cilium など)
  • 管理画面の公開方法に応じて どちらか:
    • LoadBalancer 実装(kube-vip / MetalLB / Cilium LB-IPAM など) … 既定
    • Ingress コントローラー … ingress.enabled: true の場合
    • どちらも無い場合は service.type: ClusterIP + kubectl port-forward で利用可
  • Claude の認証情報 … claude setup-token の OAuth トークン(推奨)または ANTHROPIC_API_KEY

Helm リポジトリから

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"

ローカル LB の IP + サブスクリプション認証(API 不要・推奨構成)

claude setup-token   # 手元の PC で長期 OAuth トークンを発行

helm upgrade --install claude-code cafepieters/claude-code \
  -n claude-code --create-namespace \
  -f examples/loadbalancer-oauth.values.yaml \
  --set anthropic.oauthToken="<発行されたトークン>" \
  --set-file git.identities.gitea-ssh.sshPrivateKey=P:/Claude/.ssh/id_claude \
  --set-file git.identities.gitea-ssh.knownHosts=./known_hosts.gitea

examples/loadbalancer-oauth.values.yaml は Ingress 無効・service.type: LoadBalancer + kube-vip の VIP 指定 + loadBalancerSourceRanges によるローカルセグメント限定の構成です。

ローカルチャートから(GitHub 公開リポジトリだけ触る最小構成)

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) 両対応

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 は事前に取得します:

ssh-keyscan 192.168.9.65 > known_hosts.gitea

使い方

  1. 管理画面を開く:

    • LoadBalancer(既定): kubectl -n claude-code get svc claude-code の EXTERNAL-IP を ブラウザで開く(http://<IP>/)
    • Ingress: 設定したドメイン(https://claude-code.example.com/)
    • どちらも無効: kubectl -n claude-code port-forward svc/claude-code 8080:80 → http://localhost:8080/
  2. auth.mode: token の場合、トークンを取得して UI に貼り付け(または ?token= で開く):

    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

→ 管理画面へのアクセス(LoadBalancer / Ingress) を参照。 service.type の既定は LoadBalancer、ingress.enabled の既定は false(両者は併用可)。

セッションイメージ

既定の 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 します。手動ビルドは:

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.263-a 2.1.263 Service を LoadBalancer 対応(kube-vip 等でローカル LB の IP から管理画面へアクセス、loadBalancerSourceRanges で接続元制限、既定を LoadBalancer に変更)。Ingress は従来どおり併用可。API を使わないサブスクリプション認証(claude setup-token → authMode: oauth)の手順を README に追記
2.1.263 2.1.263 自動更新
2.1.259 2.1.259 初版。gateway + manager + 使い捨て session Pod + reaper、GitHub/Gitea 対応、アイドル自動破棄、NetworkPolicy / RBAC 最小化 / restricted PodSecurity