Why are shell builtins not found when using Kubectl exec - bash

I am making a bash script to copy files from a Kubernetes pod running Debian. When I include the following line:
kubectl --namespace "$namesp" exec "$pod" -c "$container" -- cd /var
it errors out:
OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "cd": executable file not found in $PATH: unknown
command terminated with exit code 126
I also tried
kubectl --namespace "$namesp" exec "$pod" -c "$container" -- builtin
kubectl --namespace "$namesp" exec "$pod" -c "$container" -it -- cd /var
which gave the same result.
I was able to resolve the issue by changing the command to:
kubectl --namespace "$namesp" exec "$pod" -c "$container" -- /bin/bash -c "builtin"
Would love to understand why the first command(s) don't work and the latter one does. I would have thought that builtin commands are the one group of commands that would always be found, in contrast to commands that rely on the PATH environment variable.

kubectl exec is used to execute an executable in a running container. The command has to be built into the container.
Neither builtin nor cd are valid executables in your container. Only /bin/bash is.
To execute a builtin shell command, you have to execute the shell and call it as the command argument like in your third example.

Related

run a shell script inside the pod

I am trying to write a single line command to run a shell script which is inside the pod
getting a shell for a running container:
kubectl exec -it test-pod -c test-container -- /bin/bash
directory in the container:
cd test/bin
script inside the bin:
./backup.sh
how do I write all this in a single command?
Try:
kubectl exec -it test-pod -c test-container -- sh /full/path/to/the/backup.sh
Try:
kubectl exec -it test-pod -c test-container -- /bin/bash -c "/path/to/backup-script.sh"

How to execute a shell script as input on an interactive bash pod in Kubernetes?

I have a shell script my-script.sh like:
#!/bin/bash
while true; do
echo '1'
done
I can deploy a bash pod in Kubernetes like:
kubectl run my-shell --rm -it --image bash -- bash
Now, I want to execute the script on bash. How can I pass my-script.sh as input to bash? Something like
kubectl run my-shell --rm -it --image bash -- /bin/bash -c < my-script.sh
Just drop the -t to kubectl run (because you're reading from stdin, not a terminal) and the -c from bash (because you're passing the script on stdin, not as an argument):
$ kubectl run my-shell --rm -i --image docker.io/bash -- bash < my-script.sh
If you don't see a command prompt, try pressing enter.
1
1
1
1
...

Exec into kubernetes pod in a particular directory

How do I make this work?
[alan#stormfather-0be642-default-1 ~]$ kubectl exec -it my-pod-0 -- bash -c "/bin/bash && cd /tmp"
[root#my-pod-0 /]# pwd
/
Change directory first and then sh into it.
kubectl exec -it my-pod-0 -- bash -c "cd /tmp && /bin/bash"
Mohsin Amjad's answer is both simple and correct, if you are getting the
..."bash": executable file not found in $PATH...
error, this just means the container inside the pod does not have bash installed, instead try sh or other shells. I.e. something like:
kubectl exec -it my-pod-0 -- sh -c "cd /tmp && echo $0 $SHELL"

Docker exec quoting variables

I'd like to know if there's a way to do this
Let's say the dockerfile contains this line, that specifies path of an executable
ENV CLI /usr/local/bin/myprogram
I'd like to be able to call this program using ENV variable name through exec command.
For example
docker exec -it <my container> 'echo something-${CLI}
Expecting
something-/usr/local/bin/myprogram
However that returns:
OCI runtime exec failed: exec failed: container_linux.go:348: starting container process caused "exec: \"${CLI} do something\": executable file not found in $PATH": unknown
Ok, I found a way to do it, all you need to do is evaluate command with bash
docker exec -it <container id> bash -c 'echo something-${CLI}'
returns something-/usr/local/bin/myprogram
If the CLI environment variable is not already set in the container, you can also pass it in such as:
docker exec -it -e CLI=/usr/local/bin/myprogram <container id> bash -c 'echo something-${CLI}'
See the help file:
docker exec --help
Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
Run a command in a running container
Options:
-d, --detach Detached mode: run command in the background
-e, --env list Set environment variables
....
In it's original revision docker exec -it <my container> '${CLI} do something' with the expectation that ${CLI} will be substituted with /usr/local/bin/myprogram (as the exec COMMAND) and everything after passed as ARG's to /usr/local/bin/myprogram will not work, this is clearly documented: https://docs.docker.com/engine/reference/commandline/exec/
COMMAND should be an executable, a chained or a quoted command will not work. Example:
docker exec -ti my_container "echo a && echo b" will not work, but
docker exec -ti my_container sh -c "echo a && echo b" will.
Following the documentation, this will work as expected: docker exec -ti my_container sh -c "${CLI} foo", ${CLI} will be be executed after variable expansion and the argument(s) passed to the shell script set in ${CLI} (e.g. sh -c /usr/local/bin/myprogram foo).
Alternatively you could set the ENTRYPOINT to your script and pass in arguments with CMD or at the command line with docker run for example:
Given the below directory structure:
.
├── Dockerfile
└── example.sh
The Dockerfile contents:
FROM ubuntu:18.04
COPY example.sh /bin
RUN chmod u+x /bin/example.sh
ENTRYPOINT ["/bin/example.sh"]
CMD ["bla"]
And the example.sh script contents:
#!/bin/bash
echo $1
The CMD specified in the Dockerfile after the ENTRYPOINT will be the default argument for your script and you can override the default argument on the command line (assuming that the image is built and tagged as example:0.1):
user#host> docker run --rm example:0.1
bla
user#host> docker run --rm example:0.1 "arbitrary text"
arbitrary text
Note: this is my go to article for differences between ENTRYPOINT and CMD in Dockerfile's: https://medium.freecodecamp.org/docker-entrypoint-cmd-dockerfile-best-practices-abc591c30e21

Source script on interactive shell inside Docker container

I want to open a interactive shell which sources a script to use the bitbake environment on a repository that I bind mount:
docker run --rm -it \
--mount type=bind,source=$(MY_PATH),destination=/mnt/bb_repoistory \
my_image /bin/bash -c "cd /mnt/bb_repoistory/oe-core && source build/conf/set_bb_env.sh"
The problem is that the -it argument does not seem to have any effect, since the shell exits right after executing cd /mnt/bb_repoistory/oe-core && source build/conf/set_bb_env.sh
I also tried this:
docker run --rm -it \
--mount type=bind,source=$(MY_PATH),destination=/mnt/bb_repoistory \
my_image /bin/bash -c "cd /mnt/bb_repoistory/oe-core && source build/conf/set_bb_env.sh && bash"
Which spawns an interactive shell, but none of the macros defined in set_bb_env.sh
Would there be a way to provide a tty with the script properly sourcered ?
The -it flag is conflicting with the command to run in that you're telling docker to create the pseudo-terminal (ptty), and then running a command in that terminal (bash -c ...). When that command finishes, then the run is done.
What some people have done to work around this is to only have export variables in their sourced environment, and the last command would be exec bash. But if you need aliases or other items that aren't inherited like that, then your options are a bit more limited.
Instead of running the source in a parent shell, you could run it in the target shell. If you modified your .bash_profile to include the following line:
[ -n "$DOCKER_LOAD_EXTRA" -a -r "$DOCKER_LOAD_EXTRA" ] && source "$DOCKER_LOAD_EXTRA”
and then had your command be:
... /bin/bash -c "cd /mnt/bb_repository/oe-core && DOCKER_LOAD_EXTRA=build/conf/set_bb_env.sh exec bash"
that may work. This tells your .bash_profile to load this file when the env variable is already set, but not otherwise. (There can also be the -e flag on the docker command line, but I think that sets it globally for the entire container, which is probably not what you want.)

Resources