Use Templates, Claims, and Warm Pools
The optional extension controllers provide reusable templates, prepared workloads, and a claim workflow. They are disabled by default.
This guide uses one consistent resource chain:
python-template -> python-pool -> python-claim -> claimed Sandbox
Enable Extension Controllers
Connect kubectl to the intended workload cluster and inspect the controller arguments:
kubectl config current-context
kubectl get deployment agent-sandbox-controller \
-n agent-sandbox-system \
-o jsonpath='{.spec.template.spec.containers[0].args}{"\n"}'
Continue only when the output contains --extensions=true. Extension CRDs can exist while extension reconciliation is disabled.
If the flag is absent, open the installed Cluster Plugin in ACP, select Update, enable Extension controllers, wait for the Deployment rollout, and check the arguments again. Do not edit ModuleInfo, the Helm release, or the controller Deployment directly.
Set and verify the business namespace used by the remaining commands:
export BUSINESS_NAMESPACE=agent-demo
kubectl get namespace "$BUSINESS_NAMESPACE"
Create a SandboxTemplate
Create a restricted-compatible Python template. The policies disallow claim-time environment-variable and volume-template injection, which keeps the initial claim path narrow.
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
The template uses networkPolicyManagement: Unmanaged, so the business namespace is responsible for NetworkPolicy.
Before creating prepared workloads, apply and verify a minimal egress policy that allows DNS. Extend the same policy with explicitly approved business destinations when the workload needs them.
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"
Stop if the policy is not created successfully. Do not create a warm pool first and add its required network access later.
Create a SandboxWarmPool
Create one prepared workload from 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
A warm pool reduces preparation latency. It does not add a stronger runtime boundary. Runtime isolation still comes from the Sandbox Pod security settings and selected RuntimeClass.
Claim a Sandbox
Create an absolute expiration time and a claim that references 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 is an absolute expiration timestamp, not an idle timeout.
Verify the Claimed Sandbox
Wait for the claim and resolve the resulting Sandbox identity:
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
Warm-pool adoption can publish the Pod name as an annotation. A cold start can use the stable Sandbox identity as the Pod name fallback:
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")'
Expected output:
Clean Up
Verify the active cluster and namespace before deleting resources. Delete resources in reverse dependency order:
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"
Do not delete Agent Sandbox CRDs as part of workload cleanup. Removing a CRD deletes the API definition and can remove all instances of that resource type.