Working with Minimal/Distroless Containers¶
Many modern container images are built as "distroless" or minimal, meaning they contain only your application and its runtime dependencies. They do not contain a package manager, utilities like curl or cat, or even a shell (e.g. /bin/sh or /bin/bash).
While excellent for security and size, minimal containers change how you operate your app.
When ops shell Fails¶
If you run:
And get an error like:
OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH
This means your image is distroless and has no shell.
What doesn't work out-of-the-box in distroless:
helm-me ops shell(requires/bin/sh)helm-me ops cp(requirestarexecutable in the pod)- General interactive exploration
What You Can Still Do¶
Fortunately, many operations do not require a shell inside the container:
1. Read Logs¶
Logs do not require a shell. helm-me ops logs reads directly from the container runtime stdout/stderr.
2. Execute Known Binaries¶
If you know the exact path of a binary that is inside the container, you can run it directly:
3. Port Forwarding¶
Port forwarding operates at the network level and does not require a shell. You can still access internal endpoints, metrics, or debug servers (like pprof or Werkzeug debugger).
Workarounds¶
If you absolutely must explore a distroless container natively or copy files, you can use Kubernetes ephemeral debug containers.
Instead of helm-me ops shell, use kubectl debug:
# Get the pod name
helm-me ops pods
# Attach an Alpine debug container to the running pod
kubectl debug -it pod/hello-app-backend-xyz --image=alpine --target=backend -- sh
This injects a shell (alpine) into the same namespace as your running container, allowing you to inspect its filesystem (usually mounted at /proc/1/root) and network.