mcpField
D
debug-openshell-cluster

debug-openshell-cluster

github.com/nvidia云与 DevOps20.6k538 次安装今天更新
代码仓库

关于 debug-openshell-cluster

用于排查 OpenShell 网关及其计算平台部署问题的诊断技能,面向运维人员。它按网关连通性、所选驱动和平台日志逐步检查,并强调网关与计算运行时的职责边界。

主要功能

  1. 01检查 CLI 与网关连通性
  2. 02识别计算驱动与平台
  3. 03诊断启动依赖和配置
  4. 04检查 Kubernetes 与容器运行时
  5. 05排查认证、TLS 和资源准入

适用场景

  1. 01确认网关端点和认证状态
  2. 02调查沙箱创建失败
  3. 03排查 Kubernetes 部署问题

安装

复制下面的命令,在终端中运行。

$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 和 supervisor 身份验证材料:edge 或 OIDC 用户身份验证、可选的 CLI mTLS,以及由网关签发的沙箱 JWT。
  4. CLI 使用 openshell gateway add 注册可访问的网关端点。
  5. 网关通过所选计算驱动程序创建沙箱。

openshell-gateway 组合 crate 会在启动时显式安装其编译好的 Docker、Podman、Kubernetes 和 VM 注册项;openshell-server 不会链接计算驱动程序 crate。自定义网关二进制文件可以只包含其中部分注册项。如果未配置驱动程序,网关只会按优先级探测已安装的注册项(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:运行时套接字必须可从网关主机访问。

以 openshell --help 和嵌套的 --help 输出为准,确认已安装 CLI 版本的功能。部署和配置行为以已发布的安装指南、计算驱动程序参考、网关配置参考和 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 不匹配,supervisor 缺少网关 CA,或 TLS 终止配置与网关监听器不匹配。工作负载和 supervisor 不应包含用户 TLS 客户端证书或私钥。
  • 全新 Snap 安装使用 openshell.user-gateway;升级安装则通过 openshell.system-gateway 保留原有系统管理状态。服务重命名后,现有 HTTPS 注册仍可继续使用。请按照已发布的 Snap 安装步骤注册新用户、替换旧的 HTTP 注册,或通过 disable 维护状态安全地切换模式。如果 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 版本、网关工作负载、服务、密钥、沙箱 Pod、事件。
OpenShift与 Kubernetes 相同,此外还需检查 SecurityContextConstraints (SCCs);若要从外部访问,还需检查 OpenShift Route。可通过是否存在 route.openshift.io API 组来检测 OpenShift(oc api-resources --api-group=route.openshift.io)。
VMVM 驱动程序日志、rootfs 可用性、主机虚拟化支持。
Extension外部驱动程序进程、Unix 套接字所有权/模式、配置的驱动程序名称、能力握手、网关日志。
第 3 步:检查网关启动依赖项

在调试计算平台之前,请检查网关日志,查找监听器就绪前初始化的依赖项是否发生故障。

网关容器使用 Distroless Debian 运行时。对于操作系统库漏洞 问题,请检查已部署的镜像摘要和软件包版本;使用已修补基础镜像 重新构建的网关镜像进行部署。仅更新网关二进制文件不会更新其容器镜像提供的库。 对于资源准入失败,请区分调用方驱动程序配置被禁用和缺少资源审批这两种情况。Helm 默认将 server.drivers.kubernetes.allowDriverConfig 设为 false,并将 resourceAdmission.enabled 设为 true。现有 PVC、RuntimeClass 和 PriorityClass 需要带有匹配的管理员所有标签;加入命名空间和只读访问权限都不代表已获审批。GPU 设备和操作员选择的镜像拉取 Secret 无需准入标签。在托管模式下,请检查网关命名空间中配置的源镜像拉取 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 值仍可作为已弃用的、仅限环境变量的别名;网关会发出警告并选择该驱动程序。空值、无效值、逗号分隔值或冲突值都会导致启动失败。除非设置 enable_websocket_tunnel = true(Helm 中为 server.enableWebsocketTunnel),否则用于 edge-proxy CLI 访问的 WebSocket 隧道处于关闭状态。Homebrew 和 RPM 软件包启动时只会迁移完全匹配的软件包生成的 v1 默认配置。如果升级后的软件包仍报告版本不受支持,请检查当前使用的前缀或 ~/.config/openshell/gateway.toml;已编辑的 v1 文件必须遵循已发布的 schema-v2 迁移步骤,且不得被覆盖。 supervisor 网关 CA 是驱动程序所有权规则的例外:请在 [openshell.gateway] 下配置 guest_tls_ca,网关只会将其注入选定的本地驱动程序。请移除已弃用的 guest_tls_cert 和 guest_tls_key 字段。如果既没有该 CA,也没有软件包管理的本地 CA,启用 TLS 的 Docker、Podman 和 VM 驱动程序会启动失败。Kubernetes 只会将网关 CA 从 Secret 投射到 supervisor Pod;supervisor 使用沙箱承载令牌对网关 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 凭据驱动程序,无论工作区模式如何,每个提供程序凭据都位于配置的 namespace 中。指明其他命名空间的 PermissionDenied 错误表示提供程序的凭据句柄指向配置命名空间之外;请重新创建提供程序。[openshell.credential_drivers.kubernetes-secrets] 的 unknown field 启动错误表示该表设置了驱动程序不接受的键。确认网关可以访问凭据命名空间:

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 服务端的颁发者。主机名不匹配表示 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 和有效的 bearer token;请检查私有 CA 路径、端点主机名、预期受众、颁发者、kid,以及拦截器日志中的令牌拒绝信息。如果设置了 allow_insecure_transport = true,则会明确保留未经身份验证的明文传输行为。如果 provider_profile_sources 指定了拦截器,该拦截器必须声明 provider-profile 能力,并返回有效且无重复项的目录。仅选择拦截器来源时,该来源具有权威性;如需组合,请显式包含 user 来源。builtin 来源类型已移除:仍指定该类型的配置会在启动时被拒绝。

如果部署使用 supervisor 中间件,请参阅 supervisor 中间件故障排查参考 以排查启动、身份验证、策略验证以及 HTTP 或 WebSocket 故障。

对于网络策略验证失败,请先区分网关变更拒绝与 supervisor 运行时拒绝。当网关知道受影响的沙盒范围时,直接策略更新、增量合并和审批、提供程序附加以及 provider-profile 扇出,都会在持久化之前根据完整的有效策略进行验证。FAILED_PRECONDITION 歧义响应表示未存储无效版本或部分扇出。对于启动、竞态以及这些变更路径之外的策略来源,supervisor 验证仍会提供纵深防御。

运行时拒绝行为只能在 gateway.toml 中配置:

[openshell.gateway]
policy_validation_failure_mode = "fail_closed"

默认的 fail_closed 模式会停用上一代策略、关闭固定中继,并隔离新的出站流量,直至加载有效版本。retain_last_valid 会明确保留上一份有效策略处于活动状态;如果不存在上一份有效策略,仍会故障关闭。更改此字段后,请重启网关。请检查沙盒 OCSF 配置和发现事件,了解验证原因、配置模式和有效模式、活动版本,以及明确的 previous_policy_active 状态。 已发布的 supervisor 镜像使用无 shell 的 distroless Debian 13 基础镜像。 对于使用 SUPERVISOR_BASE_IMAGE 的自定义构建,请检查所选基础镜像的 GNU 运行时库、CA 证书,以及继承的用户和工作目录。 使用容器日志、引擎检查和已配置的 exec 健康探针进行诊断; exec ... sh、安装软件包和容器内 shell 脚本均不可用。工作负载的 shell 属于单独的 sandbox 镜像。复现 supervisor 启动故障时,请保留驱动程序选定的 UID 以及可写的运行时和日志挂载。

ConfigurationInvalid 就绪条件表示启动准入拒绝了镜像/有效策略或提供方配置。 supervisor 会保持运行,而工作负载不会启动。检查 openshell sandbox get,并通过完整替换策略或更换提供方来修复期望配置;不要将容器健康视为工作负载已就绪的证明。 如果 300 秒的配置修复窗口到期,gateway 会记录 ProvisioningTimedOut 并停止工作负载和 supervisor 的计算资源。 检查 sandbox JSON 中的 provisioning 和 TUI NOTES,以区分清理待处理和清理完成。 到期后修复配置不会重启计算资源:请等待清理完成,然后明确执行 sandbox start。 重复的拒绝报告不会延长截止时间,CLI 等待超时也不会影响该时间。 请参阅策略验证与修复。 隔离的 supervisor 会在准入前,通过经过身份验证的 sandbox 边界请求镜像策略发现。 修复配置期间,工作负载边界可以保持运行而不启动工作负载。不可用的边界会在其控制请求截止时间内使发现失败。永久 gateway 错误和瞬时重试耗尽会终止启动;请将这些错误视为连接、授权或生命周期故障进行检查。

步骤 4:检查由 Docker 支持的 Gateway

sandbox 容器的日志包含 sandbox 运行时警告,以及未使用 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。
  • 网关进程已停止:检查退出状态和日志。
  • 沙盒镜像缺失或拉取遭拒:验证镜像引用和注册表凭据。
  • 沙盒在就绪前因身份解析错误而失败:检查镜像的 OCI USER 以及对应的 /etc/passwd 和 /etc/group 条目,或在策略中明确设置两个进程身份字段。接受数值为 1 到 4294967294 的工作负载身份;拒绝 root、无效身份哨兵值以及缺失的身份。
  • 沙盒在就绪前因 OCI 工作区验证错误而失败:使用网关报告的不可变镜像 ID 检查镜像的 WorkingDir。空值、/ 和显式的 /sandbox 均使用受管理的 /sandbox 兼容工作区。任何其他工作目录都必须是绝对规范化目录,且不能包含符号链接组件;最终策略中的 UID、主 GID 和补充组必须通过内核的有效遍历/写入检查,包括 POSIX ACL 和 LSM 判定。OpenShell 不会创建、chown 或 chmod 非默认镜像工作目录。
  • 如果镜像 VOLUME 或驱动器挂载覆盖了工作目录或其任一父目录,Docker 和 Podman 也会拒绝该镜像,因为运行时会在验证前遮蔽不可变路径。将 VOLUME 移到工作区下方,或移除该声明。
  • 自定义 Docker 和 Podman 工作区中的更改保存在工作负载容器的可写层中,而不是受管理的命名卷中。停止并启动同一容器会保留这些更改;移除或替换该容器则不会。删除沙盒前,请导出所需文件。
  • 如果工作目录因属于特殊文件系统或与 OpenShell 控制路径冲突而被拒绝,则无法通过权限设置使其有效。请将镜像工作目录移离内核支持的挂载点,以及错误中列出的具体 supervisor、TLS、令牌、运行时和套接字路径。
  • 导出 supervisor 镜像后,本地 Docker 网关设置无法复制 openshell-sandbox:沙盒运行时和 supervisor 是彼此独立的构件。运行时镜像必须提供 /openshell-sandbox;supervisor 镜像则提供 /openshell-supervisor。
  • Docker 驱动无法初始化,因为找不到 openshell-sandbox:验证 openshell-gateway 旁边是否有同级二进制文件,或确认配置的 sandbox_runtime_image 中包含 /openshell-sandbox。
  • 沙盒始终无法注册:检查网关日志和 supervisor 的网关端点。
  • SSH 主机密钥启动错误:使用版本相匹配的网关、计算驱动和 supervisor。网关会在配置的凭据存储中保留每个沙盒的 SSH 密钥,并仅通过 supervisor 引导包发送该密钥。检查凭据驱动是否可用,并比对沙盒 JSON 输出中的公钥 host_key_fingerprint;切勿打印引导包或私钥。对于带有指纹的沙盒,如果找不到已存储的密钥,应视为错误,而不能替换其身份。请参阅 沙盒 SSH 身份文档。
  • 沙盒处于 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 中启用主机网络, 确保已禁用增强型容器隔离,并验证网关的主端点可从使用主机网络的容器访问。
  • 沙盒运行时镜像在打印 openshell-sandbox --version 前退出:验证配置的镜像中是否包含位于 /openshell-sandbox 的静态可执行文件。
  • 显式配置 protocol: tcp 端点的沙盒在工作负载就绪前失败:确认所选隔离后端支持 TCP 中介,然后检查沙盒和 supervisor 日志,查看受保护通道设置或监听器是否失败。无法提供所需外层出口防护和经过身份验证的运行时通道的驱动必须在启动 Agent 前拒绝该策略。
  • Supervisor 运行时验证失败:确认 supervisor_image 中包含来自与沙盒运行时相同版本的 /openshell-supervisor 可执行文件,并且该镜像中提供了它所依赖的动态加载器和共享库。运行 docker run --rm --network none --entrypoint /openshell-supervisor <supervisor_image> --version 应打印该版本;如果二进制文件确实存在却报错 no such file or directory,则表示缺少加载器或库。Supervisor 在自己的镜像中运行,无需是静态的;只有 /openshell-sandbox 必须是静态的。
  • 沙盒未通过强制执行探测:检查沙盒日志,找出失败的具体嵌套检查:seccomp 用户通知、任务内存、Landlock、环回 DNS 或套接字注入。运行时在满足生产环境中父进程到工作负载子进程的任务内存探测(通过 /proc/<pid>/mem)时,可能会对 process_vm_readv 和 process_vm_writev 返回 ENOSYS;只有两个后端都失败才属于致命错误。不要添加能力或切换到不受限的 seccomp 配置文件;请使用默认配置文件允许非特权探测的运行时。
  • GPU 沙盒因 Docker 报告未发现 NVIDIA CDI 设备而失败:验证 .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] 下由运维人员管理的字段。确认完整的代理表,并检查配套的 supervisor 命令和日志:

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 驱动会将经过验证的证书包复制到仅供 supervisor 使用的命名卷中,并传入固定路径 /.openshell/supervisor/upstream-proxy-ca-bundle.pem。网关主机路径不得出现在容器参数、挂载、工作负载环境或 template.driver_config.docker 中。

HTTPS 代理证书错误通常意味着证书包缺少代理监听器的签发者,或者其中的证书与代理主机名不匹配。TLS 拦截的目标错误意味着缺少重新签署证书的签发者,或者 supervisor 未收到证书包。请保持验证启用,并修正运维人员提供的证书包。

在网关优雅重启期间,具有运行意图的 Docker、Podman 和 VM 沙箱应在网关退出前停止,并在网关恢复后重新启动。请在网关日志中查找 Stopped sandbox during gateway shutdown 和 Started sandbox during gateway startup。通过 CLI 明确停止的沙箱仍会保持停止状态。Kubernetes 沙箱由集群管理,不遵循此本地网关生命周期。内部和外部驱动遵循相同规则:GetCapabilities.gateway_manages_lifecycle 必须为 true,网关才会执行关机和启动扫描。

网关还会在退出前完成 supervisor 会话所有权清理。如果关机时报告 Gateway supervisor session cleanup incomplete,请检查关联的持久化错误:已停止的 supervisor 的所有者记录可能会一直保留到租约到期,并暂时阻止重新连接。仅仅成功停止计算资源,并不能确认会话清理已完成。

对于 --restart-policy on-failure 或 always 的沙箱,请使用 openshell sandbox get <name> 检查策略、退出代码、重启次数和下次重启时间。Starting 可能表示网关正在等待退避时间结束,或等待替代 supervisor。若截止时间已过但状态仍未转为 Ready,请检查网关日志中的停止或启动错误。Docker、Podman、Kubernetes 和 VM 的原生重启策略均保持禁用;替代实例由网关负责。

步骤 5:检查由 Podman 支持的网关
podman info
podman ps --filter name=openshell
podman logs <container> --tail=200
openshell status

常见问题:

  • Podman 套接字不可用:启动或公开用户套接字。
  • Rootless 网络不可用:检查 Podman 网络配置。
  • 缺少沙箱镜像或拉取被拒绝:验证镜像引用和注册表凭据。
  • 沙箱在就绪前因身份解析错误而失败:检查镜像的 OCI USER,以及匹配的 /etc/passwd 和 /etc/group 条目,或在策略中明确设置两个进程身份字段。接受数值为 1 到 4294967294 的工作负载身份;拒绝 root、无效身份哨兵值和缺失身份。
  • Supervisor 无法连接:检查其网关端点和网关日志。
  • 检查沙箱对应的两个 Podman 容器:sandbox 隔离角色必须使用网络模式 none;supervisor 角色负责网关会话和出口流量。两者均以非 root 身份运行,并丢弃所有功能。如果身份验证失败,请检查私有通道卷和共享用户命名空间映射。
  • 如果沙箱在就绪前失败,请检查其非特权执行探测,以及配套 supervisor 的私有健康检查。不要添加功能、连接工作负载网络,也不要禁用运行时 seccomp 配置文件。无需修复沙箱 nftables 或嵌套网络设置。
  • 在 Linux 上,确认使用主机网络的 Podman supervisor 能够访问网关的主要环回端点。在 macOS 上,确认 Podman Machine 的主机环回转发正常,或配置显式的 grpc_endpoint。
  • 如果工作负载内无法解析 host.openshell.internal,请确认其 /etc/resolv.conf 中包含 nameserver 127.0.0.53。Podman 驱动会从每个沙箱专用的 secret 挂载该文件,并向 supervisor 提供别名目标地址。只有当平台默认地址(原生 Linux 上为 127.0.0.1,macOS Podman Machine 上为 192.168.127.254)无法连接到网关主机时,才检查 host_gateway_ip。

配置了 userns 时(例如 userns = "auto" 或 userns = "keep-id"):

  • 沙箱运行时交付会使用 bind mount 回退方式,而非镜像卷,因为 overlay 挂载不支持 idmapped 挂载。supervisor 二进制文件会从沙箱运行时镜像中提取,并缓存在 $XDG_DATA_HOME/openshell/podman-supervisor/(通常为 ~/.local/share/openshell/podman-supervisor/)。
  • 缓存过期:如果沙箱运行时镜像已更新,但缓存的二进制文件未刷新,创建沙箱时可能会因 ELF 验证错误或版本不匹配而失败。删除缓存目录后重试。
  • auto 模式要求当前用户在 /etc/subuid 和 /etc/subgid 中配置 subuid/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 状态:检查 supervisor 日志中的 failed to signal entrypoint process group。Supervisor 必须保留 CAP_KILL,以便其 root 进程将 SIGTERM 转发给以沙箱用户身份运行的工作负载。
步骤 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}"

根据该版本中实际存在的网关资源类型,使用相应的日志和 rollout 命令。检查安装失败、意外的值、缺失的命名空间、错误的镜像标签、与已注册端点不匹配的 TLS 设置,以及调度失败。 检查 Helm values 迁移时,请将渲染后的 gateway.toml 与预期的 gatewayConfig 表进行比较。显式资源准入设置和 Kubernetes Secrets 凭据命名空间 优先于已弃用的别名。确认凭据驱动的命名空间与其 Role 和 RoleBinding 一致。未设置工作负载的 image_pull_policy 时,将使用 Kubernetes 默认值; 全局 Helm 拉取策略适用于运行时和 supervisor 镜像。

该 chart 会将 gateway.toml ConfigMap 键直接挂载到 /etc/openshell/gateway.toml,作为只读的 subPath 文件。这样可以避免 ConfigMap 目录挂载暴露的原子写入器符号链接,因为 gateway 会拒绝符号链接配置。 checksum pod-template 注解会在 ConfigMap 变更时滚动更新工作负载。如果配置预检报告路径是符号链接或 非普通文件,请检查渲染后的挂载,并确认工作负载已滚动更新到当前 chart 修订版:

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 会在 gateway pod 上渲染为 OPENSHELL_TELEMETRY_ENABLED,gateway 会将生效值传递给 sandbox supervisor。

未启用外部凭据驱动时,Helm chart 会使用 gateway 默认的加密数据库凭据存储。该 chart 会创建一个保留的 Kubernetes Secret,用于存储共享 KEK,将其注入 gateway pod,并在 OpenShell 数据库中存储加密凭据信封。对于 workload.kind=deployment 或多副本 gateway,请确认 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

多副本 gateway 使用 PostgreSQL advisory lock 来串行处理跨对象的 sandbox 和 provider 变更。 如果这些 RPC 停滞,而普通读取和健康检查仍能正常响应,请检查长时间运行的数据库会话和等待 advisory lock 的请求。请勿将数据库 URI 或 Secret 内容输出到 日志中:

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

对于多副本 gateway 安装,supervisor 和客户端会话流量可能由非所有者 gateway 副本处理,并通过内部 PeerRelay RPC 中继到当前 supervisor 所有者。请检查无头 peer Service、 投射的 peer 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 启动日志包括 gateway peer ServiceAccount TokenReview authentication enabled。如果 peer relay 调用因 Unauthenticated 失败,请确认 gateway-peer-token 投射卷的受众为 openshell-gateway-peer,并确认接收请求的 gateway 可以 创建 TokenReview。如果调用因 PermissionDenied 失败,请确认 gateway ServiceAccount 名称、发布版本命名空间、pod UID 和 Helm 选择器标签与运行中的 gateway pod 相符。由 Deployment 支持的 gateway pod 还应从其 pod IP 发布 OPENSHELL_PEER_ENDPOINT。OPENSHELL_PEER_SERVICE_ACCOUNT_TOKEN_FILE 的命名遵循现有令牌文件约定,与 OPENSHELL_SANDBOX_TOKEN_FILE 和 OPENSHELL_K8S_SA_TOKEN_FILE 一致。

对于启用了 TLS 的 gateway,peer 客户端会验证稳定的 gateway Service DNS 名称,并从以下位置加载 chart CA 和客户端身份: OPENSHELL_PEER_TLS_CA_FILE、OPENSHELL_PEER_TLS_CERT_FILE 和 OPENSHELL_PEER_TLS_KEY_FILE。如果 peer 调用在 TLS 协商期间失败,请确认 peer-client-tls 卷存在、这些文件可读,并且服务器证书包含 OPENSHELL_PEER_TLS_SERVER_NAME 中的名称。

要检查多副本 gateway 的每副本容量,请读取每个 gateway 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)的 Pod。它会跳过证书钩子 Job Pod;旧版 chart 曾将它们标记为网关 Pod。指标端口为 service.metricsPort(默认值为 9090)。

API 服务器代理会从控制平面连接到每个 Pod。如果 NetworkPolicy 仅允许来自监控命名空间的流量访问指标端口,就会阻止该代理,除非策略也允许控制平面访问。在这种情况下,请通过 kubectl port-forward 一次读取一个 Pod;它通过 kubelet 连接到 Pod,不受 NetworkPolicy 阻止:

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 部署所需的密钥:

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

当 server.tls.clientCaSecretName="" 时,即使启用了内置 PKI 或 cert-manager,chart 也会有意省略 client_ca_path 和 tls-client-ca 挂载。这是预期行为;不要将缺少 tls-client-ca Pod 挂载视为缺陷(PKI 可能仍会创建 openshell-server-client-ca)。 用户身份验证使用 OIDC 或受信任代理(server.auth.allowUnauthenticatedUsers=true); supervisor 传输仍使用 openshell-client-tls。

在 cert-manager 安装中,certManager.enabled=true 会让 cert-manager 负责生成 TLS。 即使 pkiInitJob.enabled 仍为 true,Helm chart 也应在仅 JWT 模式下渲染 openshell-certgen 预安装/预升级钩子,以创建 openshell-jwt-keys。 如果网关 Pod 因 MountVolume.SetUp failed for volume "sandbox-jwt" 而处于 Pending 状态,且不存在 openshell-jwt-keys,请检查渲染后的 templates/certgen.yaml 输出和钩子 Job 日志;cert-manager 会创建 TLS 密钥,但不会创建 sandbox JWT 签名密钥。

如果网关因 failed to read sandbox JWT signing key from /etc/openshell-jwt/signing.pem 而退出,请确认 openshell-jwt-keys 包含 signing.pem、public.pem 和 kid,并且网关工作负载将 sandbox-jwt 密钥挂载到 /etc/openshell-jwt。即使本地 Helm 值禁用了 TLS,sandbox JWT 挂载仍然是必需的。

如果 certManager.serverIssuerRef 将服务器证书指向外部 Issuer 或 ClusterIssuer(例如,用于在 OpenShift Route 上配置 TLS passthrough 的公信 ACME 颁发者——参见 openshiftRoute.enabled),chart 会创建两张服务器证书:一张内部证书(chart CA、内部 SAN),以及一张外部证书(由配置的颁发者签发,仅包含外部 SAN)。网关会使用 SNI 来呈现正确的证书。

如果外部密钥始终未变为 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 颁发者会拒绝包含仅限内部名称(*.svc.cluster.local、localhost、环回 IP)的证书请求,并要求 commonName 同时也是 SAN——外部 Certificate 仅请求 certManager.serverDnsNames 中的主机名,正是出于这个原因。

如果配置 serverIssuerRef 后,sandbox supervisor 与网关的 TLS 握手因 UnknownCA 失败,最可能的原因是 server.grpcEndpoint 设置为了外部主机名。这会强制 supervisor 通过外部主机名连接,并通过 SNI 收到它们无法使用 chart CA 验证的 ACME 证书。请移除 server.grpcEndpoint,或将其设置为内部服务名称,以便 supervisor 收到内部证书:

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

较少见的情况是,如果网关的客户端验证 CA 配置错误,可能会出现 UnknownCA。对于所有配置,默认值 clientCaFromServerTlsSecret=true 都是正确的——内部服务器证书始终由 chart 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。 网关和沙箱 Supervisor 都使用 SPIRE 动态授予提供方令牌。网关 Pod 必须挂载 spiffe-workload-api CSI 卷,并设置 OPENSHELL_GATEWAY_SPIFFE_WORKLOAD_API_SOCKET;Supervisor Pod 必须从 Kubernetes 驱动配置中接收匹配的 Workload API 套接字。 网关通过此 Workload API 套接字获取的 JWT bundle 验证 Supervisor JWT-SVID,而不是通过 SPIRE OIDC 发现端点验证。 确认 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 标签、Supervisor 环境变量 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 缺失,post-install certgen hook 可能因等待 cert-manager 签发服务器证书超时而失败。检查 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'

网关、沙箱和 Supervisor 镜像应使用相同的发布标签。运行时镜像过旧会导致沙箱行为滞后于网关策略或协议变更。

对于漏洞报告,请记录正在运行的镜像摘要,并扫描该确切制品。网关包含固定版本的 Distroless 基础镜像;Supervisor 包含在镜像构建时更新的 Alpine 软件包。依赖项或基础镜像修复只有在重新构建、发布并重新部署镜像后,才会应用到已部署的容器。请对照该摘要对应的 SBOM 检查发现项,而不只是查看可变的 latest 或 dev 标签。 刷新网关基础镜像时,请验证各平台 SBOM 中已安装的 libc 软件包版本;二进制文件的 glibc 兼容性下限并非其运行时版本。

对于明文本地评估,请确认 chart 包含:

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 设置。声明支持沙箱身份验证的驱动,在创建沙箱和验证凭据时必须返回相同且非空的运行时身份。如果网关日志报告计算运行时身份不匹配,说明运行时资源已过时或被重新创建;请将实时资源 UID 与网关配置的沙箱进行比较。重启也会拒绝具有相同沙箱标签的多个 Sandbox 资源,并要求已持久化的命名空间和 CR UID 保持不变。由代际绑定的会话令牌被拒绝,通常意味着监督程序正在提供来自已替换运行时的凭据;请检查已持久化的代际,再重试引导。

Kubernetes 驱动会在单个驱动实例内,按沙箱串行处理生命周期变更和运行时协调。繁忙的沙箱会在下一轮协调时再次检查。如果重启仍导致监督程序丢失,请比较 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。该策略会拒绝所有工作负载出站流量,并允许监督程序 Pod 连接沙箱 TLS 监听器。随后,驱动会创建每个沙箱专用的 Service、拆分后的不可变引导 Secrets,以及启用了门控的监督程序 Pod,然后再释放任一 Pod。监督程序 Pod 运行 /openshell-supervisor。两个 Pod 使用 相同的已解析非 root 身份,不请求任何能力,丢弃 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 已就绪,且 supervisor Pod 为 Available。只有在 supervisor 已完成附加、确认强制执行、启动或恢复工作负载,并注册网关访问平面后,其 exec 就绪检查才会成功。排查引导错误时,请查看两个 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。在 operator 模式下,这些权限仅来自安装在该命名空间中的 openshell-workspace chart。恢复流程会先按名称删除记录的 generation 的引导 Secret,然后清除暂停注解:

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

任何结果为 no 的检查都可能导致恢复流程在创建工作负载 Pod 之前受阻。请升级 OpenShell chart,而不要将缺少工作负载 Pod 视为 Pod 故障。

企业上游代理

当部署通过企业 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 位于网关的发布命名空间,而非沙箱命名空间。网关会读取它,并将证书包暂存到每个沙箱的 supervisor 引导 Secret 中。若 ConfigMap 缺失,网关 Pod 会停留在 ContainerCreating 状态,与 oidc-ca 和 vault-ca 的情况相同:

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 错误。该错误会导致网关在启动时拒绝启动,而不是回退到直接出站。

代理参数和凭据挂载仅属于单独的 supervisor 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。请检查网络 supervisor 日志中的 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 并不能免除这项前置要求。
  • 持久化的 overlay 身份错误已根据其所有者标记、overlay 上层、准备好的 rootfs、显式配置或当前镜像得到解决。除非持久化状态报告的是该旧版身份,否则不要指定 10001:10001。
  • 已启用主机虚拟化支持。
  • 沙箱 supervisor 可以建立经过身份验证的网关会话。

然后运行:

openshell status
openshell logs <sandbox-name>
企业上游代理

当 VM 沙箱的出站流量经由企业 HTTP 转发代理时,由运维人员管理的设置位于 [openshell.drivers.vm] 下,网关会将这些设置转发给 openshell-driver-vm 子进程,作为 --upstream-proxy、 --upstream-no-proxy、--upstream-proxy-auth-file、 --upstream-proxy-auth-allow-insecure、 --upstream-proxy-connect-by-hostname 和 --upstream-proxy-ca-bundle 参数。网关和驱动程序都会在启动时验证这些设置,因此,任何已提供但无效的值都会导致启动失败,并报错指出对应的键,而不会回退为直接连接。请先确认配置和最终生成的驱动程序 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 会将该名称规范化为主机回环地址。请检查沙箱状态目录下的 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 网关 Pod 处于 Pending 状态PVC 未绑定、污点、选择器或资源不足kubectl -n openshell describe pod <pod>
Kubernetes 沙箱 Pod 卡在 Pending 状态,工作区 PVC 未绑定集群没有默认 StorageClass,且 OpenShell 未在工作区 PVC 上设置 storageClassName(具有默认 StorageClass 的集群无需此项即可成功绑定)kubectl -n openshell describe pvc;将 server.workspaceStorageClass(网关配置 workspace_storage_class)设置为有效的 StorageClass
Kubernetes 网关 Pod 反复崩溃缺少 Secret、数据库 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)、maxReplicas 大于 1 但未设置 server.externalDbSecret(或使用 StatefulSet 但未设置 workload.allowMultiReplicaStatefulSet)、缺少指标目标,或最小值/最大值顺序错误。“minReplicas and maxReplicas are not set”表示 --reuse-values 保留了一个未包含 chart 自动扩缩默认值的 release修复错误中指出的值;使用 --reset-then-reuse-values 而不是 --reuse-values 进行升级
HPA 的目标显示为 <unknown>没有用于 CPU/内存的 metrics-server,或指标适配器未提供自定义指标kubectl -n openshell describe hpa openshell、kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1
发布后,一个副本持有大多数会话这是预期行为:会话会留在重新连接的副本上查看每个 Pod 的 openshell_server_supervisor_sessions;随着沙箱重新创建,该值会逐渐下降
OpenShift 网关 Pod 启动失败,并出现 SCC/runAsUser 错误(例如 unable to validate against any security context constraint)Chart 默认的 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 沙箱 Pod 启动失败(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 凭据存储 Pod 始终无法调度(等待超时并显示 no matching resources found)存储的 Helm chart 固定设置了 runAsUser/fsGroup/seccomp,被 restricted-v2 拒绝,因此 StatefulSet 控制器不会创建 Pod以 OpenShift 模式部署存储的 chart(对于 OpenBao/Vault chart,使用 --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、服务验证器配置和日志;仅通过已信任的网关 TLS 端点获取 well-known 元数据
启用拦截器目录后,提供方配置文件消失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 未配置 chart 创建的 Gateway,或其代理 Service 与 OpenShell Service 冲突所选控制器不可用,或默认的 grpcRoute.gateway.name 复用了 OpenShell Service 名称检查 kubectl get gatewayclass,gateway,grpcroute -A;设置不同的 Gateway 名称,例如 <fullname>-ingress。对于现有 Gateway,设置 gateway.create=false 以及 gateway.name、gateway.namespace 和可选的 gateway.sectionName
HTTPS 入口(grpcRoute.gateway.listener.protocol=HTTPS)连接重置或 TLS 握手挂起Envoy 终止了 TLS,但网关 Pod 仍要求 TLS,因此明文后端连接失败设置 server.disableTls=true,使 Envoy 将明文转发到 Pod;确认监听器的 certificateRefs Secret 存在于 release 命名空间中,并通过 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 入口连接后返回 UnauthenticatedTLS 在 Envoy 处终止,因此网关看不到客户端证书;未配置用于身份标识的 OIDC 颁发者配置 server.oidc.issuer,并使用 openshell gateway add https://<host> --oidc-issuer <url> 注册;或者在受信任的代理/开发集群中设置 server.auth.allowUnauthenticatedUsers=true
设置 certManager.serverIssuerRef 后,外部服务器的 Certificate 始终未进入 Ready 状态ACME 颁发者拒绝了仅内部使用的 SAN、环回 IP,或未出现在 SAN 中的 commonNamekubectl -n openshell describe certificate openshell-server-external;确认 certManager.serverDnsNames 仅列出真实且可从外部解析的主机名
配置 certManager.serverIssuerRef 后,沙箱监督器 TLS 握手因 UnknownCA 失败设置了 server.grpcEndpoint 为外部主机名,强制监督器接收 ACME 证书(通过 SNI),而该证书无法通过 chart CA 验证移除 server.grpcEndpoint,或将其设置为内部服务名称;监督器应通过内部服务名称连接以接收内部证书
浏览器显示 ERR_BAD_SSL_CLIENT_AUTH_CERT,或网关日志显示在预期使用 OIDC 或直接 HTTPS 时进行了客户端证书验证监听器的客户端 CA 验证仍处于启用状态(未设置 clientCaSecretName,或 ConfigMap 中存在 client_ca_path)设置 server.tls.clientCaSecretName="",升级 chart,并确认 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 迁移步骤操作。

评论

支持 Markdown