使用模板、声明与预热池

可选的扩展控制器提供可复用模板、预置工作负载和声明工作流。默认情况下它们处于禁用状态。

本指南使用一条一致的资源链:

python-template -> python-pool -> python-claim -> claimed Sandbox

启用扩展控制器

将 kubectl 连接到目标业务集群并检查控制器参数:

kubectl config current-context

kubectl get deployment agent-sandbox-controller \
  -n agent-sandbox-system \
  -o jsonpath='{.spec.template.spec.containers[0].args}{"\n"}'

仅当输出包含 --extensions=true 时才继续。即使扩展协调已禁用,扩展 CRD 仍然可以存在。

如果该标志不存在,请在 ACP 中打开已安装的集群插件,选择 Update,启用 Extension controllers,等待 Deployment 滚动更新完成,然后再次检查参数。不要直接编辑 ModuleInfo、Helm release 或控制器 Deployment。

设置并验证后续命令使用的业务命名空间:

export BUSINESS_NAMESPACE=agent-demo
kubectl get namespace "$BUSINESS_NAMESPACE"

创建 SandboxTemplate

创建一个受限兼容的 Python 模板。这些策略禁止在声明时注入环境变量和卷模板,从而使初始声明路径保持较窄。

cat <<'EOF' | kubectl apply -n "$BUSINESS_NAMESPACE" -f -
apiVersion: extensions.agents.x-k8s.io/v1beta1
kind: SandboxTemplate
metadata:
  name: python-template
spec:
  networkPolicyManagement: Unmanaged
  envVarsInjectionPolicy: Disallowed
  volumeClaimTemplatesPolicy: Disallowed
  podTemplate:
    metadata:
      labels:
        app.kubernetes.io/name: agent-sandbox-workload
    spec:
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        runAsGroup: 1000
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: python
          image: docker-mirrors.alauda.cn/library/python:3.12-alpine
          command: ["sh", "-c", "sleep 1800"]
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
EOF

该模板使用 networkPolicyManagement: Unmanaged,因此业务命名空间负责 NetworkPolicy。

在创建预置工作负载之前,先应用并验证一个允许 DNS 的最小出站策略。当工作负载需要这些访问时,在同一策略中显式添加已批准的业务目的地。

cat <<'EOF' | kubectl apply -n "$BUSINESS_NAMESPACE" -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: agent-sandbox-egress
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: agent-sandbox-workload
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
EOF

kubectl get networkpolicy agent-sandbox-egress \
  -n "$BUSINESS_NAMESPACE"

如果策略未成功创建,则停止。不要先创建预热池,再在之后添加其所需的网络访问。

创建 SandboxWarmPool

从 python-template 创建一个预置工作负载:

cat <<'EOF' | kubectl apply -n "$BUSINESS_NAMESPACE" -f -
apiVersion: extensions.agents.x-k8s.io/v1beta1
kind: SandboxWarmPool
metadata:
  name: python-pool
spec:
  replicas: 1
  sandboxTemplateRef:
    name: python-template
  updateStrategy:
    type: OnReplenish
EOF

kubectl wait --for=jsonpath='{.status.readyReplicas}'=1 \
  sandboxwarmpool/python-pool \
  -n "$BUSINESS_NAMESPACE" \
  --timeout=300s

预热池可降低准备延迟,但不会提供更强的运行时边界。运行时隔离仍然来自 Sandbox Pod 安全设置和所选 RuntimeClass。

声明一个 Sandbox

创建一个绝对过期时间,并创建一个引用 python-pool 的声明:

export CLAIM_EXPIRE_AT="$(python3 -c 'from datetime import datetime, timedelta, timezone; print((datetime.now(timezone.utc) + timedelta(minutes=30)).strftime("%Y-%m-%dT%H:%M:%SZ"))')"

cat <<EOF | kubectl apply -n "$BUSINESS_NAMESPACE" -f -
apiVersion: extensions.agents.x-k8s.io/v1beta1
kind: SandboxClaim
metadata:
  name: python-claim
spec:
  warmPoolRef:
    name: python-pool
  lifecycle:
    shutdownPolicy: Delete
    shutdownTime: "${CLAIM_EXPIRE_AT}"
EOF

shutdownTime 是绝对过期时间戳,而不是空闲超时。

验证已声明的 Sandbox

等待声明完成,并解析生成的 Sandbox 标识:

kubectl wait --for=condition=Ready sandboxclaim/python-claim \
  -n "$BUSINESS_NAMESPACE" \
  --timeout=180s

SANDBOX_NAME="$(kubectl get sandboxclaim python-claim \
  -n "$BUSINESS_NAMESPACE" \
  -o jsonpath='{.status.sandbox.name}')"

test -n "$SANDBOX_NAME"

kubectl wait --for=condition=Ready "sandbox/${SANDBOX_NAME}" \
  -n "$BUSINESS_NAMESPACE" \
  --timeout=180s

预热池接管时可以将 Pod 名称作为注解发布。冷启动可以将稳定的 Sandbox 标识作为 Pod 名称回退值:

POD_NAME="$(kubectl get sandbox "$SANDBOX_NAME" \
  -n "$BUSINESS_NAMESPACE" \
  -o jsonpath='{.metadata.annotations.agents\.x-k8s\.io/pod-name}')"

if [ -z "$POD_NAME" ]; then
  POD_NAME="$SANDBOX_NAME"
fi

test -n "$POD_NAME"

kubectl exec -n "$BUSINESS_NAMESPACE" "$POD_NAME" -c python -- \
  python -c 'print("claim-sandbox-check=ok")'

预期输出:

claim-sandbox-check=ok

清理

在删除资源之前,先验证当前活动的集群和命名空间。 按依赖关系的相反顺序删除资源:

kubectl config current-context
kubectl delete sandboxclaim python-claim -n "$BUSINESS_NAMESPACE"
kubectl delete sandboxwarmpool python-pool -n "$BUSINESS_NAMESPACE"
kubectl delete sandboxtemplate python-template -n "$BUSINESS_NAMESPACE"
kubectl delete networkpolicy agent-sandbox-egress -n "$BUSINESS_NAMESPACE"

不要在清理工作负载时删除智能体 Sandbox CRDs。删除 CRD 会删除 API 定义,并可能移除该资源类型的所有实例。