mcpField
D
debug-openshell-cluster

debug-openshell-cluster

github.com/nvidiaクラウド・DevOps20.6k538 回インストール今日更新
リポジトリ

debug-openshell-cluster について

OpenShell ゲートウェイと計算基盤のデプロイを調査する運用者向け診断スキルです。接続性、ドライバー設定、プラットフォーム別の情報を順に確認し、ゲートウェイとランタイムの役割を区別します。

主な機能

  1. 01CLI とゲートウェイの接続確認
  2. 02計算ドライバーと基盤の特定
  3. 03起動依存関係と設定の確認
  4. 04Kubernetes とコンテナランタイムの診断
  5. 05認証、TLS、リソース承認の調査

活用シーン

  1. 01ゲートウェイの接続先と認証状態の確認
  2. 02サンドボックス作成失敗の調査
  3. 03Kubernetes デプロイのトラブル対応

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/nvidia/openshell --skill debug-openshell-cluster

インストール後、Claude Code で/debug-openshell-clusterを入力して読み込まれたか確認します。

同梱ファイルreferences/supervisor-middleware.md

詳細

翻訳後に原文が更新されています。最新の内容は原文をご確認ください。

OpenShell ゲートウェイのデプロイをデバッグする

ゲートウェイと、選択されているコンピュートプラットフォームを診断します。OpenShell が Kubernetes をプロビジョニングしたり、k3s コンテナーを実行したりすると想定しないでください。OpenShell は、Docker、Podman、Kubernetes、実験的な VM ドライバー、またはオペレーター管理のアウトオブツリーコンピュートドライバーを基盤とする、到達可能なゲートウェイエンドポイントを対象とします。

まず openshell を使って、アクティブなエンドポイントを特定します。次に、ゲートウェイのコンピュートドライバーに合ったプラットフォームツール(docker、podman、kubectl/helm、または VM ドライバーのログ)を使います。

概要

デプロイの基本的な流れは次のとおりです。

  1. オペレーターが、システムパッケージ、systemd、または Helm を使ってゲートウェイを起動またはデプロイします。CLI はゲートウェイサービスを起動、停止、破棄しません。
  2. オペレーターがコンピュートドライバーを設定します。
  3. オペレーターが、デプロイモードで必要となる CLI とスーパーバイザーの認証情報を提供します。これには、エッジ認証または OIDC ユーザー認証、任意の CLI mTLS、ゲートウェイが発行するサンドボックス JWT が含まれます。
  4. CLI が openshell gateway add で、到達可能なゲートウェイエンドポイントを登録します。
  5. ゲートウェイが、選択されたコンピュートドライバーを通じてサンドボックスを作成します。

openshell-gateway コンポジションクレートは、コンパイルされた Docker、Podman、Kubernetes、VM の各登録を起動時に明示的にインストールします。openshell-server はコンピュートドライバーのクレートにリンクしません。カスタムゲートウェイバイナリでは、これらの登録の一部だけを含めることができます。ドライバーが設定されていない場合、ゲートウェイはインストール済みの登録のみを優先順位順(Kubernetes、Podman、Docker)にプローブします。VM にはプローブがなく、明示的に有効化する必要があります。自動検出で適切なドライバーが利用できないと報告された場合は、バイナリに登録されているドライバーを確認してください。設定で選択したドライバーがコンパイル時に含まれていない場合、ゲートウェイはその名前を外部ドライバーとして扱い、エンドポイントが設定されていないと socket_path がないことを報告します。

Windows では、カスタムバイナリに MXC を個別に含めることができます。Docker、Podman、Kubernetes、VM の登録は、含めても拒否スタブとして機能し、Windows 上でこれらのランタイムを有効にはしません。

選択的ビルドのオプションと外部ドライバーの設定については、コンピュートドライバーのリファレンスを参照してください。

ローカルでの評価に限り、TLS を無効にして、http://127.0.0.1:<port> 経由でゲートウェイに接続できます。

前提条件

  • エンドポイントの確認に使える openshell CLI が必要です。
  • アクティブなゲートウェイ名とエンドポイントを把握しているか、ローカルのゲートウェイメタデータを確認できる必要があります。
  • コンピュートプラットフォームを把握している必要があります。Docker、Podman、Kubernetes、VM、またはアウトオブツリードライバーのいずれかです。
  • Kubernetes の場合、kubectl が OpenShell をホストするクラスターを対象にしており、Helm バージョン 3 以降が利用可能である必要があります。
  • Docker または Podman の場合、ランタイムソケットがゲートウェイホストから到達可能である必要があります。

インストールされている CLI バージョンの仕様は、openshell --help と、ネストされた --help の出力を正としてください。デプロイと設定の動作については、公開されているインストールガイド、コンピュートドライバーのリファレンス、ゲートウェイ設定のリファレンス、Kubernetes セットアップガイドを正としてください。

ワークフロー

診断を順番に実行し、根本原因が明らかになった時点で終了します。

ステップ 1:CLI からの到達性を確認する
openshell gateway list --output json
openshell gateway info
openshell status

保存済みのゲートウェイ選択とメタデータを介さず、一時的にエンドポイントを確認するには、次を実行します。

openshell --gateway-endpoint <url> status

よくある確認事項:

  • No active gateway:openshell gateway add <endpoint> でゲートウェイを登録します。
  • 接続拒否:ゲートウェイプロセスが実行されていない、サービスの公開設定が誤っている、またはポートフォワード/プロキシが有効になっていません。
  • TLS/証明書エラー:エンドポイントのスキームまたは信頼チェーンが誤っている、CLI の mTLS バンドルがゲートウェイ CA と一致しない、スーパーバイザーにゲートウェイ CA がない、または TLS の終端方式がゲートウェイリスナーと一致していません。ワークロードとスーパーバイザーに、ユーザーの TLS クライアント証明書や秘密鍵を含めてはいけません。
  • 新規の Snap インストールでは openshell.user-gateway を使用します。アップグレード済みのインストールでは、システム所有の状態が openshell.system-gateway を通じて保持されます。既存の HTTPS 登録は、サービス名の変更後も引き続き機能します。新しいユーザーの登録、古い HTTP 登録の置き換え、または disable メンテナンス状態を介した安全なモード変更を行うには、公開されている Snap のインストール手順に従ってください。gateway-mode=disable の場合、ローカルの Snap ゲートウェイは実行されません。
  • エッジゲートウェイまたは OIDC ゲートウェイから Unauthenticated が返される場合:保存済みの認証情報を openshell gateway login [name] で更新してから再試行します。ローカルの認証情報を意図的に消去する場合に限り、gateway logout を使用します。
  • オペレーターの認証情報を取得するには、ゲートウェイへの直接の mTLS、[openshell.gateway.mtls_auth] operator_enabled = true、および厳密に OU=operator と一致する検証済み証明書が必要です。OIDC 管理者ロールや転送された証明書ヘッダーではアクセスできません。オペレーター証明書と Authorization ヘッダーを併用しないでください。このロールを有効にするとゲートウェイ全体の管理権限が付与されます。アクセス拒否を解消するために、一般ユーザーにオペレーター証明書を発行してはいけません。公開されているゲートウェイ認証とプロバイダーのリファレンスを参照してください。
  • 秘密証明書または自己署名証明書を使用する直接の開発用エンドポイントは、--gateway-endpoint <url> --gateway-insecure を指定して分離できます。共有ゲートウェイでは、検証を無効にした設定を保存したり推奨したりしないでください。
ステップ 2:コンピューティングプラットフォームを特定する

ゲートウェイのメタデータ、デプロイ値、またはユーザーのセットアップメモを使って、ドライバーを特定します。

プラットフォーム主な確認項目
Dockerゲートウェイプロセスのログ、Docker デーモンの状態、サンドボックスコンテナー、イメージのプル。
PodmanPodman ソケット、ルートレスネットワーク、サンドボックスコンテナー、イメージのプル。
KubernetesHelm リリース、ゲートウェイワークロード、サービス、シークレット、サンドボックスポッド、イベント。
OpenShiftKubernetes と同じ項目に加えて、SecurityContextConstraints(SCC)と、外部アクセスの場合は OpenShift の Route。route.openshift.io API グループの有無で OpenShift を検出します(oc api-resources --api-group=route.openshift.io)。
VMVM ドライバーのログ、rootfs の利用可能性、ホストの仮想化サポート。
拡張機能外部ドライバープロセス、Unix ソケットの所有者/モード、設定済みのドライバー名、機能ハンドシェイク、ゲートウェイログ。
ステップ 3:ゲートウェイの起動依存関係を確認する

コンピューティングプラットフォームのデバッグを始める前に、リスナーの準備が完了する前に初期化される依存関係の障害がないか、ゲートウェイログを調べます。

ゲートウェイコンテナーは Distroless Debian ランタイムを使用します。OS ライブラリの 脆弱性が検出された場合は、デプロイ済みイメージのダイジェストとパッケージのバージョンを確認し、 修正済みのベースを使用して再ビルドしたゲートウェイイメージをデプロイしてください。 ゲートウェイのバイナリだけを更新しても、コンテナーイメージが提供するライブラリは更新されません。 リソースの受付に失敗した場合は、呼び出し元ドライバー設定の無効化とリソース承認の欠如を区別してください。Helm は server.drivers.kubernetes.allowDriverConfig をデフォルトで false に、resourceAdmission.enabled を true に設定します。既存の PVC、RuntimeClass、PriorityClass には、管理者が所有する対応するラベルが必要です。名前空間のメンバーシップと読み取り専用アクセスでは承認は得られません。GPU デバイスとオペレーターが選択した image-pull Secret には受付ラベルは不要です。マネージドモードでは、ゲートウェイ名前空間で設定されたソース image-pull Secret と、ワークスペース名前空間内の生成コピー(openshell.ai/component=image-pull)を確認してください。受付の来歴がないレガシーワークロードは再作成が必要です。修復としてコントロールプレーンリソースに自動的にラベルを付けたり、強制を無効化したりしないでください。

アウトオブツリーのコンピュートドライバーの場合は、そのバージョン付き受付ポリシーの確認応答がゲートウェイのポリシーと一致していることも確認してください。スタンドアロンドライバーのポリシーは、管理者が所有する --admission-config-json オプションを通じて設定します。

アウトオブツリーのコンピュートドライバーの場合は、選択したドライバー名とソケットが CLI フラグまたは gateway.toml 全体で一致していること、およびオペレーターが所有するドライバーがゲートウェイの起動前に実行されていることを確認してください:

rg -n '^version|compute_driver|socket_path|guest_tls_' /etc/openshell/gateway.toml
stat /run/openshell/<driver>.sock
journalctl -u <driver-service> --no-pager --lines=200
journalctl -u openshell-gateway --no-pager --lines=200

ゲートウェイ設定には [openshell] version = 2、単一の compute_driver セレクター、および [openshell.drivers.<name>] 配下のドライバー所有の設定が必要です。ゲートウェイはレガシーの compute_drivers および --drivers セレクターを暗黙的に移行せず、拒否します。有効で空でない OPENSHELL_DRIVERS 値が 1 つだけ存在する場合、正規のセレクターが存在しないときに限り、非推奨の環境変数のみのエイリアスとして残ります。ゲートウェイは警告付きでそのドライバーを選択します。空、無効、カンマ区切り、または競合する値は起動に失敗します。エッジプロキシ CLI アクセス用の WebSocket トンネルは、enable_websocket_tunnel = true(Helm では server.enableWebsocketTunnel)でない限り無効です。Homebrew および RPM パッケージの起動は、正確にパッケージが生成した v1 デフォルトのみを移行します。アップグレードされたパッケージが依然としてサポートされていないバージョンを報告する場合は、アクティブなプレフィックスまたは ~/.config/openshell/gateway.toml を確認してください。編集された v1 ファイルは公開されている schema-v2 移行手順に従う必要があり、上書きしてはなりません。スーパーバイザーゲートウェイ CA はドライバー所有の例外です。guest_tls_ca を [openshell.gateway] 配下で設定すると、ゲートウェイはそれを選択されたローカルドライバーにのみ注入します。廃止された guest_tls_cert および guest_tls_key フィールドを削除してください。TLS 対応の Docker、Podman、および VM ドライバーは、その CA もパッケージ管理のローカル CA も利用できない場合、起動に失敗します。Kubernetes は Secret からゲートウェイ CA のみをスーパーバイザー Pod に投影します。スーパーバイザーはサンドボックスベアラートークンでゲートウェイ RPC を認証します。

カスタム名は [openshell.drivers.<name>].socket_path を使用します。起動時の --compute-driver-socket オーバーライドも docker、podman、kubernetes、または vm を使用できます。その場合、エンドポイントが組み込みの構築よりも優先されます。ファーストパーティのスタンドアロンドライバーは、ソケットの親ディレクトリがドライバーの実効 UID によって所有されていることを要求し、そのモードを 0700 に強制し、ソケットをモード 0600 で作成し、同じ UID を持つピアのみを受け入れます。stat で親とソケットを別々に確認してください。異なる UID で実行されているゲートウェイは、ファイルシステムのパーミッションやグループメンバーシップが許可していても接続できません。オペレーターが提供するドライバーは、その実装に適した同等のアクセス制御を提供する必要があります。接続エラー、GetCapabilities の失敗、ピアメタデータの欠落、プロトコルメジャーの不一致、満たされていない必須機能、または予期しないアドバタイズされたドライバー名についてゲートウェイログを確認してください。openshell gateway info は成功した起動ネゴシエーションを報告します。アドバタイズされた名前は診断メタデータです。ネゴシエートされた機能がオプションの動作を制御します。ゲートウェイは、オペレーターが提供するドライバープロセスやソケットを作成または監督しません。 Kubernetes Secrets credential driver では、すべてのワークスペースモードで、各プロバイダーの認証情報は設定済みの namespace に格納されます。別の namespace を示す PermissionDenied エラーは、プロバイダーの認証情報ハンドルが設定済みの namespace の外を指していることを意味します。プロバイダーを再作成してください。[openshell.credential_drivers.kubernetes-secrets]に対する起動時のunknown field` エラーは、テーブルにドライバーが受け付けないキーが設定されていることを意味します。ゲートウェイから認証情報の namespace に接続できることを確認してください:

kubectl -n openshell get configmap openshell-config -o jsonpath='{.data.gateway\.toml}' | grep -A3 '^\[openshell\.credential_drivers\.kubernetes-secrets\]'
kubectl auth can-i get secrets -n <credential-namespace> --as system:serviceaccount:openshell:openshell

Vault 認証情報ドライバーを設定している場合は、プロバイダー解決のデバッグを始める前に、エンドポイントと信頼バンドルを確認してください。ループバック以外のアドレスでは HTTPS を使用する必要があり、ドライバーはリダイレクトを追跡しません。プライベート CA バンドルはプラットフォームのルート証明書を補完しますが、ホスト名の検証は無効になりません。Helm では、server.credentialDrivers.vault.caConfigMapName で ConfigMap を指定すると、その ca.crt キーが /etc/openshell-tls/vault-ca/ca.crt にマウントされます:

kubectl -n openshell get configmap openshell-config -o jsonpath='{.data.gateway\.toml}' | grep -A10 '^\[openshell\.credential_drivers\.vault\]'
kubectl -n openshell get pod -l app.kubernetes.io/name=openshell -o jsonpath='{range .items[0].spec.containers[0].volumeMounts[*]}{.name}{" "}{.mountPath}{"\n"}{end}' | grep vault-ca
kubectl -n openshell get configmap <vault-ca-configmap> -o jsonpath='{.data.ca\.crt}' | openssl x509 -noout -subject -issuer -dates
kubectl -n openshell logs statefulset/openshell -c openshell-gateway --tail=200

HTTP サービスの DNS アドレスは設定検証に失敗します。UnknownIssuer または無効な CA エラーは、ConfigMap が存在しない、ca.crt キーが正しくない、またはバンドルに Vault サーバーの発行元 CA が含まれていないことを意味します。ホスト名の不一致は、HTTPS の address ホストがサーバー証明書の SAN に含まれていないことを意味します。検証は有効なままにし、サービスの DNS 名に対する証明書を発行してください。

ゲートウェイインターセプターを設定している場合は、[[openshell.gateway.interceptors]]、その Unix またはネットワークエンドポイント、およびゲートウェイの起動ログを確認してください:

rg -n 'interceptors|provider_profile_sources|grpc_endpoint|tls_ca_cert_path|audience|allow_insecure_transport|binding_policy|failure_policy|gateway_jwt' /etc/openshell/gateway.toml
stat /run/openshell/interceptors/<name>.sock
journalctl -u <interceptor-service> --no-pager --lines=200
journalctl -u openshell-gateway --no-pager --lines=200

ゲートウェイは起動時に各インターセプターの Describe RPC を呼び出し、そのマニフェストを検証します。ピアメタデータの欠落、プロトコルのメジャーバージョンの不一致、必須機能の未充足、到達不能なエンドポイント、無効な RPC/フェーズのバインディング、厳密な allowlist または exact の不一致、fail_closed に解決される post_commit バインディングを確認してください。ゲートウェイの JWT 署名が有効になっている場合、認証済みのネットワークインターセプターには HTTPS と有効なベアラートークンが必要です。プライベート CA のパス、エンドポイントのホスト名、想定されるオーディエンス、発行者、kid、およびトークン拒否に関するインターセプターのログを確認してください。allow_insecure_transport = true は、認証なしの平文通信を明示的に維持します。provider_profile_sources がインターセプターを指定している場合、そのインターセプターはプロバイダープロファイル機能を通知し、有効で重複のないカタログを返す必要があります。インターセプターのみを選択したソースは、それ単独で権威あるソースとなります。合成を意図する場合は、user ソースを明示的に含めてください。builtin ソースタイプは削除されました。これを指定したままの設定は起動時に拒否されます。

デプロイでスーパーバイザーミドルウェアを使用している場合は、起動、認証、ポリシー検証、および HTTP/WebSocket の障害について、スーパーバイザーミドルウェアのトラブルシューティングリファレンスを参照してください。

ネットワークポリシーの検証に失敗した場合は、まずゲートウェイによる変更拒否とスーパーバイザーによる実行時拒否を区別してください。ゲートウェイが影響を受けるサンドボックスの範囲を把握している場合、直接のポリシー更新、段階的なマージと承認、プロバイダーのアタッチ、およびプロバイダープロファイルのファンアウトは、永続化の前に完全な実効ポリシーに対して検証されます。FAILED_PRECONDITION の曖昧性応答は、無効なリビジョンや部分的なファンアウトが保存されなかったことを意味します。スーパーバイザーの検証は、起動時、競合時、およびこれらの変更経路以外のポリシーソースに対する多層防御として機能します。

実行時の拒否動作は gateway.toml でのみ設定します:

[openshell.gateway]
policy_validation_failure_mode = "fail_closed"

デフォルトの fail_closed モードでは、以前の世代が無効化され、固定されたリレーが閉じられ、有効な世代が読み込まれるまで新しいエグレスが隔離されます。retain_last_valid を指定すると、以前の有効なポリシーが明示的に維持されます。そのようなポリシーがない場合も、引き続きフェイルクローズとなります。このフィールドを変更した後は、ゲートウェイを再起動してください。検証の根拠、設定モードと実効モード、アクティブな世代、および明示的な previous_policy_active の状態について、サンドボックスの OCSF 設定と検出イベントを確認してください。 公開されている supervisor イメージでは、シェルを含まない distroless Debian 13 ベースを使用しています。 SUPERVISOR_BASE_IMAGE を使用してカスタムビルドする場合は、選択したベースイメージの GNU ランタイムライブラリ、CA 証明書、継承されるユーザーと作業ディレクトリを確認してください。 診断にはコンテナーログ、エンジンのインスペクション、設定済みの exec ヘルスプローブを使用します。exec ... sh、パッケージのインストール、コンテナー内のシェルスクリプトは使用できません。ワークロードのシェルは、別個のサンドボックスイメージに属します。 supervisor の起動失敗を再現する際は、ドライバーが選択した UID と、書き込み可能なランタイム/ログのマウントを維持してください。

ConfigurationInvalid の readiness 条件は、イメージ/実効ポリシーまたはプロバイダー設定が起動時の許可判定で拒否されたことを意味します。ワークロードが起動しないまま、supervisor は稼働し続けます。openshell sandbox get を調べ、完全なポリシー置換またはプロバイダーの変更によって、望ましい設定を修正してください。コンテナーが正常であることを、ワークロードの準備が整った証拠と見なさないでください。 300 秒のプロビジョニング修復期間が過ぎると、ゲートウェイは ProvisioningTimedOut を記録し、ワークロードと supervisor のコンピュートを停止します。サンドボックスの JSON と TUI NOTES の provisioning を調べて、クリーンアップが保留中か完了済みかを判別してください。期限切れ後に設定を修正しても、コンピュートは再起動しません。クリーンアップの完了を待ってから、明示的に sandbox start を実行してください。拒否レポートが繰り返し送信されても期限は延長されず、CLI の待機タイムアウトもこの期限には影響しません。 ポリシーの検証と修復を参照してください。 分離された supervisor は、許可判定の前に、認証済みサンドボックス境界を通じてイメージポリシーの検出を要求します。設定を修復する間、ワークロード境界はワークロードを起動せずに稼働し続けることができます。境界を利用できない場合、コントロール要求の期限内に検出が失敗します。恒久的なゲートウェイエラーと、一時的な再試行の上限到達は、起動を終了させます。これらのエラーは、接続性、認可、またはライフサイクルの問題として調査してください。

ステップ 4:Docker バックエンドのゲートウェイを確認する

サンドボックスコンテナーのログには、サンドボックスランタイムの警告と、TTY なしで実行した場合のメインプロセスの stdout および stderr が記録されます。supervisor コンテナーのログには、supervisor の診断情報と OCSF の簡略形式が記録されます。 ocsf_json_enabled=true の場合は、ログコレクター向けのコンパクトな OCSF-JSON レコードも含まれます。これらは docker logs <supervisor-container> で確認してください。docker cp では稼働中の /var/log tmpfs を参照できず、ワークロードの exec では別のファイルシステムにアクセスします。マーカー形式と配信上の制限については、公開されているOCSF JSON エクスポートガイドを参照してください。

docker info
docker ps --filter name=openshell
docker logs <container> --tail=200
docker run --rm --entrypoint /openshell-sandbox "${OPENSHELL_SANDBOX_RUNTIME_IMAGE:-ghcr.io/nvidia/openshell/sandbox:latest}" --version
openshell status

Docker で GPU の問題が発生した場合は、CDI のサポートと NVIDIA CDI の検出をそれぞれ確認してください。

docker info --format '{{json .CDISpecDirs}}'
docker info --format '{{json .DiscoveredDevices}}'
for dir in /etc/cdi /var/run/cdi; do
  if [ -d "$dir" ]; then
    find "$dir" -maxdepth 1 -type f \( -name '*.yaml' -o -name '*.json' \) -print
  else
    echo "$dir missing"
  fi
done
systemctl is-enabled nvidia-cdi-refresh.service nvidia-cdi-refresh.path || true
systemctl is-active nvidia-cdi-refresh.service nvidia-cdi-refresh.path || true
systemctl status nvidia-cdi-refresh.service nvidia-cdi-refresh.path --no-pager --lines=50
journalctl -u nvidia-cdi-refresh.service --no-pager --lines=100

NVIDIA Container Toolkit の CDI 更新ユニットが有効になっていない場合、または NVIDIA CDI 仕様が生成されていない場合は、それらを有効にして更新を実行してください。

sudo systemctl enable --now nvidia-cdi-refresh.path
sudo systemctl enable --now nvidia-cdi-refresh.service
sudo systemctl restart nvidia-cdi-refresh.service
docker info --format '{{json .DiscoveredDevices}}'

よくある確認結果:

  • Docker デーモンが利用できません:Docker Desktop または Docker Engine を起動してください。
  • ゲートウェイプロセスが停止しました:終了ステータスとログを確認してください。
  • サンドボックスイメージが見つからないか、プルが拒否されました:イメージ参照とレジストリの認証情報を確認してください。
  • ID 解決エラーにより、準備完了前にサンドボックスが失敗します:イメージの OCI USER と、対応する /etc/passwd および /etc/group のエントリーを確認するか、ポリシーでプロセスの ID フィールドを両方とも明示的に設定してください。数値のワークロード ID 1 から 4294967294 は受け付けられます。root、無効な ID を示すセンチネル値、ID の欠落は拒否されます。
  • OCI ワークスペース検証エラーにより、準備完了前にサンドボックスが失敗します:ゲートウェイが報告した不変のイメージ ID を使って、イメージの WorkingDir を確認してください。空、/、明示的な /sandbox は、管理対象の /sandbox 互換ワークスペースを使用します。それ以外の作業ディレクトリは、シンボリックリンクを含まない絶対パスの正規化済みディレクトリである必要があります。最終的なポリシー UID、プライマリ GID、補助グループは、POSIX ACL や LSM による判定を含め、カーネルの実効的なディレクトリ通過・書き込みチェックを通過する必要があります。OpenShell は、デフォルト以外のイメージ作業ディレクトリを作成、chown、chmod しません。
  • Docker と Podman は、イメージの VOLUME またはドライバーマウントが作業ディレクトリやその親ディレクトリを覆う場合も拒否します。ランタイムが検証前に不変のパスをマスクするためです。VOLUME をワークスペースの下に移動するか、宣言を削除してください。
  • カスタム Docker および Podman ワークスペースへの変更は、管理対象の名前付きボリュームではなく、ワークロードコンテナーの書き込み可能レイヤーに保存されます。同じコンテナーを停止・起動した場合は保持されますが、コンテナーを削除または置き換えると保持されません。サンドボックスを削除する前に、必要なファイルをエクスポートしてください。
  • 特殊なファイルシステムまたは OpenShell 制御パスとの衝突として拒否された作業ディレクトリは、権限を変更しても有効になりません。エラーに記載されたカーネル管理のマウントと、具体的なスーパーバイザー、TLS、トークン、ランタイム、ソケットのパスから、イメージの作業ディレクトリを移動してください。
  • supervisor イメージをエクスポートした後、ローカルの Docker ゲートウェイ設定で openshell-sandbox をコピーできません。サンドボックスランタイムとスーパーバイザーは別々のアーティファクトです。ランタイムイメージには /openshell-sandbox が必要です。スーパーバイザーイメージには /openshell-supervisor が含まれます。
  • openshell-sandbox が見つからないため Docker ドライバーを初期化できません:openshell-gateway の隣にあるバイナリを確認するか、設定された sandbox_runtime_image に /openshell-sandbox が含まれていることを確認してください。
  • サンドボックスが登録されません:ゲートウェイログとスーパーバイザーのゲートウェイエンドポイントを確認してください。
  • SSH ホストキーの起動エラー:ゲートウェイ、コンピュートドライバー、スーパーバイザーのリリースが一致していることを確認してください。ゲートウェイは各サンドボックスの SSH キーを設定済みの認証情報ストアに保持し、スーパーバイザーのブートストラップバンドルを通してのみ送信します。認証情報ドライバーが利用可能であることを確認し、サンドボックスの JSON 出力にある公開 host_key_fingerprint を比較してください。ブートストラップバンドルや秘密鍵を決して表示しないでください。フィンガープリントがあるサンドボックスの保存済みキーが見つからない場合はエラーであり、ID の置き換えを許可するものではありません。サンドボックス SSH ID のドキュメントを参照してください。
  • サンドボックスが Ready の状態で、外部ツールサーバーへの呼び出しが失敗します:openshell sandbox get <name> の Tool server connections を確認してください。設定済みの MCP-over-HTTP エンドポイントの場合、JSON 出力の endpoint_statuses には、各アドレスとともに last_result および last_reported_at が表示されます。ホスト、パス、ポートでエンドポイントを選択し、報告された失敗箇所を確認してください。last_reported_at はゲートウェイが受け付けた時刻を記録し、リセット後に保持されていた証拠が受け付けられた場合にも更新されることがあります。結果は期限切れにならず、現在の可用性を証明するものでもありません。HttpResponseReceived にツールエラーが含まれている場合もあります。複数のパスが同じホストとポートを共有している場合、パスが判明する前の失敗はログに残ります。現在のツールの可用性が重要な場合は、実際の操作を確認してください。
  • Docker Desktop で Policy fetch failed after 5 attempts が繰り返し表示される場合、 ホストネットワーキングが無効になっている可能性があります。Docker Desktop でホストネットワーキングを有効にし、Enhanced Container Isolation が無効であることを確認して、 ホストネットワークを使用するコンテナーからゲートウェイのプライマリエンドポイントに到達できることを確認してください。
  • openshell-sandbox --version を表示する前にサンドボックスランタイムイメージが終了します:設定されたイメージに、/openshell-sandbox の静的実行ファイルが含まれていることを確認してください。
  • protocol: tcp エンドポイントを明示的に指定したサンドボックスが、ワークロードの準備完了前に失敗します:選択した隔離バックエンドが TCP 仲介に対応していることを確認し、保護されたチャネルの設定またはリスナーの失敗について、サンドボックスとスーパーバイザーのログを確認してください。必要な外側の送信トラフィック制限と認証済みランタイムチャネルを提供できないドライバーは、エージェントの起動前にポリシーを拒否する必要があります。
  • スーパーバイザーのランタイム検証が失敗します:supervisor_image にサンドボックスランタイムと同じリリースの /openshell-supervisor 実行ファイルが含まれ、その実行ファイルがリンクする動的ローダーと共有ライブラリがイメージ内で利用可能であることを確認してください。docker run --rm --network none --entrypoint /openshell-supervisor <supervisor_image> --version を実行すると、そのリリースが表示されるはずです。存在するバイナリに対して no such file or directory エラーが出る場合、ローダーまたはライブラリが不足しています。スーパーバイザーは専用のイメージから実行されるため、静的である必要はありません。静的でなければならないのは /openshell-sandbox のみです。
  • サンドボックスの強制適用プローブが失敗します:サンドボックスログで、失敗したセキュアコンピューティング(seccomp)のユーザー通知、タスクメモリ、Landlock、ループバック DNS、ソケットインジェクションの具体的なネストされたチェックを確認してください。本番環境の親からワークロードの子へのタスクメモリプローブが /proc/<pid>/mem 経由で成功していても、ランタイムが process_vm_readv および process_vm_writev に対して ENOSYS を返すことがあります。致命的なのは、両方のバックエンドが失敗した場合のみです。ケイパビリティを追加したり、制限のない seccomp プロファイルに切り替えたりしないでください。非特権プローブを許可するデフォルトプロファイルを持つランタイムを使用してください。
  • Docker が NVIDIA CDI デバイスを検出できないと報告するため、GPU サンドボックスが失敗します:.DiscoveredDevices に nvidia.com/gpu=all のようなエントリーが含まれること、/etc/cdi または /var/run/cdi に生成済みの NVIDIA 仕様があること、NVIDIA Container Toolkit の nvidia-cdi-refresh.service と nvidia-cdi-refresh.path が有効で正常であることを確認してください。このサービスはワンショットユニットのため、正常に実行された後に inactive (dead) となるのは問題ない場合があります。systemctl status と journalctl を使って、成功と、更新のスキップまたは失敗とを見分けてください。nvidia-cdi-refresh.service を再起動して不足または古い CDI 仕様を再生成し、その後 Docker を再起動または再読み込みして docker info を再確認してください。
  • Docker または Podman が明示的な cdi_devices セレクターを拒否します:ホストデバイスのパスではなく、CDI 修飾名(<vendor>/<class>=<name>)を使用してください。構文検証では他のベンダーも受け付けられますが、ランタイムがそのデバイスを備えていることや、その GPU ワークロードがサポートされていることを示すものではありません。リクエスト要件については、公開されている GPU 選択のドキュメントを参照してください。
企業向け上流プロキシ

Docker の企業向けプロキシ設定は、[openshell.drivers.docker] 配下のオペレーター管理フィールドです。プロキシテーブル全体を確認し、対応するスーパーバイザーコマンドとログを調べます。

grep -A20 '^\[openshell.drivers.docker\]' <gateway.toml> | grep -E 'https_proxy|no_proxy|proxy_auth_file|proxy_auth_allow_insecure|proxy_connect_by_hostname|proxy_ca_bundle'
docker ps --filter label=openshell.ai/isolation-role=supervisor
docker inspect --format '{{json .Config.Cmd}} {{json .Mounts}}' <supervisor-container>
docker logs <supervisor-container> --tail=200 | grep -Ei 'upstream|connect|proxy|certificate'

proxy_ca_bundle にはゲートウェイホスト上の PEM ファイルを指定し、https_proxy が必要です。プロキシ URL には http:// または https:// を使用できます。プレーンな HTTP プロキシでも、宛先の TLS を再署名する場合があります。バンドルが存在しない、読み取り不可、空、サイズ超過、不正な形式、または証明書を含まない場合は、フェイルクローズします。Docker ドライバーは検証済みバンドルをスーパーバイザー専用の名前付きボリュームにコピーし、固定パス /.openshell/supervisor/upstream-proxy-ca-bundle.pem を渡します。ゲートウェイホスト上のパスは、コンテナーの引数、マウント、ワークロードの環境変数、または template.driver_config.docker に含めないでください。

HTTPS プロキシの証明書エラーは、通常、バンドルにプロキシリスナーの発行者が含まれていないか、その証明書がプロキシのホスト名と一致しないことを示します。TLS インターセプトされた宛先のエラーは、再署名の発行者が不足しているか、スーパーバイザーにバンドルが渡されていないことを示します。検証は有効のままにして、オペレーターのバンドルを修正してください。

ゲートウェイの正常な再起動時には、実行意図のある Docker、Podman、VM のサンドボックスはゲートウェイの終了前に停止し、ゲートウェイの復帰後に再起動します。ゲートウェイログで Stopped sandbox during gateway shutdown と Started sandbox during gateway startup を確認してください。CLI から明示的に停止されたサンドボックスは停止したままです。Kubernetes のサンドボックスはクラスター管理であり、このローカルなゲートウェイのライフサイクルには従いません。内部ドライバーと外部ドライバーには同じルールが適用されます。ゲートウェイがシャットダウン時と起動時の一括処理を実行するには、GetCapabilities.gateway_manages_lifecycle が true である必要があります。

ゲートウェイは、終了前にスーパーバイザーセッションの所有権クリーンアップも完了させます。シャットダウン時に Gateway supervisor session cleanup incomplete と報告された場合は、関連する永続化エラーを調べてください。停止したスーパーバイザーの所有者レコードは、リースの期限が切れるまで残り、再接続を一時的に妨げる場合があります。コンピュートの停止に成功しただけでは、セッションクリーンアップが完了したことにはなりません。

--restart-policy on-failure または always が設定されたサンドボックスでは、openshell sandbox get <name> でポリシー、終了コード、再起動回数、次回の再起動時刻を確認してください。Starting は、ゲートウェイがバックオフの終了または代替スーパーバイザーを待っていることを示す場合があります。期限を過ぎても Ready に遷移しない場合は、ゲートウェイログで停止または起動のエラーを確認してください。Docker、Podman、Kubernetes、VM のネイティブな再起動ポリシーは無効のままです。代替の起動はゲートウェイが管理します。

ステップ 5:Podman ベースのゲートウェイを確認する
podman info
podman ps --filter name=openshell
podman logs <container> --tail=200
openshell status

よくある調査結果:

  • Podman ソケットを利用できない場合:ユーザーソケットを起動するか、公開してください。
  • Rootless ネットワークを利用できない場合:Podman のネットワーク設定を確認してください。
  • サンドボックスのイメージが見つからない、またはプルが拒否された場合:イメージ参照とレジストリの認証情報を確認してください。
  • ID 解決エラーにより準備完了前にサンドボックスが失敗する場合:イメージの OCI USER と、対応する /etc/passwd および /etc/group のエントリーを確認するか、ポリシーで両方のプロセス ID フィールドを明示的に設定してください。数値のワークロード ID 1 から 4294967294 は受け入れられますが、root、無効な ID を示すセンチネル、ID の欠落は拒否されます。
  • スーパーバイザーが接続できない場合:そのゲートウェイエンドポイントとゲートウェイログを確認してください。
  • サンドボックス用の両方の Podman コンテナを確認してください。sandbox 分離ロールのネットワークモードは none である必要があります。supervisor ロールがゲートウェイセッションと外向き通信を管理します。どちらも root 以外のユーザーで実行され、すべてのケイパビリティが削除されています。認証に失敗する場合は、プライベートチャネルのボリュームと共有ユーザー名前空間のマッピングを確認してください。
  • 準備完了前にサンドボックスが失敗する場合は、非特権の強制適用プローブと、対応するスーパーバイザーのプライベートヘルスチェックを確認してください。ケイパビリティを追加したり、ワークロードネットワークを接続したり、ランタイムの seccomp プロファイルを無効にしたりしないでください。修復が必要なサンドボックスの nftables やネストされたネットワーク設定はありません。
  • Linux では、ホストネットワークを使用する Podman スーパーバイザーがゲートウェイのプライマリループバックエンドポイントに到達できることを確認してください。macOS では、Podman Machine のホストループバック転送を確認するか、明示的な grpc_endpoint を設定してください。
  • ワークロード内で host.openshell.internal を解決できない場合は、その /etc/resolv.conf に nameserver 127.0.0.53 が含まれていることを確認してください。Podman ドライバーはサンドボックスごとのシークレットからこのファイルをマウントし、エイリアスの宛先をスーパーバイザーに渡します。プラットフォームのデフォルト(ネイティブ Linux では 127.0.0.1、macOS Podman Machine では 192.168.127.254)でゲートウェイホストに到達できない場合に限り、host_gateway_ip を確認してください。

userns が設定されている場合(例:userns = "auto" または userns = "keep-id"):

  • サンドボックスランタイムの提供では、オーバーレイマウントが idmapped マウントをサポートしないため、イメージボリュームの代わりにバインドマウントのフォールバックを使用します。スーパーバイザーのバイナリはサンドボックスランタイムイメージから抽出され、$XDG_DATA_HOME/openshell/podman-supervisor/(通常は ~/.local/share/openshell/podman-supervisor/)にキャッシュされます。
  • キャッシュが古い場合:サンドボックスランタイムイメージが更新されてもキャッシュ内のバイナリが更新されないと、ELF 検証エラーまたはバージョン不一致によりサンドボックスの作成が失敗することがあります。キャッシュディレクトリを削除して再試行してください。
  • auto モードでは、現在のユーザーの subuid/subgid 範囲が /etc/subuid および /etc/subgid に必要です。これらがない場合、コンテナの作成時に Podman はユーザー名前空間のマッピングエラーを返します。
  • private モードでは、TOML 設定に uidmap と gidmap の配列を明示的に指定する必要があります。両方がない場合、ゲートウェイは起動時に設定を拒否します。Rootless Podman では中間 ID を使用します(例:uidmap = ["0:0:1", "1:1:65535"])。rootful Podman ではホストの絶対 ID を使用します(例:uidmap = ["0:1000:1", "1:100000:65536"])。
  • nomap(ハイフンなし)は入力として受け入れられますが、Podman の API 向けに no-map に正規化されます。
  • Podman が SIGKILL に頼るまで、ワークロードは stopping の状態のままになります。スーパーバイザーのログで failed to signal entrypoint process group を確認してください。サンドボックスユーザーで実行されるワークロードに対し、root プロセスが SIGTERM を転送できるよう、スーパーバイザーは CAP_KILL を保持する必要があります。
ステップ 6:Kubernetes Helm ゲートウェイを確認する
helm -n openshell status openshell
helm -n openshell get values openshell
kubectl -n openshell get deployment,statefulset,pod,svc,pvc
GATEWAY_DEPLOYMENT="$(kubectl -n openshell get deployment openshell >/dev/null 2>&1 && echo deployment/openshell || echo statefulset/openshell)"
kubectl -n openshell logs "${GATEWAY_DEPLOYMENT}" -c openshell-gateway --tail=200
kubectl -n openshell rollout status "${GATEWAY_DEPLOYMENT}"

リリースに存在するゲートウェイリソース種別に応じたログおよびロールアウトのコマンドを使用してください。インストールの失敗、予期しない値、名前空間の欠落、誤ったイメージタグ、登録済みエンドポイントと一致しない TLS 設定、スケジューリングの失敗がないか確認してください。 Helm の値の移行を確認する際は、レンダリングされた gateway.toml と、想定される gatewayConfig テーブルを比較してください。明示的に設定されたリソース許可設定と Kubernetes Secrets の認証情報名前空間は、非推奨のエイリアスより優先されます。認証情報ドライバーの名前空間が、その Role および RoleBinding と一致していることを確認してください。ワークロードの image_pull_policy が未設定の場合は、Kubernetes のデフォルトが使用されます。グローバルな Helm のプルポリシーは、ランタイムとスーパーバイザーのイメージに適用されます。

チャートは、gateway.toml ConfigMap キーを読み取り専用の subPath ファイルとして /etc/openshell/gateway.toml に直接マウントします。これにより、ゲートウェイがシンボリックリンクを含む設定を拒否するため、ConfigMap ディレクトリのマウントで公開されるアトミックライターのシンボリックリンクを回避できます。チェックサムの Pod テンプレートアノテーションにより、ConfigMap が変更されるとワークロードがロールアウトされます。設定の事前チェックでシンボリックリンクまたは通常ファイル以外のパスが報告された場合は、レンダリングされたマウントを調べ、ワークロードが現在のチャートリビジョンにロールアウトされたことを確認してください。

kubectl -n openshell get deployment,statefulset -o yaml | rg -n 'gateway-config|mountPath|subPath|checksum/gateway-config'
kubectl -n openshell rollout status <deployment-or-statefulset>/openshell
kubectl -n openshell logs <gateway-pod> -c openshell-gateway --tail=200

server.telemetryEnabled はゲートウェイ Pod に OPENSHELL_TELEMETRY_ENABLED をレンダリングし、ゲートウェイは有効な値をサンドボックスのスーパーバイザーに伝播します。

外部認証情報ドライバーが有効でない場合、Helm チャートはゲートウェイのデフォルトの暗号化データベース認証情報ストレージを使用します。チャートは共有 KEK 用の保持対象 Kubernetes Secret を作成してゲートウェイ Pod に注入し、暗号化された認証情報エンベロープを OpenShell データベースに保存します。workload.kind=deployment の場合、またはゲートウェイが複数レプリカの場合は、server.externalDbSecret が共有データベースを参照していることを確認してください。複数の認証情報ドライバーに言及するレンダリング/インストールエラーは、gatewayConfig.openshell.gateway.credential_drivers リストで複数の外部認証情報バックエンドが選択されたことを意味します。

HA または PostgreSQL を使用したインストールでは、server.externalDbSecret が参照する外部データベース Secret と、クラスター内にデプロイされている場合は PostgreSQL ワークロードも確認してください。

kubectl -n <namespace> get secret <external-db-secret> -o yaml
kubectl -n <namespace> get deployment,service,pod -l app.kubernetes.io/name=<postgres-workload>
kubectl -n <namespace> logs deployment/<postgres-workload> --tail=200

複数レプリカのゲートウェイは、PostgreSQL のアドバイザリロックを使用して、オブジェクトをまたぐサンドボックスおよびプロバイダーの変更を直列化します。通常の読み取りとヘルスチェックは応答しているのに、これらの RPC が停止する場合は、実行時間の長いデータベースセッションとアドバイザリロックの待機セッションを調べてください。データベース URI や Secret の内容をログに出力しないでください。

SELECT pid, granted, waitstart
FROM pg_locks
WHERE locktype = 'advisory';

複数レプリカのゲートウェイをインストールした場合、スーパーバイザーおよびクライアントのセッショントラフィックは、所有者ではないゲートウェイレプリカが処理し、内部 PeerRelay RPC を介して現在のスーパーバイザー所有者に中継されることがあります。ヘッドレスのピア Service、投影されたピア ServiceAccount トークンボリューム、および TokenReview RBAC を確認してください。

kubectl -n openshell get svc openshell-peer -o wide
kubectl -n openshell get endpoints openshell-peer
kubectl -n openshell get pod -l app.kubernetes.io/instance=openshell \
  -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{.spec.volumes[?(@.name=="gateway-peer-token")]}{"\n"}{.spec.volumes[?(@.name=="peer-client-tls")]}{"\n"}{.spec.containers[0].env[?(@.name=="OPENSHELL_PEER_SERVICE_ACCOUNT_TOKEN_FILE")]}{"\n"}{.spec.containers[0].env[?(@.name=="OPENSHELL_PEER_ENDPOINT")]}{"\n"}{.spec.containers[0].env[?(@.name=="OPENSHELL_PEER_TLS_SERVER_NAME")]}{"\n"}{end}'
kubectl auth can-i create tokenreviews.authentication.k8s.io \
  --as=system:serviceaccount:openshell:openshell
kubectl auth can-i get pods -n openshell \
  --as=system:serviceaccount:openshell:openshell
kubectl -n openshell logs "${GATEWAY_DEPLOYMENT}" --tail=200 | grep -E 'gateway peer|PeerRelay|supervisor owner|owner relay'

ゲートウェイの起動ログには、gateway peer ServiceAccount TokenReview authentication enabled が含まれるのが想定されます。ピアリレーの呼び出しが Unauthenticated で失敗する場合は、gateway-peer-token 投影ボリュームのオーディエンスが openshell-gateway-peer であり、受信側ゲートウェイが TokenReview を作成できることを確認してください。PermissionDenied で失敗する場合は、ゲートウェイの ServiceAccount 名、リリースの名前空間、Pod UID、Helm セレクターラベルが、稼働中のゲートウェイ Pod と一致していることを確認してください。Deployment を使用するゲートウェイ Pod は、Pod IP から OPENSHELL_PEER_ENDPOINT も公開する必要があります。OPENSHELL_PEER_SERVICE_ACCOUNT_TOKEN_FILE という名前は、OPENSHELL_SANDBOX_TOKEN_FILE および OPENSHELL_K8S_SA_TOKEN_FILE で使用されている既存のトークンファイル命名規則に従います。

TLS を有効にしたゲートウェイでは、ピアクライアントは安定したゲートウェイ Service の DNS 名を検証し、チャートの CA とクライアント ID を OPENSHELL_PEER_TLS_CA_FILE、OPENSHELL_PEER_TLS_CERT_FILE、および OPENSHELL_PEER_TLS_KEY_FILE から読み込みます。TLS ネゴシエーション中にピアの呼び出しが失敗する場合は、peer-client-tls ボリュームが存在し、これらのファイルを読み取れること、およびサーバー証明書に OPENSHELL_PEER_TLS_SERVER_NAME の名前が含まれていることを確認してください。

複数レプリカのゲートウェイでレプリカごとの容量を確認するには、各ゲートウェイ Pod のメトリクスとオートスケーラーを確認してください。

for pod in $(kubectl -n openshell get pod \
    -l app.kubernetes.io/name=openshell,app.kubernetes.io/instance=openshell \
    -o jsonpath='{range .items[?(@.spec.containers[0].name=="openshell-gateway")]}{.metadata.name}{" "}{end}'); do
  echo "${pod}"
  kubectl get --raw "/api/v1/namespaces/openshell/pods/${pod}:9090/proxy/metrics" \
    | grep -E '^openshell_server_(supervisor_sessions|relay_pending|relay_rejected_total|routed_request_attempts_total)'
done
kubectl -n openshell get hpa
kubectl -n openshell describe hpa openshell

JSONPath フィルターは、最初のコンテナがゲートウェイ (openshell-gateway)であるポッドのみを残します。以前のチャートでゲートウェイポッドと同じラベルが付けられていた、証明書フックの Job ポッドは除外されます。メトリクスポートは service.metricsPort(デフォルトは 9090)です。

API サーバープロキシは、コントロールプレーンから各ポッドに接続します。メトリクスポートへの接続を監視用の名前空間からのみ許可する NetworkPolicy は、コントロールプレーンも許可しない限り、接続をブロックします。その場合は、NetworkPolicy にブロックされず、kubelet 経由でポッドに到達する kubectl port-forward を使って、ポッドを 1 つずつ読み取ります。

kubectl -n openshell port-forward pod/<gateway-pod> 9090:9090 >/dev/null &
pf_pid=$!
sleep 2
curl -s http://localhost:9090/metrics \
  | grep -E '^openshell_server_(supervisor_sessions|relay_pending|relay_rejected_total|routed_request_attempts_total)'
kill "${pf_pid}"

Helm デプロイに必要な Secret を確認します。

kubectl -n openshell get secret \
  openshell-server-tls \
  openshell-server-client-ca \
  openshell-client-tls \
  openshell-jwt-keys

server.tls.clientCaSecretName="" の場合、組み込み PKI または cert-manager を使用していても、チャートは意図的に client_ca_path と tls-client-ca マウントを省略します。これは想定された動作です。tls-client-ca ポッドマウントがないことを不具合として扱わないでください(PKI によって openshell-server-client-ca が存在する場合はあります)。 ユーザー認証には OIDC または信頼済みプロキシ(server.auth.allowUnauthenticatedUsers=true)を使用します。スーパーバイザーのトランスポートでは、引き続き openshell-client-tls を使用します。

cert-manager を使用するインストールでは、certManager.enabled=true により、cert-manager が TLS 生成を担当します。pkiInitJob.enabled が引き続き true であっても、Helm チャートは JWT のみのモードで openshell-jwt-keys を作成するために、openshell-certgen の pre-install/pre-upgrade フックをレンダリングする必要があります。 ゲートウェイポッドが MountVolume.SetUp failed for volume "sandbox-jwt" で保留状態になり、openshell-jwt-keys が存在しない場合は、レンダリングされた templates/certgen.yaml の出力とフック Job のログを確認してください。cert-manager は TLS Secret を作成しますが、サンドボックス JWT 署名用 Secret は作成しません。

ゲートウェイが failed to read sandbox JWT signing key from /etc/openshell-jwt/signing.pem で終了する場合は、openshell-jwt-keys に signing.pem、public.pem、kid が含まれていることと、ゲートウェイのワークロードが sandbox-jwt Secret を /etc/openshell-jwt にマウントしていることを確認してください。ローカルの Helm 値で TLS を無効にしていても、サンドボックス JWT マウントは必要です。

certManager.serverIssuerRef がサーバー証明書を外部の Issuer または ClusterIssuer(たとえば、TLS パススルーを使う OpenShift Route で信頼された公開証明書を使用するための ACME Issuer。openshiftRoute.enabled を参照)に指定している場合、チャートは2 つのサーバー証明書を作成します。1 つは内部用(チャート CA、内部 SAN)、もう 1 つは外部用(設定された Issuer による発行、外部 SAN のみ)です。ゲートウェイは SNI を使用して適切な証明書を提示します。

外部 Secret が Ready にならない場合は、外部の Certificate/CertificateRequest/Challenge リソースを直接確認します。

kubectl -n openshell get certificate,certificaterequest,challenge
kubectl -n openshell describe certificate openshell-server-external
oc -n openshell get route

ACME Issuer は、内部専用の名前(*.svc.cluster.local、localhost、ループバック IP)を含む証明書リクエストを拒否します。また、commonName が SAN にも含まれている必要があります。このため、外部の Certificate がリクエストするのは certManager.serverDnsNames に指定されたホスト名のみです。

serverIssuerRef の設定後、サンドボックスのスーパーバイザーとゲートウェイ間の TLS ハンドシェイクが UnknownCA で失敗する場合、最も可能性が高い原因は server.grpcEndpoint が外部ホスト名に設定されていることです。これにより、スーパーバイザーは外部ホスト名経由で接続し、チャート CA では検証できない ACME 証明書を(SNI 経由で)受け取ります。server.grpcEndpoint を削除するか、内部サービス名に設定して、スーパーバイザーが内部証明書を受け取るようにします。

helm -n openshell get values openshell | grep -E 'grpcEndpoint|clientCaFromServerTlsSecret|clientCaSecretName|serverIssuerRef|caSecretName'
# server.grpcEndpoint should be unset or point to internal service name

UnknownCAは、ゲートウェイのクライアント検証用CAが誤って設定されている場合にも発生することがあります。デフォルトのclientCaFromServerTlsSecret=trueは、すべての構成で正しい設定です。内部サーバー証明書には常にチャートCA(クライアント証明書に署名するものと同じCA)が署名しているため、そのca.crtが適切な信頼アンカーとなります。Supervisor Podには、コピーされたSecretからca.crtのみがマウントされます。tls.crtとtls.keyはユーザークライアント用であり、サンドボックス内から参照できてはなりません。server.tls.clientCaSecretNameを使って別のクライアントCAを意図的にマウントする場合に限り、この設定を上書きしてください。マウントされたクライアントCAが、クライアント証明書に署名したCAと一致することを確認してください。

kubectl -n openshell get statefulset openshell -o jsonpath='{.spec.template.spec.volumes[?(@.name=="tls-client-ca")]}' | jq .
# Should show items filter for ca.crt from openshell-server-tls

gatewayConfig.openshell.drivers.kubernetes.provider_spiffe_workload_api_socket_pathが設定されている場合でも、ゲートウェイでは[openshell.gateway.gateway_jwt]がレンダリングされ、sandbox-jwt Secretがマウントされるはずです。 SPIREは、動的なプロバイダートークンの付与のために、ゲートウェイとサンドボックススーパーバイザーの両方で使用されます。ゲートウェイPodではspiffe-workload-api CSIボリュームをマウントし、OPENSHELL_GATEWAY_SPIFFE_WORKLOAD_API_SOCKETを設定する必要があります。Supervisor Podには、Kubernetesドライバーの設定から対応するWorkload APIソケットを渡す必要があります。ゲートウェイはSPIRE OIDCディスカバリーエンドポイントではなく、このWorkload APIソケット経由で取得したJWTバンドルを使って、スーパーバイザーのJWT-SVIDを検証します。SPIREがインストールされていること、CSIドライバーが利用可能であること、Kubernetesドライバーの設定にprovider_spiffe_workload_api_socket_pathが含まれていることを確認してください。

helm -n openshell get values openshell | grep provider_spiffe_workload_api_socket_path
kubectl get pods -A | grep -E 'spire|spiffe'
kubectl -n openshell get configmap openshell-config -o yaml | grep provider_spiffe_workload_api_socket_path
kubectl -n openshell get pod -l app.kubernetes.io/name=helm-chart -o jsonpath="{.items[*].spec.containers[*].env[?(@.name==\"OPENSHELL_GATEWAY_SPIFFE_WORKLOAD_API_SOCKET\")].value}{\"\n\"}"

プロバイダートークンの付与を使うサンドボックスPodには、openshell.ai/sandbox-idアノテーション、openshell.ai/managed-by=openshellラベル、スーパーバイザーの環境変数OPENSHELL_K8S_SA_TOKEN_FILEとOPENSHELL_PROVIDER_SPIFFE_WORKLOAD_API_SOCKET、さらに投影されたopenshell-sa-tokenボリュームとspiffe-workload-api CSIボリュームの両方が設定されているはずです。

grpcRoute.backendTLSPolicy.enabled=trueの場合、GatewayプロキシはConfigMap内のCAを使ってバックエンドPodのTLS証明書を検証します。ConfigMapが存在し、正しいCAが含まれていること、enableMtlsが無効になっていること、BackendTLSPolicyリソースが存在することを確認してください。

kubectl -n openshell get backendtlspolicy
kubectl -n openshell get configmap openshell-backend-ca -o yaml
helm -n openshell get values openshell | grep -E 'backendTLSPolicy|enableMtls|failOnTimeout|timeoutSeconds|caCertificateConfigMapName'

cert-managerのインストール後にConfigMapが見つからない場合、cert-managerによるサーバー証明書の発行を待つ間に、インストール後のcertgenフックがタイムアウトした可能性があります。certgen Jobのログを確認してください。

kubectl -n openshell get jobs | grep certgen
kubectl -n openshell logs job/openshell-certgen-backend-ca

pkiInitJob.timeoutSecondsを増やし、helm upgradeを実行して再試行してください。GatewayプロキシにTLS error: Secret is not supplied by SDSなどのバックエンドTLSエラーが表示される場合、ConfigMapのCAがサーバー証明書のCAと一致していない可能性があります。両方が同じ発行元のものであることを確認してください。

現在ゲートウェイのデプロイメントで使用されているイメージ参照を確認してください。

GATEWAY_DEPLOYMENT="$(kubectl -n openshell get deployment openshell >/dev/null 2>&1 && echo deployment/openshell || echo statefulset/openshell)"
kubectl -n openshell get "${GATEWAY_DEPLOYMENT}" -o jsonpath="{.spec.template.spec.containers[*].image}{\"\n\"}{.spec.template.spec.containers[*].env[?(@.name==\"OPENSHELL_SUPERVISOR_IMAGE\")].value}{\"\n\"}"
helm -n openshell get values openshell | grep -E 'repository|tag|supervisorImage|workload'

ゲートウェイ、サンドボックス、スーパーバイザーの各イメージには、同じリリースタグを使用してください。古いランタイムイメージを使うと、サンドボックスの動作がゲートウェイのポリシーやプロトコルの変更に追いつかなくなることがあります。

脆弱性の報告では、実行中のイメージダイジェストを記録し、その正確なアーティファクトをスキャンしてください。ゲートウェイには固定されたDistrolessベースイメージが含まれており、スーパーバイザーにはイメージのビルド時に更新されたAlpineパッケージが含まれています。依存関係やベースイメージの修正がデプロイ済みコンテナに反映されるのは、イメージを再ビルド、公開、再デプロイした後です。変更可能なlatestやdevタグだけでなく、そのダイジェストのSBOMと照合して所見を確認してください。 ゲートウェイのベースイメージを更新する場合は、各プラットフォームのSBOMでインストール済みのlibcパッケージのリビジョンを確認してください。バイナリのglibc互換性の下限は、実行時のバージョンではありません。

ローカルで平文評価を行う場合は、チャートに次の設定があることを確認してください。

helm -n openshell get values openshell | grep -E 'disableTls|grpcEndpoint'

期待される形式:

server:
  disableTls: true
  grpcEndpoint: http://openshell.openshell.svc.cluster.local:8080

サービスの公開設定を確認してください。

kubectl -n openshell get svc openshell -o wide
kubectl -n openshell get endpoints openshell

ローカルでポートフォワーディングをテストする場合:

kubectl -n openshell port-forward service/openshell 8080:8080

ポートフォワーディングは実行したままにします。別のターミナルで、必要に応じてローカルエンドポイントを登録し、確認してください。

openshell gateway add http://127.0.0.1:8080 --local --name local-kubernetes
openshell status

ゲートウェイは正常に動作しているものの、サンドボックスの作成に失敗する場合:

kubectl -n openshell get pods
kubectl -n openshell get events --sort-by=.lastTimestamp | tail -n 50
GATEWAY_DEPLOYMENT="$(kubectl -n openshell get deployment openshell >/dev/null 2>&1 && echo deployment/openshell || echo statefulset/openshell)"
kubectl -n openshell logs "${GATEWAY_DEPLOYMENT}" -c openshell-gateway --tail=200

設定済みのサンドボックス名前空間を確認してください。

helm -n openshell get values openshell | grep sandboxNamespace

次に、その名前空間内のサンドボックスリソースを調査してください。 分割リリースでは、ゲートウェイの値を workspaceResources.enabled=false に設定し、対象の名前空間に個別の openshell-workspace リリースが存在する必要があります。

helm -n openshell get values openshell | grep -A2 workspaceResources
helm -n <sandbox-namespace> status openshell-workspace
kubectl -n <sandbox-namespace> get serviceaccount,role,rolebinding,networkpolicy \
  -l app.kubernetes.io/instance=openshell-workspace
kubectl auth can-i create sandboxes.agents.x-k8s.io \
  --namespace <sandbox-namespace> \
  --as system:serviceaccount:openshell:openshell

ゲートウェイがサンドボックスを作成または監視できない場合は、ワークスペースの RoleBinding のサブジェクトが、ゲートウェイの ServiceAccount 名と名前空間に一致することを確認してください。 SSH リレー接続に失敗する場合は、ワークスペースの NetworkPolicy が、ゲートウェイの実際の app.kubernetes.io/name ラベルと app.kubernetes.io/instance ラベルを選択していることを確認してください。

TokenReview のブートストラップまたはサンドボックスの登録に失敗する場合は、設定されたサンドボックスのサービスアカウントを確認してください。Helm はデフォルトで専用のサンドボックス用サービスアカウントを作成し、その値を [openshell.drivers.kubernetes].service_account_name に書き込みます。選択された Kubernetes コンピュートドライバーは、他のサービスアカウントから発行された投影トークンを拒否します。外部ドライバーの場合は、そのログを調べ、supports_sandbox_authentication を通知していることを確認してください。ゲートウェイは不透明な認証情報をドライバーソケット経由で委譲し、Kubernetes の設定を解釈することはありません。サンドボックス認証を通知するドライバーは、サンドボックスの作成時と認証情報の認証時に、同じ空でないランタイム ID を返す必要があります。コンピュートのランタイム ID が一致しないことを示すゲートウェイログは、ランタイムリソースが古いか、再作成されたことを示します。ライブリソースの UID と、ゲートウェイがプロビジョニングしたサンドボックスを比較してください。再起動時には、同じサンドボックスラベルが付いた複数の Sandbox リソースも拒否されます。また、永続化された名前空間と CR UID が変更されていないことも必要です。世代に紐づくセッショントークンが拒否される場合は通常、スーパーバイザーが置き換えられたランタイムの認証情報を提示しています。ブートストラップを再試行する前に、永続化された世代を確認してください。

Kubernetes ドライバーは、1 つのドライバーインスタンス内で、サンドボックスごとのライフサイクル変更とランタイムの調整を直列化します。処理中のサンドボックスは、次回の調整パスで再確認されます。再起動後もスーパーバイザーが失われる場合は、Sandbox と Pod の UID を比較し、どのゲートウェイまたは外部ドライバープロセスがクリーンアップを実行したかを特定してください。ローカルの変更ゲートは、別々のプロセス間では連携しません。

helm -n openshell get values openshell | grep -A3 sandboxServiceAccount
kubectl -n <sandbox-namespace> get serviceaccount openshell-sandbox
kubectl -n openshell get configmap openshell-config -o jsonpath='{.data.gateway\.toml}'
kubectl -n <sandbox-namespace> get sandbox <sandbox-name> -o jsonpath='{.spec.template.spec.serviceAccountName}{"\n"}'

Kubernetes ドライバーは、サンドボックスのワークロード Pod と、別個に直接管理されるスーパーバイザー Pod を作成します。クラスターの CNI は、すべてのサンドボックス名前空間で Kubernetes NetworkPolicy のイングレスおよびエグレスを強制する必要があります。Kubernetes API は、その強制を証明できません。テナントが Pod を作成したり、OpenShell のロールラベルを複製したり、ブートストラップ Secret を読み取ったりできない、信頼できる名前空間でのみサンドボックスを実行してください。

ワークロード Pod は /openshell-sandbox を実行します。ゲートウェイの認証情報は持たず、直接エグレスもできません。停止状態の Sandbox リソースを作成する前に、名前空間全体に適用されるワークロード NetworkPolicy が 1 つ作成されます。このポリシーはワークロードのすべてのエグレスを拒否し、スーパーバイザー Pod がサンドボックスの TLS リスナーに接続することを許可します。続いてドライバーは、サンドボックスごとの Service、分割された不変のブートストラップ Secret、およびゲート付きのスーパーバイザー Pod を作成してから、いずれかの Pod を稼働させます。スーパーバイザー Pod は /openshell-supervisor を実行します。両方の Pod は、解決された同じ非 root ID を使用し、ケイパビリティを要求せず、ALL をドロップし、特権昇格を無効にして、RuntimeDefault の seccomp を使用します。スーパーバイザーは、サーバー証明書の検証とブートストラップトークンによるクライアント認証を使用した、サンドボックスごとの TLS 経由でサンドボックスに接続します。また、ゲートウェイポリシー、プロバイダー認証情報、DNS、および仲介された上流接続を管理します。

Kubernetes サンドボックスが Starting のままになる場合、またはレディネスを失う場合は、ドライバーが管理するすべてのリソースを調査してください。

kubectl -n <sandbox-namespace> get sandbox,pod,service,secret -l openshell.ai/sandbox-id=<sandbox-id>
kubectl -n <sandbox-namespace> get networkpolicy openshell-sandbox-workloads -o yaml
kubectl -n <sandbox-namespace> describe pod -l openshell.ai/sandbox-id=<sandbox-id>,openshell.ai/boundary-role=supervisor
kubectl -n <sandbox-namespace> logs pod/<supervisor-pod> --tail=200
kubectl -n <sandbox-namespace> get pod -l openshell.ai/sandbox-id=<sandbox-id>,openshell.ai/boundary-role=workload -o yaml
kubectl -n <sandbox-namespace> get networkpolicy -l openshell.ai/sandbox-id=<sandbox-id> -o yaml

作成と復旧はフェイルクローズで動作します。Secret がない場合、両方の Pod は何もせずに待機します。ワークロードフェンスがない、または監視されていない場合、ドライバーは Sandbox を解放しません。また、レディネスには Agent Sandbox のレディネスと Available 状態の supervisor Pod の両方が必要です。exec によるレディネスチェックは、supervisor が接続し、強制適用を確認し、ワークロードを開始または再開して、ゲートウェイのアクセスプレーンを登録した後にのみ成功します。ブートストラップエラーの確認には、両方の Pod ログを使用してください。強制適用の設定中に EPERM が発生した場合、ランタイムが必要な非特権の seccomp、タスクメモリ、または Landlock 操作をブロックしています。回避策として、ワークロード Pod にケイパビリティ、ゲートウェイの送信トラフィック、または認証情報を追加しないでください。

Sandbox がブートストラップの releasing フェーズに留まる場合は、まず supervisor Pod を調べてください。このフェーズでは、ゲートウェイがワークロードを実行状態に保ち、supervisor がその Sandbox のランタイム制御関係を適切に解放できるようにします。Pod の削除タイムスタンプ、終了猶予期間、イベント、ファイナライザーを確認し、ゲートウェイの ServiceAccount が Sandbox の名前空間で Pod を削除できることを確認してください。

kubectl -n <sandbox-namespace> get pod \
  -l openshell.ai/sandbox-id=<sandbox-id>,openshell.ai/boundary-role=supervisor \
  -o yaml
kubectl auth can-i delete pods \
  --namespace <sandbox-namespace> \
  --as system:serviceaccount:openshell:openshell

ワークロード Pod を手動で一時停止または削除しないでください。ドライバーはランタイム制御が解放された後にのみ suspending に進み、その後ワークロードを一時停止します。

Sandbox がブートストラップの suspending フェーズに留まる場合は、ゲートウェイの ServiceAccount が Sandbox の名前空間で Secret を作成および削除できることを確認してください。オペレーターモードでは、これらの権限は名前空間にインストールされた openshell-workspace チャートからのみ付与されます。復旧時には、一時停止アノテーションを消去する前に、記録された世代のブートストラップ Secret を名前で削除します。

for verb in create delete; do
  kubectl auth can-i "$verb" secrets \
    --namespace <sandbox-namespace> \
    --as system:serviceaccount:openshell:openshell
done

no の結果が 1 つでもあると、ワークロード Pod の作成前に復旧が行き詰まる可能性があります。ワークロード Pod がないことを Pod の障害として扱うのではなく、OpenShell チャートをアップグレードしてください。

企業のアップストリームプロキシ

デプロイでサンドボックスの外向き通信を企業の HTTP フォワードプロキシ経由にする場合、運用者が管理する設定は、Helm の upstreamProxy の値から [openshell.drivers.kubernetes] に反映されます。プロキシ設定がない場合は直接接続による外向き通信が維持されます。値が存在するものの無効な場合は、直接接続に暗黙に切り替わるのではなく、ゲートウェイの起動時に失敗します(validate_upstream_proxy_config)。まず、設定がどのように反映されているか確認してください。

kubectl -n openshell get configmap openshell-config -o jsonpath='{.data.gateway\.toml}' | grep -E 'https_proxy|no_proxy|proxy_auth_secret_(name|key)|proxy_auth_allow_insecure|proxy_connect_by_hostname|proxy_ca_bundle'
helm -n openshell get values openshell | grep -A12 upstreamProxy

http://host:port と https://host:port の両方のフォワードプロキシに対応しています。プレーン HTTP による外向き通信は対象外で、常に直接接続します。proxy_auth_secret_name で指定された認証情報の Secret は、サンドボックスの名前空間に proxy_auth_secret_key で指定されたキーとともに存在する必要があります。また、Kubernetes では 253 バイトを超える名前のキーや、./.. という名前のキーは作成できません。

プライベート CA を使用する https:// プロキシ、または TLS を傍受するプロキシでは、upstreamProxy.caBundle.configMapName も必要です。この ConfigMap はサンドボックスの名前空間ではなく、ゲートウェイのリリース名前空間に配置します。ゲートウェイはこれを読み取り、バンドルを各サンドボックスのスーパーバイザーのブートストラップ Secret にステージングします。ConfigMap がない場合、oidc-ca や vault-ca と同様に、ゲートウェイの Pod は ContainerCreating の状態になります。

kubectl -n openshell get configmap <proxy-ca-configmap> -o jsonpath='{.data}' >/dev/null && echo "CA ConfigMap present"
kubectl -n openshell describe pod -l app.kubernetes.io/name=openshell | grep -A5 'ContainerCreating\|MountVolume'
kubectl -n <sandbox-namespace> get secret <supervisor-bootstrap-secret> -o jsonpath='{.data.upstream-proxy-ca\.pem}' | head -c 20

反映された TOML で proxy_ca_bundle が設定されているのに最後のコマンドが空の場合、バンドルがサンドボックスに届いていません。ゲートウェイのログで proxy_ca_bundle エラーを確認してください。このエラーは起動時に失敗し、直接接続の外向き通信にフォールバックしません。

プロキシ引数と認証情報のマウント先は、独立したスーパーバイザー Pod のみに設定します。ワークロード Pod にこれらを渡してはいけません。認証情報は openshell-upstream-proxy-auth として読み取り専用で /run/openshell/upstream-proxy-auth に投影し、ファイルパスで渡します。環境変数、アノテーション、コマンド引数に含めてはいけません。

kubectl -n <sandbox-namespace> get secret <proxy-auth-secret> -o jsonpath='{.data}' >/dev/null && echo "secret present"
kubectl -n <sandbox-namespace> get pod <supervisor-pod> -o jsonpath='{.spec.containers[0].command}' | grep -- '--upstream-'
kubectl -n <sandbox-namespace> get pod <supervisor-pod> -o jsonpath='{.spec.containers[0].command}' | grep -- '--upstream-proxy-ca-bundle'
kubectl -n <sandbox-namespace> get pod <supervisor-pod> -o jsonpath='{.spec.containers[0].volumeMounts}' | grep upstream-proxy-auth
kubectl -n <sandbox-namespace> get events --sort-by=.lastTimestamp | grep -Ei 'secret|MountVolume' | tail -n 20

Secret がない場合やキーが誤っている場合、Pod は MountVolume.SetUp failed/secret ... not found イベントが発生して起動できません。Pod が起動しても外向き通信に失敗する場合は、次に企業のプロキシ自体を疑ってください。ポリシー評価後に、ポリシーで許可された TLS CONNECT リクエストがタイムアウトする場合、通常はサンドボックスの名前空間からプロキシ URL に到達できないか、直接接続すべきクラスター内部の宛先が no_proxy に含まれていないことを意味します。ネットワークスーパーバイザーのログで、CONNECT とアップストリームプロキシの判断を確認してください。

kubectl -n <sandbox-namespace> logs pod/<supervisor-pod> --tail=200 | grep -Ei 'upstream|connect|proxy'
ステップ 7:VM ベースのゲートウェイを確認する

ユーザーの環境で利用できる VM ドライバーのログとホスト診断を使用してください。次の点を確認します。

  • VM ドライバーのプロセスが実行中で、ゲートウェイから到達できること。
  • ランタイムの rootfs が存在し、想定されたアーキテクチャと一致すること。
  • e2fsprogs の mke2fs または mkfs.ext4、debugfs、e2fsck がインストールされていること。起動前に、使用するローカル VM 設定、サービスアカウント、環境を指定して openshell-gateway config preflight を実行し、選択されたパスとバージョンを確認してください。リモートエンドポイントでは、ホストのチェックが実行されなかったことが報告されます。sandbox_uid/sandbox_gid を明示的に指定しても、この前提条件はなくなりません。
  • 永続化されたオーバーレイの ID エラーが、所有者マーカー、オーバーレイの上位レイヤー、準備済み rootfs、明示的な設定、または現在のイメージに基づいて解決されていること。永続化された状態で旧 ID が報告されている場合を除き、10001:10001 を割り当てないでください。
  • ホストの仮想化サポートが有効になっていること。
  • サンドボックススーパーバイザーが、認証済みのゲートウェイセッションを確立できること。

次に、以下を実行します。

openshell status
openshell logs <sandbox-name>
企業の上流プロキシ

VM サンドボックスの外向き通信が企業の HTTP フォワードプロキシ経由になる場合、オペレーターが管理する設定は [openshell.drivers.vm] 配下に置き、ゲートウェイはそれらを --upstream-proxy、 --upstream-no-proxy、--upstream-proxy-auth-file、 --upstream-proxy-auth-allow-insecure、 --upstream-proxy-connect-by-hostname、--upstream-proxy-ca-bundle として openshell-driver-vm サブプロセスに渡します。ゲートウェイと ドライバーは起動時に設定を検証するため、存在するが無効な値があると、直接接続にフォールバックせず、キー名を示すエラーで フェイルクローズします。まず、設定と、その結果のドライバー argv を確認してください。

grep -A20 '^\[openshell.drivers.vm\]' <gateway.toml> | grep -E 'https_proxy|no_proxy|proxy_auth_file|proxy_auth_allow_insecure|proxy_connect_by_hostname|proxy_ca_bundle'
ps -o args= -p "$(pgrep -f openshell-driver-vm | head -n1)" | tr ' ' '\n' | grep -A1 -- '--upstream-proxy\|--upstream-no-proxy'

libkrun ゲストと QEMU ゲストには、どちらも NIC がありません。プロキシ設定、認証情報、プライベート CA のデータはホストの openshell-supervisor に保持されます。ゲートウェイホスト上のプロキシには、 http://host.openshell.internal:<port> を使用してください。スーパーバイザーがこの名前をホストのループバックに正規化します。接続や認証情報の失敗については、サンドボックスの状態ディレクトリにある supervisor.log と supervisor.err.log を確認してください。

よくある失敗パターン

症状考えられる原因確認方法
openshell status が失敗するゲートウェイエンドポイントに到達できない、または認証情報が一致しないopenshell gateway info、ゲートウェイログ
ゲートウェイの OCSF JSONL のサイズが増えない、欠落がある、または SIEM に拒否されるファイルエラー、キューの逼迫、シッパーの処理が保持期間に追いつかない、またはスキーマの不一致ゲートウェイの警告と openshell_ocsf_log_* メトリクスを確認します。[openshell.gateway.ocsf_log]、schema_version、ディレクトリの権限、空き容量、レプリカごとのパス、シッパーのローテーションチェックポイントを確認します。公開されているゲートウェイ設定リファレンスを参照してください。
BatchSpanProcessor.ExportError で 127.0.0.1:4317 への接続拒否が繰り返し報告されるローカルゲートウェイの起動時には OTLP が設定されていたものの、その後コレクターへの転送タスクが停止した、または設定が手動で作成されたgateway:docker、gateway:podman、または gateway:vm を再起動してリスナーを再検出します。生成された gateway.toml で [openshell.gateway.otlp] を確認します。
ゲートウェイは起動するが、サンドボックスの作成に失敗するコンピュートドライバーがランタイムに到達できないDocker/Podman/Kubernetes/VM ドライバーのログ
Docker または Podman のサンドボックスが登録されないゲートウェイエンドポイントの誤り、ホストネットワークを利用できない、またはスーパーバイザーの起動失敗ゲートウェイログとスーパーバイザーコンテナのログ
CPU のみの VM の起動時に、読み取り専用の /proc を削除できないというエラーが報告される古いスーパーバイザーは、ホストデバイスから GPU 要件を推測することがありますゲートウェイ、VM ドライバー、同梱スーパーバイザーのバージョンを確認し、互換性のある更新済みアーティファクトを使用します。CPU のみの VM に読み書き可能な /proc は不要です。
Docker の GPU サンドボックスが起動前に失敗するNVIDIA CDI 仕様がない、または Docker がそれを検出していないdocker info --format '{{json .DiscoveredDevices}}'、/etc/cdi、/var/run/cdi、nvidia-cdi-refresh.service
Kubernetes ゲートウェイポッドが Pending のままになるPVC がバインドされていない、テイント、セレクター、またはリソース不足kubectl -n openshell describe pod <pod>
Kubernetes サンドボックスポッドが Pending のままで、ワークスペース PVC がバインドされないクラスターにデフォルトの StorageClass がなく、OpenShell がワークスペース PVC に storageClassName を設定していない(デフォルトの StorageClass があるクラスターでは、設定がなくても正常にバインドされます)kubectl -n openshell describe pvc を実行します。有効な StorageClass を server.workspaceStorageClass(ゲートウェイ設定では workspace_storage_class)に設定します。
Kubernetes ゲートウェイポッドがクラッシュループするシークレットがない、DB URL が不正、TLS 設定が不正kubectl -n openshell logs deployment/openshell -c openshell-gateway または kubectl -n openshell logs statefulset/openshell -c openshell-gateway
helm upgrade が autoscaling.* メッセージで失敗するHPA の値が無効です。resources.requests(または resources.limits)がない、server.externalDbSecret を指定せずに maxReplicas を 1 より大きくしている(または workload.allowMultiReplicaStatefulSet を指定せずに StatefulSet で設定している)、メトリクスのターゲットがない、あるいは最小値と最大値の順序が不正です。「minReplicas and maxReplicas are not set」は、--reuse-values によりチャートのオートスケーリングのデフォルト値を持たないリリースの値が引き継がれたことを意味しますエラーで示された値を修正します。--reuse-values の代わりに --reset-then-reuse-values を指定してアップグレードします。
HPA のターゲットに <unknown> と表示されるCPU/メモリ用の metrics-server がない、またはメトリクスアダプターがカスタムメトリクスを提供していないkubectl -n openshell describe hpa openshell、kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1
ロールアウト後、1 つのレプリカにほとんどのセッションが集まる想定どおりです。セッションは再接続した場所にとどまりますポッドごとの openshell_server_supervisor_sessions を確認します。サンドボックスが再作成されるにつれて値は減少します。
OpenShift ゲートウェイポッドの起動が SCC/runAsUser エラー(例:unable to validate against any security context constraint)で失敗するチャートのデフォルトの podSecurityContext/securityContext が runAsUser/fsGroup を固定しているため、restricted-v2 SCC に拒否されています。代わりに、名前空間に割り当てられた UID/GID 範囲を注入する必要がありますoc -n openshell describe pod <pod> を実行します。podSecurityContext: null を指定してデプロイし、securityContext.runAsUser をクリアします(deploy/helm/openshell/ci/values-openshift-scc.yaml を参照)。
OpenShift サンドボックスポッドの起動が失敗する(unable to validate against any security context constraint)openshell-sandbox サービスアカウントに、必要な特権 SCC が付与されていませんoc adm policy add-scc-to-user privileged -z openshell-sandbox -n openshell を実行します。完了後は remove-scc-from-user で削除します。
OpenShift でセルフホストされた Vault/OpenBao の認証情報ストアポッドがスケジュールされない(no matching resources found で待機がタイムアウトする)ストアの Helm チャートが runAsUser/fsGroup/seccomp を固定しており、restricted-v2 に拒否されるため、StatefulSet コントローラーがポッドを作成しませんストアのチャートを OpenShift モードでデプロイします(OpenBao/Vault チャートでは --set global.openshift=true)。これにより、名前空間の SCC が適合するセキュリティコンテキストを割り当てます。手動で SCC を付与する必要はありません。
Vault 認証情報ドライバーがプロバイダー作成時に HTTP 403/Vault Kubernetes auth denied the configured role を返すVault の auth/kubernetes メソッドまたはゲートウェイのログインロールが設定されていない、あるいはロールがゲートウェイのサービスアカウントと名前空間に紐付けられていないVault で bao auth enable kubernetes と bao write auth/kubernetes/config kubernetes_host=... kubernetes_ca_cert=@... を実行します。ログインロールの bound_service_account_names/bound_service_account_namespaces がゲートウェイの SA と名前空間に一致し、ポリシーで認証情報のパスへのアクセスが許可されていることを確認します。
CLI で TLS エラーが発生するローカルの mTLS バンドルがサーバー証明書/CA と一致しない~/.config/openshell/gateways/<name>/mtls/ を確認します。
Edge または OIDC ゲートウェイが Unauthenticated を返す保存されたログイン情報の有効期限切れ、オーディエンス/スコープの不一致、またはゲートウェイ認証設定の変更openshell gateway info、openshell gateway login <name>、ゲートウェイ認証ログ
OIDC の初期化中にゲートウェイが終了する発行者が HTTPS ではない、ディスカバリーがリダイレクトされた、メタデータのメディアタイプが JSON ではない、またはサイズ制限を超えた、あるいは jwks_uri が信頼されていないオリジンを使用しているHTTPS の発行者を使用します。server.oidc.caConfigMapName でプライベート CA をマウントします。JWKS は発行者のオリジンに置くか、その HTTPS オリジンを server.oidc.jwksAllowedOrigins に明示的に追加します。数値形式のループバック HTTP は開発専用であり、server.oidc.dangerouslyAllowInsecureHttp=true も必要です。
インターセプターの有効化後、ゲートウェイがヘルスチェックの提供前に失敗するインターセプターのエンドポイントに到達できない、またはマニフェスト/バインディングの検証に失敗したゲートウェイとインターセプターのログ、インターセプターのソケット、binding_policy、フェーズ、失敗ポリシー
認証済みインターセプターまたはミドルウェアがゲートウェイ呼び出しを拒否するプライベート CA またはホスト名の不一致、期待されるオーディエンスまたは発行者の不一致、古い/不明な kid、または拡張トークンの形式不正tls_ca_cert_path、登録時の audience、サービス検証設定とログを確認します。well-known メタデータの取得には、すでに信頼されているゲートウェイ TLS エンドポイントのみを使用します。
インターセプターカタログの有効化後にプロバイダープロファイルが表示されなくなるprovider_profile_sources で権威あるインターセプターのみが選択されていた、または無効/重複した ID が返されたソース一覧とインターセプターの Describe/カタログログを確認します。インポートしたプロファイルとの合成を意図している場合は user を含めます。
新しいゲートウェイで provider list-profiles が空になるプロファイルがインポート専用で、まだ何もインポートされていないopenshell provider profile import --from providers --global でインポートします。カタログが空でも正常な準備完了状態であり、失敗ではありません。
プロファイルが見つからないというエラーが出て、サンドボックスの作成またはプロバイダーのアタッチに失敗するプロバイダーのプロファイルがインポートされていない、削除された、または別のスコープにあるプロバイダーが使用するスコープにインポートします。エラーにはプロファイル ID とコマンドが示されます。
スーパーバイザーミドルウェアの登録後にゲートウェイが失敗するサービスを利用できない、マニフェストが無効、バインディングが重複している、予約名を使用している、またはペイロード/タイムアウト制限が無効ミドルウェアサービスとゲートウェイのログ、[[openshell.supervisor.middleware]]、Describe の応答
ポリシー更新が network_middlewares を拒否するミドルウェア名が不明、実装所有の設定が無効、順序が重複している、ホストセレクターの範囲が広すぎる/無効、または tls: skip をフェイルクローズでカバーしているポリシーエラー、ゲートウェイログ、ミドルウェアの ValidateConfig、セレクターと順序のフィールド
ヘルスチェックの提供前に、ゲートウェイまたは拡張機能が相手側を拒否するピアメタデータがない、プロトコルのメジャーバージョンに互換性がない、または required_capabilities を満たしていないゲートウェイと拡張機能の起動ログ、PeerMetadata を比較します。旧形式から現行形式への移行には、ゲートウェイと拡張機能を連携して停止する必要があります。
エンドポイントの曖昧さによりポリシー変更が FAILED_PRECONDITION を返す同じ詳細度の有効なエンドポイントセレクター間で、接続またはリクエスト処理のメタデータが一致しないCLI エラー、ベースポリシーとプロバイダー合成済みポリシー、影響を受けるプロファイルのアタッチ状況を確認します。新しいリビジョンが保存されていないことを確認します。
スーパーバイザーがポリシー隔離状態になるpolicy_validation_failure_mode = "fail_closed" のときに、実行時候補の検証に失敗したサンドボックスの OCSF 設定/検出イベント、検証理由、有効な世代、previous_policy_active
カスタムコンピュートドライバーを利用できないドライバープロセス/ソケットがない、アクセスできない、または選択した名前がエンドポイント/設定キーと一致しないソケットの所有者/モード、ドライバーサービスのログ、ゲートウェイの GetCapabilities ログ
サンドボックスが Stopping または Starting のままになるドライバーの停止/起動に失敗した、保持されていたリソースが見つからない、または新しいスーパーバイザーがまだ接続していないゲートウェイとドライバーのログ、docker inspect、podman inspect、Agent Sandbox のステータス/PVC、または VM の状態マーカーとランチャープロセス
イメージのプルに失敗するゲートウェイまたはサンドボックスのイメージをプルできないランタイムイベントとイメージプル用の認証情報
ゲートウェイ API リソースで the server could not find the requested resource が発生するGateway API の CRD がない状態で、オプションの Gateway API リソースが適用された標準の Gateway API CRD と選択したコントローラーをインストールしてから、オプションのイングレスリソースを適用する前に grpcRoute を有効にします。
カスタム GatewayClass がチャート作成の Gateway をプログラムしない、またはそのプロキシ Service が OpenShell Service と競合する選択したコントローラーが利用できない、またはデフォルトの grpcRoute.gateway.name が OpenShell Service と同じ名前を再利用しているkubectl get gatewayclass,gateway,grpcroute -A を確認します。<fullname>-ingress など、別の Gateway 名を設定します。既存の Gateway の場合は、gateway.create=false と gateway.name、gateway.namespace、任意の gateway.sectionName を設定します。
HTTPS イングレス(grpcRoute.gateway.listener.protocol=HTTPS)で接続がリセットされる、または TLS ハンドシェイクが停止するEnvoy が TLS を終端する一方で、ゲートウェイポッドが TLS を引き続き要求するため、バックエンドへの平文接続が失敗するserver.disableTls=true を設定し、Envoy からポッドへ平文で転送します。リスナーの certificateRefs Secret がリリースの名前空間に存在することと、https://<host> で openshell status が実行できることを確認します。
grpcRoute.replicaRouting.enabled=true の場合も、サンドボックスの SSH、転送、または exec がピアレプリカ経由で中継される<release>-replica-<i> Service にエンドポイントがないため、Envoy が Unavailable を返し、CLI がルーティングなしで再試行するkubectl -n openshell get endpoints <release>-replica-0 <release>-replica-1 を実行します。workload.kind=statefulset と、GRPCRoute のステータスが Accepted/ResolvedRefs であることを確認します。
接続後に HTTPS イングレスが Unauthenticated を返すEnvoy で TLS が終端されるため、ゲートウェイはクライアント証明書を認識しません。ID 用の OIDC 発行者が設定されていませんserver.oidc.issuer を設定し、openshell gateway add https://<host> --oidc-issuer <url> で登録します。または、信頼できるプロキシ/開発用クラスターでは server.auth.allowUnauthenticatedUsers=true を設定します。
certManager.serverIssuerRef を設定しても、外部サーバーの Certificate が Ready にならないACME 発行者が内部限定の SAN、ループバック IP、または SAN に含まれない commonName を拒否したkubectl -n openshell describe certificate openshell-server-external を実行します。certManager.serverDnsNames に、外部から名前解決可能な実在のホスト名のみが指定されていることを確認します。
certManager.serverIssuerRef の設定後、サンドボックスのスーパーバイザーが UnknownCA で TLS ハンドシェイクに失敗するserver.grpcEndpoint に外部ホスト名を設定しているため、スーパーバイザーが ACME 証明書を受信します(SNI 経由)。この証明書はチャートの CA では検証できませんserver.grpcEndpoint を削除するか、内部サービス名に設定します。スーパーバイザーは内部サービス名で接続し、内部証明書を受信する必要があります。
ブラウザーで ERR_BAD_SSL_CLIENT_AUTH_CERT が表示される、または OIDC/直接 HTTPS を想定しているのにゲートウェイログにクライアント証明書の検証が表示されるリスナーのクライアント CA 検証が有効なままになっている(clientCaSecretName が未設定、または ConfigMap に client_ca_path がある)server.tls.clientCaSecretName="" を設定してチャートをアップグレードし、ConfigMap に client_ca_path がないことを確認します。

レポート

結果をユーザーに返す際は、次の情報を含めてください。

  • アクティブなゲートウェイエンドポイントと認証モード。
  • コンピューティングプラットフォームとドライバー。
  • ゲートウェイプロセスまたはワークロードの状態。
  • 最近のゲートウェイログの概要。
  • TLS、OIDC/mTLS、またはサンドボックス JWT の不足または形式不正な情報。
  • サービスの公開状態。
  • サンドボックスワークロードの状態。
  • 失敗した正確なコマンドと、最短の修正方法。

パッケージ構成のプリフライト

証明書の生成またはデーモンの起動前に停止する Debian、Ubuntu、または Snap ゲートウェイの場合、サービスを起動せずに選択された構成を検証します。

openshell-gateway config preflight [--path PATH | -- GATEWAY_ARGS...]

パスを指定しない場合、プリフライトでは空でない OPENSHELL_GATEWAY_CONFIG または自動検出された XDG 構成が検証されます。構成がなくても成功します。明示的に指定したパスが存在しない場合、レガシーな schema-v1 ファイル、形式不正な TOML、シンボリックリンク、または通常ファイル以外の場合は、ゲートウェイの起動前に失敗します。また、ドライバーの選択と構成、ソケット、レート制限、TLS、インターセプター、スーパーバイザーミドルウェアについて、読み取り専用の有効構成チェックも実行します。ファイルにセレクターがない場合、プリフライトはソケットやプロセスを使った検出プローブを実行せず、自動検出可能なドライバーの構成済みテーブルを検証します。-- の後の引数は、コマンドラインによる上書きを含め、有効なデーモン呼び出しを検証します。プリフライトでは、失敗したファイルはすべてそのまま保持されます。ユーザーにファイルの自動削除や書き換えを勧めないでください。ファイルをバックアップし、Gateway Configuration のリファレンスに記載された手動の schema-v2 移行手順に従ってください。

コメント