Skip to content

Complexities

exec()

The behaviour of kubectl exec is not consistent with that in docker exec. Consider the following command (note: the k8s_sandbox package does not actually use kubectl, but it illustrates the point).

kubectl exec pod   -- bash -c "python server.py &"
docker exec container bash -c "python server.py &"

Kubernetes won't consider the command completed until the Python process exits, whereas Docker will consider the command completed as soon as the bash script exits.

More specifically, Kubernetes will wait for the stdout and stderr file descriptors to be closed (including by any child processes which inherited them).

The kubectl command could be re-written like so to make it behave in the same way as docker exec:

kubectl exec pod -- bash -c "python server.py > /dev/null 2>&1 &"

However, we do not have control over the commands which LLMs choose to run, so the k8s_sandbox package attempts to emulate the Docker behaviour (which seems more intuitive anyway).

See the source code for documentation on how this is achieved.

Why not use tty=True (-t)?

Whilst this would give us the behaviour we want around commands containing a backgrounded task (&), it means that stderr is redirected to stdout. It also changes the line endings of the output from \n to \r\n, which means that the output is not consistent with output from other sandbox environments like Docker.