How do I run a command while starting a Pod in Kubernetes? - kubernetes

I want to execute a command during the creation of the pod.
I see two options available :
kubectl run busybox --image=busybox --restart=Never -- sleep 3600
kubectl run busybox --image=busybox --restart=Never -- /bin/sh -c "sleep 3600"
What is the difference between the above two commands ?

In short no difference in the outcome if you want to run "sleep 3600".
Both perform the same operation.
To understand the behaviour of those options add dry-run option to it
First one passes "sleep" & "3600" as arguments to Entrypoint of busybox image which is "/bin/sh"
kubectl run busybox --image=busybox --restart=Never --dry-run=client -o yaml -- sleep 3600
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: busybox
name: busybox
spec:
containers:
- args:
- sleep
- "3600"
image: busybox
name: busybox
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Never
second one passes "/bin/sh -c" , "sleep" & "3600" as arguments to Entrypoint of busybox image which is "/bin/sh" . So it will open a new shell to run "sleep 3600" inside the container.
kubectl run busybox --image=busybox --restart=Never --dry-run=client -o yaml -- /bin/sh -c "sleep 3600"
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: busybox
name: busybox
spec:
containers:
- args:
- /bin/sh
- -c
- sleep 3600
image: busybox
name: busybox
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Never
status: {}
As mentioned in the beginning it does not make any difference in the outcome of "sleep 3600" But this method is useful when you want to run multiple commands by container for example "sleep 3600" & "echo boo". so the syntax would be
kubectl run busybox --image=busybox --restart=Never -- /bin/sh -c "sleep 3600;echo boo"

Related

Running sh shell in Busybox

Hope all is well. I am stuck with this Pod executing a shell script, using the BusyBox image. The one below works,
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: loop
name: busybox-loop
spec:
containers:
- args:
- /bin/sh
- -c
- |-
for i in 1 2 3 4 5 6 7 8 9 10; \
do echo "Welcome $i times"; done
image: busybox
name: loop
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Never
status: {}
But this one doesn't works as I am using "- >" as the operator,
apiVersion: v1
kind: Pod
metadata:
labels:
run: busybox-loop
name: busybox-loop
spec:
containers:
- image: busybox
name: busybox-loop
args:
- /bin/sh
- -c
- >
- for i in {1..10};
- do
- echo ("Welcome $i times");
- done
restartPolicy: Never
Is it because the for syntax "for i in {1..10};" will not work on sh shell. As we know we don't have any other shells in Busybox or the "- >" operator is incorrect, I don't think so because it works for other shell scripts.
Also when can use "- |" multiline operator(I hope the term is correct) and "- >" operator. I know this syntax below is easy to use, but the problem is when we use double quotes in the script, the escape sequence confuses and never works.
args: ["-c", "while true; do echo hello; sleep 10;done"]
Appreciate your support.
...But this one doesn't works as I am using "- >" as the operator...
You don't need '-' after '>' in this case, try:
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
run: busybox
spec:
containers:
- name: busybox
image: busybox
args:
- ash
- -c
- >
for i in 1 2 3 4 5 6 7 8 9 10;
do
echo "hello";
done
kubectl logs pod busybox will print hello 10 times.
Brace expansion in for loop is not supported by ash shell. One more solution here can be replacing it with seq command and update formatting like this:
spec:
containers:
- image: busybox
name: busybox-loop
args:
- /bin/sh
- -c
- >
for i in `seq 1 10`;
do echo "Welcome $i times";
done
restartPolicy: Never
It doesn't matter in this case which operator to use - - | or - >, both will work fine.
I think you can use this command to create the pod:
$ kubectl run busybox --image=busybox --dry-run=client -o yaml --command -- /bin/sh -c "for i in {1..10}; do echo 'Welcome $i times'; done" | kubectl apply -f -
pod/busybox created
$ kubectl logs busybox
Welcome 10 times
Note that you can take a look into YAML created by the dry run command as well.
apiVersion: v1
kind: Pod
metadata:
labels:
run: busybox
name: busybox
spec:
containers:
- image: busybox
command:
- /bin/sh
- -c
- for i in {1..10}; do echo 'Welcome $i times'; done

how to make curl available in my container in k8s pod?

I'm using busybox image in my pod. I'm trying to curl another pod, but "curl is not found". How to fix it?
apiVersion: v1
kind: Pod
metadata:
labels:
app: front
name: front
spec:
containers:
- image: busybox
name: front
command:
- /bin/sh
- -c
- sleep 1d
this cmd:
k exec -it front -- sh
curl service-anotherpod:80 -> 'curl not found'
Additional to #gohm'c's answer, you could also try uusing Alpine Linux and either make your own image that has curl installed, or use apk add curl in the pod to install it.
Example pod with alpine:
apiVersion: v1
kind: Pod
metadata:
labels:
app: front
name: front
spec:
containers:
- image: alpine
name: front
command:
- /bin/sh
- -c
- sleep 1d
busybox is a single binary program which you can't install additional program to it. You can either use wget or you can use a different variant of busybox like progrium which come with a package manager that allows you to do opkg-install curl.
You could make your own image and deploy it to a pod. Here is an example Dockerfile
FROM alpine:latest
RUN apk update && \
apk upgrade && \
apk add --no-cache \
bind-tools \
curl \
iproute2 \
wget \
&& \
:
ENTRYPOINT [ "/bin/sh", "-c", "--" , "while true; do sleep 30; done;" ]
Which you can then build like this
docker image build -t networkutils:latest .
Run like this
docker container run -rm -d --name networkutils networkutils
And access it's shell to run curl, wget, or whichever commands you have installed like this
docker container exec -it networkutils sh
To run and access it in k3s you can do make a deployment file like this
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: networkutils
namespace: default
labels:
app: networkutils
spec:
replicas: 1
selector:
matchLabels:
app: networkutils
template:
metadata:
labels:
app: networkutils
spec:
containers:
- name: networkutils-container
image: networkutils:latest
imagePullPolicy: Never
Start the pod
kubectl apply -f deployment.yml
And then access the shell
kubectl exec -it networkutils -- /bin/sh

Creating a Docker container that runs forever using bash

I'm trying to create a Pod with a container in it for testing purposes that runs forever using the K8s API. I have the following yaml spec for the Pod which would run a container and exit straight away:
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
containers:
- name: ubuntu
image: ubuntu:trusty
command: ["echo"]
args: ["Hello World"]
I can't find any documentation around the command: tag but ideally I'd like to put a while loop in there somewhere printing out numbers forever.
If you want to keep printing Hello every few seconds you can use:
apiVersion: v1
kind: Pod
metadata:
name: busybox2
labels:
app: busybox
spec:
containers:
- name: busybox
image: busybox
ports:
- containerPort: 80
command: ["/bin/sh", "-c", "while :; do echo 'Hello'; sleep 5 ; done"]
You can see the output using kubectl logs <pod-name>
Other option to keep a container running without printing anything is to use sleep command on its own, for example:
command: ["/bin/sh", "-ec", "sleep 10000"]

Serialize creation of Pods in a deployment manifest using Helm charts

So I have a helm chart that deploys a pod, so the next task is to create another pod once the first pod is running.
So I created a simple pod.yaml in chart/templates which creates a simple pod-b, so next step to only create pod-b after pod-a is running.
So was only at helm hooks but don't think they care about pod status.
Another idea is to use Init container like below but not sure how to write command to lookup a pod is running?
spec:
containers:
- name: myapp-container
image: busybox
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
Another idea is a simple script to check pod status something like:
y=`kubectl get po -l app=am -o 'jsonpath={.items[0].status.phase}'`
while [ $i -le 5 ]
do
if [[ "$y" == "Running" ]]; then
break
fi
sleep 5
done
Any advice would be great.
If you want your post-install/post-upgrade chart hooks to work, you should add readiness probes to your first pod and use --wait flag.
helm upgrade --install -n test --wait mychart .
pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-exec
labels:
test: readiness
spec:
containers:
- name: readiness
image: k8s.gcr.io/busybox
args:
- /bin/sh
- -c
- sleep 30; touch /tmp/healthy; sleep 600
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 10
hook.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: "post-deploy"
annotations:
"helm.sh/hook": post-upgrade,post-install
"helm.sh/hook-delete-policy": before-hook-creation
spec:
backoffLimit: 1
template:
metadata:
name: "post-deploy"
spec:
restartPolicy: Never
containers:
- name: post-deploy
image: k8s.gcr.io/busybox
args:
- /bin/sh
- -c
- echo "executed only after previous pod is ready"

Kubernetes | Any hooks available for Pod restarts?

Are there any hooks available for Pod lifecycle events? Specifically, I want to run a command to upload logs on pod restart.
Edit: PreStop hook doesn't work for container restart - please see rest of answer below
As standing in documentation there are PreStop and PostStart events and you can attach to them.
Example from docs:
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]
Edit:
So I checked with following POC if that preStop hook is executed on container crash and conclusion is: NOT
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
volumeMounts:
- mountPath: /data
name: test-volume
image: nginx
command: ["/bin/sh"]
args: ["-c", "sleep 5; exit 1"]
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /data/postStart"]
preStop:
exec:
command: ["/bin/sh","-c","echo preStop handler! > /data/preStop"]
volumes:
- name: test-volume
hostPath:
path: /data
type: Directory
As solution for you I would recommend to override command section for you container this way:
command: ["/bin/sh"]
args: ["-c", "your-application-executable; your-logs-upload"]
so your-logs-upload executable will be executed after your-application-executable crash/end