I would like to execute a command in a container (let it be ls) then read the exit code with echo $?
kubectl exec -ti mypod -- bash -c "ls; echo $?" does not work because it returns the exit code of my current shell not the one of the container.
So I tried to use eval on a env varible I defined in my manifest :
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- container2
image: varunuppal/nonrootsudo
env:
- name: resultCmd
value: 'echo $?'
then kubectl exec -ti mypod -- bash -c "ls;eval $resultCmd" but the eval command does not return anything.
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
Note that I can run these two commands within the container
kubectl exec -ti mypod bash
#ls;eval $resultCmd
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
**0**
How can I make it work?
Thanks in advance,
This is happening because you use double quotes instead of single ones.
Single quotes won't substitute anything, but double quotes will.
From the bash documentation:
3.1.2.2 Single
Quotes
Enclosing characters in single quotes (') preserves the literal
value of each character within the quotes. A single quote may not
occur between single quotes, even when preceded by a backslash.
To summarize, this is how your command should look like:
kubectl exec -ti firstpod -- bash -c 'ls; echo $?'
Using the POSIX shell eval command is wrong 99.999% of the time. Even if you ignore the presence of Kubernetes in this question. The problem in your question is that your kubectl command is expanding the definition of $resultCmd in the shell you ran the kubectl command. Specifically due to your use of double-quotes. That interactive shell has no knowledge of the definition of $resultCmd in your "manifest" file. So that shell replaces $resultCmd with nothing.
Thanks Kurtis Rader and Thomas for your answers.
It also works when I precede the $? with a backslash :
kubectl exec -ti firstpod -- bash -c "ls; echo \$?"
Related
I am using K8S
I want to calculate a string that that is a result of kubectl exec -it ... -c
after the -c option there is a string.
How can I pass a string with double quotes inside.
The following example doesn't work properly.
x="$(kubectl exec -it mysql-pod -- /bin/sh -c \"mysql -uroot -p12345
-e 'show databases'\" 2>/dev/null)"
echo $x
Thanks.
when only a command needs to be executed on a pod , -it option is not required as it stands for attaching an interactive teminal
when mysql is itself an executable command , no need to use /bin/sh -c
no need to encapsulate whole command in " "
So try following
x=$(kubectl exec mysql-pod -- mysql -uroot -p12345 -e 'show databases ;' 2>/dev/null)
echo $x
I found that creating a yaml object description using --dry-run=client and providing --command only works when the provided arguments are in a very specific order.
This works:
k run nginx --image=nginx --restart=Never --dry-run=client -o yaml --command -- env > nginx.yaml
This does NOT:
k run nginx --image=nginx --restart=Never --command -- env --dry-run=client -o yaml > nginx.yaml
I feel a bit confused because the version that does not work looks a lot more intuitive to me then the one that does work. Ideally both should work in my opinion. Is this intended behavior? I can't find any documentation about it.
Everything after -- is a positional argument (until the > which is a shell metachar), not an option.
Ideally both should work in my opinion.
Unfortunately, the commands you presented are not the same. They will never work the same either. This is correct behaviour. Double dash (--) is of special importance here:
a double dash (--) is used in most Bash built-in commands and many other commands to signify the end of command options, after which only positional arguments are accepted.
So you can't freely swap "parameters" places. Only these options can be freely set
--image=nginx --restart=Never --dry-run=client -o yaml --command
Then you have -- env (double dash, space, and another command). After -- (double dash and space) only positional arguments are accepted.
Additionally, > is shell meta-character to set redirection.
I want to execute set in a pod, to analyze the environment variables:
kubectl exec my-pod -- set
But I get this error:
OCI runtime exec failed: exec failed: container_linux.go:370: starting container process caused: exec: "set": executable file not found in $PATH: unknown
I think, this is a special case, because there's no executable set like there's for example an execute ls.
Remarks
When I open a shell in the pod, it's possible to call set there.
When I call kubectl exec with other commands, for example ls, I get no error.
There are some other questions regarding kubectl exec. But these do not apply to my question, because my problem is about executing set.
set is not a binary but instead a shell command that sets the environment variable.
If you want to set an environment variable before executing a follow up command consider using env
kubectl exec mypod -- env NAME=value123 script01
# or
kubectl exec mypod -- /bin/sh -c 'NAME=value123 script01'
see https://stackoverflow.com/a/55894599/93105 for more information
if you want to set the environment variable for the lifetime of the pod then you probably want to set it in the yaml manifest of the pod itself before creating it.
you can also run set if you first run the shell
kubectl exec mypod -- /bin/sh -c 'set'
I have a docker image with below entrypoint.
ENTRYPOINT ["sh", "-c", "python3 -m myapp ${*}"]
I tried to pass arguments to this image in my kubernetes deployments so that ${*} is replaced with them, but after checking the logs it seem that the first argument was ignored.
I tried to reproduce the result regardless of image, and applied below pod:
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
- name: test
image: postgres # or any image you may like
command: ["bash -c /bin/echo ${*}"]
args:
- sth
- serve
- arg
when I check the logs, I just see serve arg, and sth is completely ignored.
Any idea on what went wrong or what should I do to pass arguments to exec-style entrypoints instead?
First, your command has quoting problems -- you are effectively running bash -c echo.
Second, you need to closely read the documentation for the -c option (emphasis mine):
If the -c option is present, then commands are read from
the first non-option argument command_string. If there
are arguments after the command_string, the first argument
is assigned to $0 and any remaining arguments are assigned
to the positional parameters. The assignment to $0 sets
the name of the shell, which is used in warning and error
messages.
So you want:
command: ["bash", "-c", "echo ${*}", "bash"]
Given your pod definition, this would set $0 to bash, and then $1 to sth, $2 to serve, and $3 to arg.
There are some subtleties around using sh -c here. For the examples you show, it's not necessary. The important things to remember are that the ENTRYPOINT and CMD are combined together into a single command (or, in Kubernetes, command: and args:), and that sh -c generally takes only a single string argument and acts on it.
The examples you show don't use any shell functionality and you can break the commands into their constituent words as YAML list items.
command:
- /bin/echo
- sth
- serve
- arg
For the Dockerfile case, there is a pattern of using ENTRYPOINT to specify a command and CMD for its arguments, which parallels Kubernetes's syntax here. For this to work well, I'd avoid sh -c (including the implicit sh -c from the ENTRYPOINT shell form); just provide the first set of words in JSON-array form.
ENTRYPOINT ["python", "-m", "myapp"]
# don't override command:, the image's ENTRYPOINT is right, but do add
args:
- foo
- bar
- baz
(If your entrypoint setup is complex enough to require shell operators, it's typically easier to write and debug to move it into a dedicated script and make that script be the ENTRYPOINT or CMD, rather than trying to figure out sh -c semantics and YAML quoting.)
Team,
I need to execute a shell script that is within a kubernetes pod. However the call needs to come from outside the pod. Below is the script for your reference:
echo 'Enter Namespace: '; read namespace; echo $namespace;
kubectl exec -it `kubectl get po -n $namespace|grep -i podName|awk '{print $1}'` -n $namespace --- {scriptWhichNeedToExecute.sh}
Can anyone suggest on how to do this?`
There isn't really a good way. A simple option might be cat script.sh | kubectl exec -i -- bash but that can have weird side effects. The more correct solution would be to use a debug container but that feature is still in alpha right now.