Kubernetes CronJob startup prob - kubernetes

I'm starting with Kubernetes and I implemented a CronJob that runs a Java jar.
It works fine but what I have observed is that if for some reason (for example, a wrong secret key) the container does not start, the pod will sit there indefinitely with error status : CreateContainerConfigError.
Is there a way to automatically kill the pod when such situation occurs ?
I tried with startup probe as indicated in code below but the probe did not even run.
apiVersion: batch/v1
kind: CronJob
metadata:
name: appName
namespace: appNamespace
labels:
app: appName
release: production
tiers: backend
spec:
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
volumes:
- name: tmp-pod
emptyDir: {}
containers:
- name: appName
image: docker-image
command: ["/bin/bash", "-c"]
args:
- |
touch /tmp/pod/app-started;
java -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/urandom -jar /app.jar;
volumeMounts:
- mountPath: /tmp/pod
name: tmp-pod
env:
- name: env_var
value: value
# if app is not started within 5m (30 * 10 = 300s), container will be killed.
startupProbe:
exec:
command:
- cat
- /tmp/pod/app-started
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 30
resources:
requests:
memory: "2200Mi"
cpu: "750m"
limits:
memory: "2200Mi"
restartPolicy: OnFailure
schedule: "0 12 * * *"
concurrencyPolicy: Forbid
Does CronJob not support probes ?
Or I'm doing something wrong ?
Would there be another way of killing container that is not able to start after some time ?

I had the same issue, kubernetes v1.23.14
It seems that the kubernetes has a bug with cronjobs probs
Events:
Normal Started 3m38s kubelet Started container k8s-costs
Warning Unhealthy 3m38s kubelet Startup probe failed: cat: /var/run/secrets/vault-envs: No such file or directory
Normal Killing 3m37s kubelet Stopping container k8s-costs
kubelet said "Stopping container" but it still working
So as result I see that pod is Successed and everything fine, no alerts.
But really job execution was failed and already we in a fire

You can use a liveness probe to automatically kill a pod if the container inside it fails to start. A liveness probe continuously checks if the container is running, and if it detects that the container has failed, it restarts the container.
Here is an example of how to add a liveness probe to your pod definition:
apiVersion: batch/v1
kind: CronJob
metadata:
name: appName
namespace: appNamespace
labels:
app: appName
release: production
tiers: backend
spec:
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
volumes:
- name: tmp-pod
emptyDir: {}
containers:
- name: appName
image: docker-image
command: ["/bin/bash", "-c"]
args:
- |
touch /tmp/pod/app-started;
java -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/urandom -jar /app.jar;
volumeMounts:
- mountPath: /tmp/pod
name: tmp-pod
env:
- name: env_var
value: value
livenessProbe:
exec:
command:
- cat
- /tmp/pod/app-started
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 30
resources:
requests:
memory: "2200Mi"
cpu: "750m"
limits:
memory: "2200Mi"
restartPolicy: OnFailure
schedule: "0 12 * * *"
concurrencyPolicy: Forbid
In the above example, the liveness probe exec command checks for the presence of the file /tmp/pod/app-started. If the file does not exist after the initial delay of 5 seconds, the probe will check every 10 seconds until the failure threshold of 30 is reached. At that point, the container will be killed and restarted.

Related

Kubernetes livenessProbe some container stops with failure and others in success. What is the cause?

Deep dive to this question. I have a scheduled cron job and a never ending container in the same pod. To end the never ending container when the cron job has done it's work I'm using a liveness probe.
apiVersion: batch/v1
kind: CronJob
metadata:
name: pod-failed
spec:
schedule: "*/10 * * * *"
concurrencyPolicy: Replace
jobTemplate:
spec:
ttlSecondsAfterFinished: 300
activeDeadlineSeconds: 300
backoffLimit: 4
template:
spec:
containers:
- name: docker-http-server
image: katacoda/docker-http-server:latest
ports:
- containerPort: 80
volumeMounts:
- mountPath: /cache
name: cache-volume
volumeMounts:
- mountPath: /cache
name: cache-volume
livenessProbe:
exec:
command:
- sh
- -c
- if test -f "/cache/stop"; then exit 1; fi;
initialDelaySeconds: 5
periodSeconds: 5
- name: busy
image: busybox
imagePullPolicy: IfNotPresent
command:
- sh
- -c
args:
- echo start > /cache/start; sleep 15; echo stop > /cache/stop;
volumeMounts:
- mountPath: /cache
name: cache-volume
restartPolicy: Never
volumes:
- name: cache-volume
emptyDir:
sizeLimit: 10Mi
As you see the cron job will write the /cache/stop file and the never ending container is stopped. The problem is that with some images the never ending container stops in failure.
Is there a way to stop every container in success?
Name: pod-failed-27827190
Namespace: default
Selector: controller-uid=608efa7c-53cf-4978-9136-9fec772c1c6d
Labels: controller-uid=608efa7c-53cf-4978-9136-9fec772c1c6d
job-name=pod-failed-27827190
Annotations: batch.kubernetes.io/job-tracking:
Controlled By: CronJob/pod-failed
Parallelism: 1
Completions: 1
Completion Mode: NonIndexed
Start Time: Mon, 28 Nov 2022 11:30:00 +0100
Active Deadline Seconds: 300s
Pods Statuses: 0 Active (0 Ready) / 0 Succeeded / 5 Failed
Pod Template:
Labels: controller-uid=608efa7c-53cf-4978-9136-9fec772c1c6d
job-name=pod-failed-27827190
Containers:
docker-http-server:
Image: katacoda/docker-http-server:latest
Port: 80/TCP
Host Port: 0/TCP
Liveness: exec [sh -c if test -f "/cache/stop"; then exit 1; fi;] delay=5s timeout=1s period=5s #success=1 #failure=3
Environment: <none>
Mounts:
/cache from cache-volume (rw)
busy:
Image: busybox
Port: <none>
Host Port: <none>
Command:
sh
-c
Args:
echo start > /cache/start; sleep 15; echo stop > /cache/stop;
Environment: <none>
Mounts:
/cache from cache-volume (rw)
Volumes:
cache-volume:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium:
SizeLimit: 10Mi
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 2m5s job-controller Created pod: pod-failed-27827190-8tqxk
Normal SuccessfulCreate 102s job-controller Created pod: pod-failed-27827190-4gj2s
Normal SuccessfulCreate 79s job-controller Created pod: pod-failed-27827190-5wgfg
Normal SuccessfulCreate 56s job-controller Created pod: pod-failed-27827190-lzv8k
Normal SuccessfulCreate 33s job-controller Created pod: pod-failed-27827190-fr8v5
Warning BackoffLimitExceeded 9s job-controller Job has reached the specified backoff limit
As you can see the image: katacoda/docker-http-server:latest is failing with the liveness probe. This doesn't happens with ngix for example.
apiVersion: batch/v1
kind: CronJob
metadata:
name: pod-failed
spec:
schedule: "*/10 * * * *"
concurrencyPolicy: Replace
jobTemplate:
spec:
ttlSecondsAfterFinished: 300
activeDeadlineSeconds: 300
backoffLimit: 4
template:
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /cache
name: cache-volume
volumeMounts:
- mountPath: /cache
name: cache-volume
livenessProbe:
exec:
command:
- sh
- -c
- if test -f "/cache/stop"; then exit 1; fi;
initialDelaySeconds: 5
periodSeconds: 5
- name: busy
image: busybox
imagePullPolicy: IfNotPresent
command:
- sh
- -c
args:
- echo start > /cache/start; sleep 15; echo stop > /cache/stop;
volumeMounts:
- mountPath: /cache
name: cache-volume
restartPolicy: Never
volumes:
- name: cache-volume
emptyDir:
sizeLimit: 10Mi
Of course the never ending image that I'm pulling is ending in failure and I've no control over that image.
Is there a way to force success status of the job/pod?
It depends on the exit code of the container's main process. Every container receives a term signal when kubernetes wants to stop it to give it the chance to end gracefully. This also applies when the reason is a failed liveness probe. I guess nginx exits with exit code 0 while your katacode http server returns with a code different to 0. Looking at the docs of the golang ListenAndServe method it clearly states that it ends with a non-nil error: https://pkg.go.dev/net/http#Server.ListenAndServe
You could override the container's default command with a bash script that starts the application and then waits until the stop file is written:
containers:
- name: docker-http-server
image: katacoda/docker-http-server:latest
command:
- "sh"
- "-c"
- "/app & while true; do if [ -f /cache/stop ]; then exit 0; fi; sleep 1; done;"
Here, "/app" is the start command of the katacode http server container.

Running mongodb stateful set on Kubernetes with istio

I am trying to setup mongodb on kubernetes with istio. My statefulset is as follows:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: treeservice
namespace: staging
spec:
serviceName: tree-service-service
replicas: 1
selector:
matchLabels:
app: treeservice
template:
metadata:
labels:
app: treeservice
spec:
containers:
- name: mongodb-cache
image: mongo:latest
imagePullPolicy: Always
ports:
- containerPort: 30010
volumeMounts:
- name: mongodb-cache-data
mountPath: /data/db
resources:
requests:
memory: "4Gi" # 4 GB
cpu: "1000m" # 1 CPUs
limits:
memory: "4Gi" # 4 GB
cpu: "1000" # 1 CPUs
readinessProbe:
exec:
command:
- mongo
- --eval "db.stats()" --port 30010
initialDelaySeconds: 60 #wait this period after staring fist time
periodSeconds: 30 # polling interval every 5 minutes
timeoutSeconds: 60
livenessProbe:
exec:
command:
- mongo
- --eval "db.stats()" --port 30010
initialDelaySeconds: 60 #wait this period after staring fist time
periodSeconds: 30 # polling interval every 5 minutes
timeoutSeconds: 60
command: ["/bin/bash"]
args: ["-c","mongod --port 30010 --replSet test"] #bind to localhost
volumeClaimTemplates:
- metadata:
name: mongodb-cache-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: fast
resources:
requests:
storage: 300Gi
however, the pod is not created and I see the following error:
kubectl describe statefulset treeservice -n staging
Warning FailedCreate 1m (x159 over 1h) statefulset-controller create Pod treeservice-0 in StatefulSet treeservice failed error: Pod "treeservice-0" is invalid: spec.containers[1].env[7].name: Invalid value: "ISTIO_META_statefulset.kubernetes.io/pod-name": a valid environment variable name must consist of alphabetic characters, digits, '_', '-', or '.', and must not start with a digit (e.g. 'my.env-name', or 'MY_ENV.NAME', or 'MyEnvName1', regex used for validation is '[-._a-zA-Z][-._a-zA-Z0-9]*')
I assum treeservice is a valid pod name. Am I missing something?
I guess it's due to this issue https://github.com/istio/istio/issues/9571 which is still open
I made it work temporarily using the following:
annotations:
sidecar.istio.io/inject: "false"

Intermittent failure creating container on Kubernetes - failing to mount default token

For the past couple of days we have been experiencing an intermittent deployment failure when deploying (via Helm) to Kubernetes v1.11.2.
When it fails, kubectl describe <deployment> usually reports that the container failed to create:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 1s default-scheduler Successfully assigned default/pod-fc5c8d4b8-99npr to fh1-node04
Normal Pulling 0s kubelet, fh1-node04 pulling image "docker-registry.internal/pod:0e5a0cb1c0e32b6d0e603333ebb81ade3427ccdd"
Error from server (BadRequest): container "pod" in pod "pod-fc5c8d4b8-99npr" is waiting to start: ContainerCreating
and the only issue we can find in the kubelet logs is:
58468 kubelet_pods.go:146] Mount cannot be satisfied for container "pod", because the volume is missing or the volume mounter is nil: {Name:default-token-q8k7w ReadOnly:true MountPath:/var/run/secrets/kubernetes.io/serviceaccount SubPath: MountPropagation:<nil>}
58468 kuberuntime_manager.go:733] container start failed: CreateContainerConfigError: cannot find volume "default-token-q8k7w" to mount container start failed: CreateContainerConfigError: cannot find volume "default-token-q8k7w" to mount into container "pod"
It's intermittent which means it fails around once in every 20 or so deployments. Re-running the deployment works as expected.
The cluster and node health all look fine at the time of the deployment, so we are at a loss as to where to go from here. Looking for advice on where to start next on diagnosing the issue.
EDIT: As requested, the deployment file is generated via a Helm template and the output is shown below. For further information, the same Helm template is used for a lot of our services, but only this particular service has this intermittent issue:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: pod
labels:
app: pod
chart: pod-0.1.0
release: pod
heritage: Tiller
environment: integration
annotations:
kubernetes.io/change-cause: https://github.com/path_to_release
spec:
replicas: 2
revisionHistoryLimit: 3
selector:
matchLabels:
app: pod
release: pod
environment: integration
strategy:
rollingUpdate:
maxSurge: 0
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: pod
release: pod
environment: integration
spec:
containers:
- name: pod
image: "docker-registry.internal/pod:0e5a0cb1c0e32b6d0e603333ebb81ade3427ccdd"
env:
- name: VAULT_USERNAME
valueFrom:
secretKeyRef:
name: "pod-integration"
key: username
- name: VAULT_PASSWORD
valueFrom:
secretKeyRef:
name: "pod-integration"
key: password
imagePullPolicy: IfNotPresent
command: ['mix', 'phx.server']
ports:
- name: http
containerPort: 80
protocol: TCP
envFrom:
- configMapRef:
name: pod
livenessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 10
readinessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 10
resources:
limits:
cpu: 750m
memory: 200Mi
requests:
cpu: 500m
memory: 150Mi

Failed to attach volume ... already being used by

I am running Kubernetes in a GKE cluster using version 1.6.6 and another cluster with 1.6.4. Both are experiencing issues with failing over GCE compute disks.
I have been simulating failures using kill 1 inside the container or killing the GCE node directly. Sometimes I get lucky and the pod will get created on the same node again. But most of the time this isn't the case.
Looking at the event log it shows the error trying to mount 3 times and it fails to do anything more. Without human intervention it never corrects it self. I am forced to kill the pod multiple times until it works. During maintenances this is a giant pain.
How do I get Kubernetes to fail over with volumes properly ? Is there a way to tell the deployment to try a new node on failure ? Is there a way to remove the 3 retry limit ?
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: dev-postgres
namespace: jolene
spec:
revisionHistoryLimit: 0
template:
metadata:
labels:
app: dev-postgres
namespace: jolene
spec:
containers:
- image: postgres:9.6-alpine
imagePullPolicy: IfNotPresent
name: dev-postgres
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgres-data
env:
[ ** Removed, irrelevant environment variables ** ]
ports:
- containerPort: 5432
livenessProbe:
exec:
command:
- sh
- -c
- exec pg_isready
initialDelaySeconds: 30
timeoutSeconds: 5
failureThreshold: 6
readinessProbe:
exec:
command:
- sh
- -c
- exec pg_isready --host $POD_IP
initialDelaySeconds: 5
timeoutSeconds: 3
periodSeconds: 5
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: dev-jolene-postgres
I have tried this with and without PersistentVolume / PersistentVolumeClaim.
apiVersion: "v1"
kind: "PersistentVolume"
metadata:
name: dev-jolene-postgres
spec:
capacity:
storage: "1Gi"
accessModes:
- "ReadWriteOnce"
claimRef:
namespace: jolene
name: dev-jolene-postgres
gcePersistentDisk:
fsType: "ext4"
pdName: "dev-jolene-postgres"
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dev-jolene-postgres
namespace: jolene
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
By default, every node is schedulable, so there is no need to explicitly mention it in deployment. and feature which can mention retry limits is still in progress, which can be tracked here, https://github.com/kubernetes/kubernetes/issues/16652

How to run command after initialization

I would like to run specific command after initialization of deployment is successful.
This is my yaml file:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: auth
spec:
replicas: 1
template:
metadata:
labels:
app: auth
spec:
containers:
- name: auth
image: {{my-service-image}}
env:
- name: NODE_ENV
value: "docker-dev"
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 3000
However, I would like to run command for db migration after (not before) deployment is successfully initialized and pods are running.
I can do it manually for every pod (with kubectl exec), but this is not very scalable.
I resolved it using lifecycles:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: auth
spec:
replicas: 1
template:
metadata:
labels:
app: auth
spec:
containers:
- name: auth
image: {{my-service-image}}
env:
- name: NODE_ENV
value: "docker-dev"
resources:
requests:
cpu: 100m
memory: 100Mi
ports:
- containerPort: 3000
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", {{cmd}}]
You can use Helm to deploy a set of Kubernetes resources. And then, use a Helm hook, e.g. post-install or post-upgrade, to run a Job in a separate docker container. Set your Job to invoke db migration. A Job will run >=1 Pods to completion, so it fits here quite well.
I chose to use a readinessProbe
My application requires configuration after the process has completely started.
The postStart command was running before the app was ready.
readinessProbe:
exec:
command: [healthcheck]
initialDelaySeconds: 30
periodSeconds: 2
timeoutSeconds: 1
successThreshold: 3
failureThreshold: 10