GKE readiness/liveness randomly failed - kubernetes

I am facing a very weird problem.
I have a deployment with nginx container(six pods) work on GKE, I use Liveness/Readiness Probe on nginx container, all the pods are working fine.
One day, all pods were dead because of readiness/liveness failed. And I use kubectl describe pod that pop up ...
Liveness probe failed: Get http://10.28.6.19:80/healthz: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
Readiness probe failed: Get http://10.28.6.19:80/healthz: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
I try to delete pods to let six pods reborn, the pod is very normal.
Some posts said: this is pods hit the limit of resource, I swear my pod resource usage is very low. And I don't set limit for my pods.
I have encounter this problem third, until now I still don't know the root cuse and any solution of this kind of problem.
Deployment Spec as below, Nginx will direct repose 200 status code according to /healthz, so nginx config have to add a location
readinessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 10
timeoutSeconds: 2
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 10
timeoutSeconds: 2

When your app starts hitting the resource limit, the Kubernetes starts throttling your container. Resulting in probe failure. You should always set the resource request and limit for avoiding such events:
containers:
- name: app
image: images.my-company.example/app:v4
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"

Liveness probe failed: Get http://10.28.6.19:80/healthz: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
Readiness probe failed: Get http://10.28.6.19:80/healthz: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
The error message says that your HTTP request wasn't successful.
Readiness Probe needs to succeed for the pod to be added as an endpoint for the
service exposing it.
kubectl get po -o wide : Run this command to get the pod's cluster IP
kubectl exec -t [another_pod] -- curl -I [pod's cluster IP] : If this command returns a 200 response, the path is configured properly and the readiness probe should pass. If you get anything other than a 200 response, this is why the readiness probe fails and you need to check your image.

You can try out any of these solutions.
1. Increase the timeoutSeconds to atleast 10 seconds. During peak load time nginx don't provide the response in 2 seconds. Also configure successThreshold and failureThreshold values.
2. Replace httpGet to exec method which will call the same endpoint using curl if needed. This resolves my issue.
3. Isolate the nginx containers to separate node pools to ensure no other deployments are creating any kind of resource constraints to nginx pods.

Related

Readiness probe failed: remote error: tls: bad certificate

I get the following error:
Warning Unhealthy 14m (x4 over 15m) kubelet Liveness probe failed: Get "https://10.244.1.13:8443/healthz": remote error: tls: bad certificate
The server is configured with tls support.
In https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ it is written that: If scheme field is set to HTTPS, the kubelet sends an HTTPS request skipping the certificate verification. so it is not clear why we get this error.
What you have mentioned in the description is completely different from the subject.
Please check you have configured only in readiness prob and You need to configure in both readiness and liveness probe.
if you are looking forward to send to the HTTPS request to the service you have to change the scheme.
livenessProbe:
httpGet:
path: /
port: 443
scheme: HTTPS
readinessProbe:
httpGet:
path: /
port: 443
To avoid the error the kubelet should be configured with the ca certificate of the server.

Why is my kubernetes readiness probe for hashicorp vault hitting http when I specify https?

My readiness probe specifies HTTPS and 8200 as the port to check my hashicorp vault pod.
readinessProbe:
httpGet:
scheme: HTTPS
path: '/v1/sys/health?activecode=200'
port: 8200
Once the pod is running kubectl describe pod shows this
Readiness probe failed: Error checking seal status: Error making API request.
URL: GET http://127.0.0.1:8200/v1/sys/seal-status
Code: 400. Raw Message:
Client sent an HTTP request to an HTTPS server.
I have found this similar problem. See the whole answer here.
According to this documentation:
The http/https scheme is controlled by the tlsDisable value.
When set to true, changes URLs from https to http (such as the VAULT_ADDR=http://127.0.0.1:8200 environment variable set on the Vault pods).
To turn it off:
global:
tlsDisable: false
NOTE:
Vault should always be used with TLS in production to provide secure communication between clients and the Vault server. It requires a certificate file and key file on each host where Vault is running.
See also this documentation. One can find there many examples of using readiness and liveness probes, f.e
readinessProbe:
exec:
command:
- /bin/sh
- -ec
- vault status
initialDelaySeconds: 5
periodSeconds: 5

Kubernetes - How to read response body in livenessProbe of a container?

Below is the current configuration for livenessProbe:
livenessProbe:
httpGet:
path: /heartbeat
port: 8000
initialDelaySeconds: 2
timeoutSeconds: 2
periodSeconds: 8
failureThreshold: 2
But response body for URL .well-known/heartbeat shows status: "DOWN" and the http return status as 200
So, Kubelet does not restart the container, due to http response status 200
How to ensure Kubelet reads the response body instead of http return status? using livenessProbe configuration
You can interpret the body in your probe using shell command, example:
livenessProbe:
exec:
command:
- sh
- -c
- curl -s localhost | grep 'status: "UP"'
grep return non-zero if status: "DOWN" which will direct readinessProbe to fail. You can of course adjust the script according to your actual response body.
How to ensure Kubelet reads the response body instead of http return status? using livenessProbe configuration
This is not according to the "contract" provided by Kubernetes. You probably need to implement a custom endpoint that follows the contract for HTTP liveness probes as below.
From Define a HTTP liveness probe
If the handler returns a failure code, the kubelet kills the container and restarts it.
Any code greater than or equal to 200 and less than 400 indicates success. Any other code indicates failure.

How to terminate janusgraph container in case any exception is thrown

I'm using janusgraph docker image - https://hub.docker.com/r/janusgraph/janusgraph
In my kubernetes deployment to initialise the remote graph using groovy script mounted to docker-entrypoint-initdb.d
This works as expected but in case if the remote host is not ready the janusgraph container throws exception and is still in the running mode.
Because of this kubernetes will not attempt to restart the container again. Is there any way so that I can configure this janusgraph container to terminate in case of any exception
As #Gavin has mentioned you can use probes to check if containers are working. Liveness Probes is used to know when containers are failed. If a container is unresponsive - it can restart the container.
Readiness probes inform when the container is available for accepting traffic. The readiness probe is used to control which pods are used as the backends for a service. A pod is considered ready when all of its containers are ready. If a pod is not ready, it is removed from service Endpoints.
Kubernetes supports three mechanisms for implementing liveness and readiness probes:
1) making an HTTP request against a container
This probes have additional fields that can be set on httpGet:
host: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead.
scheme: Scheme to use for connecting to the host (HTTP or HTTPS). Defaults to HTTP.
path: Path to access on the HTTP server. Defaults to /.
httpHeaders: Custom headers to set in the request. HTTP allows repeated headers.
port: Name or number of the port to access on the container. Number must be in the range 1 to 65535.
Read more: http-probes.
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
2) opening a TCP socket against a container
initialDelaySeconds: 15
livenessProbe: ~
periodSeconds: 20
port: 8080
tcpSocket: ~
3) running a command inside a container
livenessProbe:
exec:
command:
- sh
- /tmp/status_check.sh
initialDelaySeconds: 10
If you will get status code different than 0 this will mean that probe failed.
You can also add to probes additional params such as initialDelaySeconds: indicate number of seconds after the container has started before liveness or readiness probes are initiated. See: configuring-probes.
In every case add also restartPolicy: Never
to your pods definition. By default is always.
A readinessProbe could be employed here with a command like janusgraph show-config or something similar which will exit with code -1
spec:
containers:
- name: liveness
image: janusgraph/janusgraph:latest
readinessProbe:
exec:
command:
- janusgraph
- show-config
Kubernetes will terminate the pod if the readinessProbe fails. A livenessProbe could also be used here too, in case this pod needs to be terminated if the remote host ever becomes unavailable.
Consider enabling JanusGraph server metrics, which could then be used with Prometheus for additional monitoring or even with the livenessProbe itself.

How to debug failed requests with client_disconnected_before_any_response

We have an HTTP(s) Load Balancer created by a kubernetes ingress, which points to a backend formed by set of pods running nginx and Ruby on Rails.
Taking a look to the load balancer logs we have detected an increasing number of requests with a response code of 0 and statusDetails = client_disconnected_before_any_response.
We're trying to understand why this his happening, but we haven't found anything relevant. There is nothing in the nginx access or error logs.
This is happening for multiple kind of requests, from GET to POST.
We also suspect that sometimes despite of the request being logged with that error, the requests is actually passed to the backend. For instance we're seeing PG::UniqueViolation errors, due to idential sign up requests being sent twice to the backend in our sign up endpoint.
Any kind of help would be appreciated. Thanks!
 UPDATE 1
As requested here is the yaml file for the ingress resource:
 UPDATE 2
I've created a log-based Stackdriver metric, to count the number of requests that present this behavior. Here is the chart:
The big peaks approximately match the timestamp for these kubernetes events:
Full error: Readiness probe failed: Get http://10.48.1.28:80/health_check: net/http: request canceled (Client.Timeout exceeded while awaiting headers)"
So it seems sometimes the readiness probe for the pods behind the backend fails, but not always.
Here is the definition of the readinessProbe
readinessProbe:
failureThreshold: 3
httpGet:
httpHeaders:
- name: X-Forwarded-Proto
value: https
- name: Host
value: [redacted]
path: /health_check
port: 80
scheme: HTTP
initialDelaySeconds: 1
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 5
A response code of 0 and statusDetails = client_disconnected_before_any_response means the client closed the connection before the Load Balancer being able to provide a response as per this GCP documentation.
Investigating why it did not respond in time, one of the reasons could be the difference between the keepalive timeouts from nginx and the GCP Load Balancer, even if this will most-like provide a backend_connection_closed_before_data_sent_to_client caused by a 502 Bad Gateway race condition.
To make sure the backend responds to the request and to see if how long it takes, you can repeat this process for a couple of times (since you still get some valid responses):
curl response time
$ curl -w "#curl.txt" -o /dev/null -s IP_HERE
curl.txt content(create and save this file first):
time_namelookup: %{time_namelookup}\n
time_connect: %{time_connect}\n
time_appconnect: %{time_appconnect}\n
time_pretransfer: %{time_pretransfer}\n
time_redirect: %{time_redirect}\n
time_starttransfer: %{time_starttransfer}\n
----------\n
time_total: %{time_total}\n
If this is the case, please review the sign up endpoint code for any type of loop like the PG::UniqueViolation errors that you mentioned.