Create a sandbox for interactive inspection

You don’t need an SSH server or SSH keys inside the sandbox. kubectl exec uses your Kubernetes authentication to open a process in the selected container.

Download inspect_filesystem.py into your working directory:

    

        
        
cd "$LP_WORKDIR"
curl -fL https://raw.githubusercontent.com/ArmDeveloperEcosystem/arm-learning-paths/main/content/learning-paths/servers-and-cloud-computing/gke-agent-sandbox/files/inspect_filesystem.py \
  -o inspect_filesystem.py

    

Create a sandbox claim and wait for the Pod to be ready:

    

        
        
rm -rf "$LP_WORKDIR/runs/shell"
python3 claim.py create \
  --context "$GKE_CONTEXT" --namespace "$NAMESPACE" \
  --pool axion-python-pool --purpose shell --output-dir "$LP_WORKDIR/runs/shell"

    

Load the Pod name into your shell, verify the binding, then open a shell in the sandbox:

    

        
        
source "$LP_WORKDIR/runs/shell/binding.env"
python3 claim.py check --record "$LP_WORKDIR/runs/shell/run.json"
kubectl --context "$GKE_CONTEXT" -n "$NAMESPACE" exec -it "$POD_NAME" -c runtime -- /bin/sh

    

You now have a shell inside the sandbox.

Inspect the user and Linux environment

Run the following commands inside the sandbox shell:

    

        
        
id
uname -m
uname -sr
pwd
python3 --version
cat /etc/os-release
ls -la /workspace

    

The expected output is:

    

        
        uid=1000 gid=1000 groups=1000
aarch64
Linux 4.19.0-gvisor
/workspace
Python 3.12.15
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
...
total 4
drwxrwxrwt 2 root root   40 ...
drwxr-xr-x 2 root root 4096 ...

        
    

The kernel release can include gvisor.

gVisor supplies an advertised kernel identity rather than reporting the real kernel version of the node. The Debian release identifies the operating system environment of the container.

Retrieve CPU and memory information within the sandbox:

    

        
        
lscpu
head -n 12 /proc/meminfo

    

The CPU shows Neoverse-V2 with 2 cores, confirming this is a Google Axion node. Memory shows 512MB total, matching the 512Mi limit set in the sandbox template.

Write a test file to the writable workspace, then leave the sandbox shell:

    

        
        
printf 'created in my sandbox shell\n' > /workspace/shell-marker.txt
cat /workspace/shell-marker.txt
exit

    

You’ve now returned to your local machine terminal. Exiting the shell doesn’t delete its Pod or claim.

Compare filesystem writes

inspect_filesystem.py attempts to write a file to several paths in the sandbox and reports whether each write succeeded or was denied.

Review the script before running it:

    

        
        
cat inspect_filesystem.py

    

Run the script from your local machine in the same Pod:

    

        
        
python3 claim.py check --record "$LP_WORKDIR/runs/shell/run.json"
kubectl --context "$GKE_CONTEXT" -n "$NAMESPACE" exec -i "$POD_NAME" -c runtime -- \
  python3 - < inspect_filesystem.py | tee "$LP_WORKDIR/output/filesystem-probes.txt"

    

The output is similar to:

    

        
        /workspace: write/read/remove succeeded
/tmp: write/read/remove succeeded
/etc: denied (errno 13: Permission denied)
/usr/local: denied (errno 13: Permission denied)

        
    

Denied-write errno values and messages vary.

The output shows which paths are writable and which are blocked. /workspace and /tmp succeed because they’re writable volumes in the template. /etc and /usr/local are blocked because the root filesystem is read-only and the process runs as a non-root user.

Verify sandbox configuration

Reconnect to confirm that the test file is still there:

    

        
        
python3 claim.py check --record "$LP_WORKDIR/runs/shell/run.json"
kubectl --context "$GKE_CONTEXT" -n "$NAMESPACE" exec -it "$POD_NAME" -c runtime -- /bin/sh

    

Inside the sandbox, read and remove the test file. Check for the default service-account token:

    

        
        
cat /workspace/shell-marker.txt
rm /workspace/shell-marker.txt
if test -e /var/run/secrets/kubernetes.io/serviceaccount/token; then
  echo 'Unexpected: default service-account token exists'
else
  echo 'Default service-account token is absent'
fi
exit

    

The token should be absent. If it exists, stop and inspect the Pod configuration before continuing.

Save the Pod configuration and check the resource limits:

    

        
        
kubectl --context "$GKE_CONTEXT" -n "$NAMESPACE" get pod "$POD_NAME" -o yaml \
  > "$LP_WORKDIR/output/interactive-pod.yaml"
kubectl --context "$GKE_CONTEXT" -n "$NAMESPACE" get pod "$POD_NAME" \
  -o jsonpath='{.spec.runtimeClassName}{"\n"}{.spec.containers[0].resources.limits}{"\n"}'

    

Confirm RuntimeClass gvisor and limits 500m CPU and 512Mi memory.

Release the claim for interactive inspection

Remove the claim when you’re done:

    

        
        
python3 claim.py delete --record "$LP_WORKDIR/runs/shell/run.json"

    

Keep the cluster and warm pool running.

What you’ve accomplished and what’s next

You’ve inspected the environment interactively and verified permitted and denied writes. You’ve also confirmed that the sandbox runs as a non-root user with the expected resource limits.

Next, you’ll connect the Antigravity CLI to the sandbox and run agent-generated Python remotely.

Back
Next