Mở đầu
Khi bạn thiết kế một ứng dụng quan trọng, có tính sẵn sàng cao, khả năng phục hồi là một trong những yếu tố quan trọng nhất cần xem xét. Một ứng dụng có khả năng phục hồi khi nó có thể nhanh chóng phục hồi khi bị failures. Các ứng dụng cloud-native thường được thiết kế để sử dụng kiến trúc microservice nơi mà mỗi thành phần sống trong một container. Để đảm bảo rằng ứng dụng được quản lý bới Kubernetes có tính sẵn sàng cao, có các patterns cụ thể mà bạn cần tuân theo khi thiết kế cluster. Một trong số các patterns đó là Health Probe Pattern. Health Probe Pattern định nghĩa cách ứng dụng báo cáo trạng thái sức khỏe của mình cho Kubernetes. Trạng thái sức khỏe không chỉ là về việc pod có hoạt động hay không mà còn có khả năng nhận và trả lời các request hay không. Khi Kubernetes hiểu rõ hơn về tình trạng sức khỏe của pod, nó có thể đưa ra các quyết định thông minh hơn về traffic-routing và load balancing. Do đó, áp dụng Nguyên tắc High Observability Principle (HOP) đảm bảo rằng mọi request mà ứng dụng của bạn nhận được đều có thể phản hồi kịp thời.
HIGH OBSERVABILITY PRINCIPLE (HOP)
Nguyên tắc này nói như thế nào: Containers cung cấp một cách thống nhất để đóng gói và chạy các ứng dụng bằng cách xem chúng như black box. Những bất cứ container nào muốn trở thành cloud-native citizen phải cung cấp API cho việc check health và các mục đích khác.
Đây là điều kiện tiên quyết cơ bản để automating container updates và life cycles theo cách thống nhất, từ đó cải thiện khả năng phục hồi và trải nghiệm người dùng của hệ thống.
Trong điều kiện thực tế, ở mức tối thiểu, ứng dụng được đóng gói của bạn phải cung cấp API cho các loại health checks như liveness và readiness. Một ứng dụng cloud-native được thiết kế tốt cũng nên ghi log các sự kiện thiết yếu vào các kênh error standard (STDERR) và standard output (STDOUT). Hơn nữa, một helper service như filebeat, logstash hoặc fluentd ships các nhật ký đó đến centralized monitoring, như Prometheus và log aggregation system chẳng hạn như ELK stack. Sơ đồ sau minh họa cách ứng dụng cloud-native tuân theo Health Probe Pattern và High Observability Principle.
url: https://www.redhat.com/en/resources/cloud-native-container-design-whitepaper
Mình sẽ đưa ra một ví dụ cho dễ hiểu, nếu có bạn nào đã tìm hiểu về Elasticsearch ắt sẽ biết ES cung cấp API cho việc check health.
https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html
Trong Kubernetes chúng ta sử dụng Health Check và phương thức http/https để gọi đến API này để kiểm tra xem container ES đã hoặt động Ok chưa. cách config trông như bên dưới:
readinessProbe:
initialDelaySeconds: 180
periodSeconds: 10
failureThreshold: 100
timeoutSeconds: 5
httpGet:
scheme: HTTPS
path: /_cluster/health
port: 9200
httpHeaders:
- name: Authorization
value: Basic KJhKykjHJhb654kLKhkjh4mhjhGKJGHK
Kubernetes Health Check
Kubernetes cung cấp các cách health check (Probes)cho container.
- LivenessProbe
- ReadinessProbe
Đầu tiên chúng ta sẽ cùng xem các probes này hoạt động ở vị trí nào trong pod lifcyle.
url: https://blog.francium.tech/lifecycle-of-a-kubernetes-pod-1214199ddd2c
OK! Bây giờ chúng ta sẽ cùng tìm hiểu xem lợi ích của 2 probes này.
Kubernetes Liveness and Readiness Probes
kubelet sử dụng liveness probes để biết khi nào nên khởi động lại Container. Ví dụ như liveness probes có thể bắt được một deadlock, điều đó làm cho Container không thể hoặt động được. Khởi động lại Container trong các trường hợp như vậy giúp ứng dụng available hơn.
kubelet sử dụng readiness probes để biết được khi nào Container có thể accepting traffic. 1 Pod được coi là ready khi tất cả các container của nó ready. Một ví dụ sử dụng tín hiệu này là để control các Pods được sử dụng ở các dịch vụ Backend. Khi Pod chưa ready, nó sẽ xóa khỏi bộ cân bằng tải của Service.
Ví dụ: nếu một container loads một lượng lớn cache khi khởi động và mất vài phút để khởi động, bạn không muốn gửi requests đến container này cho đến khi nó ready, hoặc các request fail để bạn route các request đó đến các Pod khác, cái đó được gọi là khả năng phục vụ request. Cụ thể hơn trong dự án của mình, Mình có 3 Pod Elasticsearch phục vụ cho mục đích lưu trữ log (Fluetd gửi log đến ES realtime). Khi thực hiện hiện rolling update cho Elastisearch, mình phải đặt config readinessProbe để kiểm tra tình trạng health như thế nào thông qua việc request đến path /_cluster/health nếu chưa Ok thì mình chưa cho Pod đó nhận request (nhận log từ fluentd).
Kubernetes theo dõi trạng thái của Pods bằng một trong những bộ điều khiển của nó (Deployments, ReplicaSets, DaemonSets, StatefulSets, etc.). Nếu bộ điều khiển phát hiện ra rằng pod bị crashed vì một lý do nào đó, nó sẽ cố gắng khởi động lại hoặc đặt lại nó cho một node khác. Tuy nhiên, một Pod có thể báo cáo rằng nó đã up và running; tuy nhiên, nó không hoạt động. Mình sẽ lấy một ví dụ: bạn có một ứng dụng sử dụng Apache làm web server. Bạn đã triển khai nó trên nhiều Pods trong cluster của bạn. Do thư viện bị cấu hình sai, tất cả các request cho ứng dụng này bị response với mã HTTP 500 (Internal Server Error). Khi Deployment kiểm tra trạng thái của Pod, nó phát hiện ra rằng Pod đang running. Nhưng nó không phải là những gì khách hàng của bạn nghĩ. Mình sẽ mô tả tình huống không mong muốn này như sau:
url: https://www.magalix.com/blog/kubernetes-and-containers-best-practices-health-probes
Trong ví dụ trên, Kubernetes đang thực hiện quá trình health check. Trong loại kiểm tra này, kubelet liên tục thăm dò container. Nếu nó phát hiện ra rằng process không hoạt động, nó sẽ khởi động lại. Nếu lỗi được khắc phục chỉ bằng cách khởi động lại ứng dụng và nếu chương trình được thiết kế để tự tắt khi có bất kỳ lỗi nào xảy ra, thì quá trình health checks là tất cả những gì bạn cần tuân theo HOP và Health Probe Pattern. Thật không may, không phải tất cả các lỗi biến mất bằng cách khởi động lại. Vì lý do này, Kubernetes cung cấp hai cách triệt để hơn để phát hiện các lỗi của pod: liveness probe và readiness probe.
Với chỉ vài dòng config trong file YAML, bạn có thể bật chế độ auto heaing cho Kubernetes Pod tốt hơn. Nếu chúng ta kết hợp đúng đắn liveness và readiness probes sẽ giúp việc Deployment trong Kubernetes đạt được:
- Cho phép Deployment zero downtime
- Ngăn chặn deployment mà images có vấn đề
- Đảm bảo rằng các container failed được tự động khởi động lại
Các bạn có thể tham khảo thêm ở tài liệu chính thức của Kubernetes tại đây
Cả 2 Health Probes này cơ bản có syntax cự kỳ đơn giản khá giống nhau, trông như bên dưới:
livenessProbe:
httpGet:
path: /monitoring/health
port: 3000
Liveness Probes
Giả sử rằng một Pod đang chạy ứng dụng của chúng ta bên trong một containr, nhưng vì lý do nào đó như là memory leak, cpu usage, application deadlock v.v.. ứng dụng không đáp ứng các requestscủa chúng ta và bị kẹt trong trạng thái lỗi.
Liveness probe kiểm tra sức khỏe của container như mình đã nói, và nếu vì lý do nào đó, Liveness probe không thành công, nó sẽ khởi động lại container. Chúng ta có thể hình dung hoạt động của Liveness probe như hình bên dưới:
url: https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-setting-up-health-checks-with-readiness-and-liveness-probes
Hoặc
url:https://bcho.tistory.com/tag/liveness probe
Readiness Probes
Hãy để tưởng tượng rằng ứng dụng của bạn mất một phút để warm up và start.
Dịch vụ của bạn sẽ không hoạt động cho đến khi nó up và running, mặc dù process đã hoặt động. Nghĩa là mặc dù thấy đã chạy rồi nhưng thực tế là hoạt động chưa OK. Hoặc bạn cũng gặp vấn đề khi scale up deployment để có thêm nhiều bản sao. một Pod (bảo sao) mới không nên nhận traffic cho đến khi nó thật sự sẵn sàng, nhưng theo mặc định thì Kubernetes sẽ gửi traffic ngay khi container starts.
Bằng cách sử dụng readiness probe, Kubernetes sẽ đợi cho đến khi ứng dụng được khởi động hoàn toàn (ở trạng thái có thể nhận traffic) trước khi cho phép service gửi traffic đến Pod mới.
Chúng ta có thể hình dung mô hình bên dưới:
url: https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-setting-up-health-checks-with-readiness-and-liveness-probes
Hoặc
url:https://bcho.tistory.com/tag/liveness probe
Các cách define Probe
Có 3 cách để định nghĩa Probe
- exec
- httpGet
- tcpSocket
exec
exec sẽ thực thi một hoặc nhiều command bên trong container. Khi command kết thúc, nếu status trả về là 0 thì healthy, khác 0 thì là unhealthy.
exec:
command:
- find
- alive.txt
- -mmin
httpGet
httpGet phát hành 1 request HTTP GET. Nếu response trả về có mã lớn hơn hoặc bằng 200 và nhỏ hơn 400 thì xem như thành công và là healthy. Nếu không thì nó được coi là unhealthy.
- host: Host name để kết nối đến, mặc định là pod IP. Bạn cũng có thể muốn set tham số "Host" trong httpHeaders.
- scheme: Scheme dùng để kết nối đến host (HTTP hoặc HTTPS). Defaults là HTTP.
- path: Đường dẫn để truy cập đến HTTP server.
- httpHeaders: Custom headers để set trong request. HTTP cho phép các headers lặp lại.
- port: Tên hoặc số port để truy cập đến container. Số này phải nằm trong khoảng 1 đến 65535.
Ví dụ:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Host
value: www.example.local
tcpSocket
Loại thứ 3 là TCP Socket. Với kiểu config này kubelet sẽ cố gắng mở một kết nối socket đến container của bạn trên port chỉ định. Nếu nó có thể thiết lập một connect thì container của bạn được xem là healthy, ngược lại thì là thất bại.
- host: chỉ định địa chỉ lên kết, mặc định là Pod IP
- port: chỉ định Port khi thực hiện request. Có thể sử dụng sô port hoặc port name
Ví dụ:
tcpSocket:
port: 6379
Một số parameter
Probes có một số tham số mà bạn có thể sử dụng để kiểm soát chính xác hơn hành vi của liveness và readiness checks:
- initialDelaySeconds: Số giây sau khi container started trước khi liveness hoặc readiness probes thực hiện check. Nghĩa là container start xong, cách bao nhiêu giây thì mới thực hiện check.
- periodSeconds: Tần suất (tính bằng giây) để thực hiện probes. Mặc định là 10 giây. Giá trị tối thiểu là 1.
- timeoutSeconds: Số giây sau khi probes times out. Mặc định là 1 giây. Giá trị tối thiểu là 1.
- successThreshold: Số lần success liên tiếp của probes sau khi failed, nếu nó đạt con số này sẽ được coi là thành công, không thì sẽ thực hiện check tiếp. Mặc định là 1. Phải là 1 cho liveness. Giá trị tối thiểu là 1.
- failureThreshold: Khi một Pod start và probe thất bại, Kubernetes sẽ thử một số lần failureThreshold trước khi bỏ cuộc. Từ bỏ trong trường hợp liveness probe có nghĩa là khởi động lại container. Trong trường hợp readiness probe, Pod sẽ được đánh dấu Unready. Mặc định là 3. Giá trị tối thiểu là 1.
LivenessProbe Example
Chuẩn bị file Manifest
#liveness-check.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-check
spec:
containers:
- image: nginx
name: nginx
livenessProbe:
httpGet:
port: 80
path: /
failureThreshold: 5
periodSeconds: 5
[vagrant@ci health-probes]$ kubectl apply -f liveness-check.yaml -n kuber-best-practice
pod "liveness-check" created
[vagrant@ci health-probes]$ kubectl get pods -n kuber-best-practice
NAME READY STATUS RESTARTS AGE
liveness-check 1/1 Running 0 58s
[vagrant@ci health-probes]$ kubectl describe po/liveness-check -n kuber-best-practice
Name: liveness-check
Namespace: kuber-best-practice
Node: 192.168.33.50/192.168.33.50
Start Time: Mon, 23 Sep 2019 11:24:46 +0900
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"liveness-check","namespace":"kuber-best-practice"},"spec":{"containers":[{"image":...
Status: Running
IP: 10.42.0.62
Containers:
nginx:
Container ID: docker://cb1042b72ebe8e504d8bd8a56db033694a6c6c9a85f869247586255c62cbf901
Image: nginx
Image ID: docker-pullable://nginx@sha256:9688d0dae8812dd2437947b756393eb0779487e361aa2ffbc3a529dca61f102c
Port: <none>
Host Port: <none>
State: Running
Started: Mon, 23 Sep 2019 11:24:56 +0900
Ready: True
Restart Count: 0
Liveness: http-get http://:80/ delay=0s timeout=1s period=5s #success=1 #failure=5
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-tml4h (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-tml4h:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-tml4h
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 1m default-scheduler Successfully assigned liveness-check to 192.168.33.50
Normal SuccessfulMountVolume 1m kubelet, 192.168.33.50 MountVolume.SetUp succeeded for volume "default-token-tml4h"
Normal Pulling 1m kubelet, 192.168.33.50 pulling image "nginx"
Normal Pulled 1m kubelet, 192.168.33.50 Successfully pulled image "nginx"
Normal Created 1m kubelet, 192.168.33.50 Created container
Normal Started 1m kubelet, 192.168.33.50 Started container
Chúng ta để ý chổ này
Liveness: http-get http://:80/ delay=0s timeout=1s period=5s #success=1 #failure=5
Vậy là chúng ta đã setting cho Liveness probe Ok rồi. Bây giờ mình sẽ thử xóa file /usr/share/nginx/html/index.html trong container xem sao.
[vagrant@ci health-probes]$ kubectl exec liveness-check -- rm /usr/share/nginx/html/index.html -n kuber-best-practice
[vagrant@ci health-probes]$ kubectl describe po/liveness-check -n kuber-best-practice | tail
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 15m default-scheduler Successfully assigned liveness-check to 192.168.33.50
Normal SuccessfulMountVolume 15m kubelet, 192.168.33.50 MountVolume.SetUp succeeded for volume "default-token-tml4h"
Warning Unhealthy 42s (x5 over 1m) kubelet, 192.168.33.50 Liveness probe failed: HTTP probe failed with statuscode: 403
Normal Pulling 41s (x2 over 15m) kubelet, 192.168.33.50 pulling image "nginx"
Normal Killing 41s kubelet, 192.168.33.50 Killing container with id docker://nginx:Container failed liveness probe.. Container will be killed and recreated.
Normal Pulled 36s (x2 over 15m) kubelet, 192.168.33.50 Successfully pulled image "nginx"
Normal Created 36s (x2 over 15m) kubelet, 192.168.33.50 Created container
Normal Started 36s (x2 over 15m) kubelet, 192.168.33.50 Started container
Các bạn có thể thấy Probe thất bại và hiển thị thông báo "Liveness probe failed: HTTP probe failed with statuscode: 403" tuy nhiên chỉ trong chốc lát, container đã được khởi động lại bình thường.
Readiness Probes Example
Chuẩn bị file Manifest
#readiness-check.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-check
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
readinessProbe:
httpGet:
port: 80
path: /
failureThreshold: 1
periodSeconds: 1
---
apiVersion: v1
kind: Service
metadata:
name: readiness-check-svc
spec:
selector:
app: nginx
ports:
- port: 80
[vagrant@ci health-probes]$ kubectl apply -f readiness-check.yaml -n kuber-best-practice
pod "readiness-check" created
service "readiness-check-svc" created
[vagrant@ci health-probes]$ kubectl get all -n kuber-best-practice
NAME READY STATUS RESTARTS AGE
pod/readiness-check 1/1 Running 0 13s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/readiness-check-svc ClusterIP 10.43.175.77 <none> 80/TCP 1m
[vagrant@ci health-probes]$ kubectl describe po/readiness-check -n kuber-best-practice
Name: readiness-check
Namespace: kuber-best-practice
Node: 192.168.33.51/192.168.33.51
Start Time: Mon, 23 Sep 2019 11:49:49 +0900
Labels: app=nginx
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"readiness-check","namespace":"kuber-best-practice"},"spec...
Status: Running
IP: 10.42.1.7
Containers:
nginx:
Container ID: docker://145a03bb80ed336064ca00219223a013b638c6ebd5a80f42a04e0981c8373c03
Image: nginx
Image ID: docker-pullable://nginx@sha256:9688d0dae8812dd2437947b756393eb0779487e361aa2ffbc3a529dca61f102c
Port: <none>
Host Port: <none>
State: Running
Started: Mon, 23 Sep 2019 11:49:56 +0900
Ready: True
Restart Count: 0
Readiness: http-get http://:80/ delay=0s timeout=1s period=1s #success=1 #failure=1
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-tml4h (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-tml4h:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-tml4h
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m default-scheduler Successfully assigned readiness-check to 192.168.33.51
Normal SuccessfulMountVolume 2m kubelet, 192.168.33.51 MountVolume.SetUp succeeded for volume "default-token-tml4h"
Normal Pulling 2m kubelet, 192.168.33.51 pulling image "nginx"
Normal Pulled 2m kubelet, 192.168.33.51 Successfully pulled image "nginx"
Normal Created 2m kubelet, 192.168.33.51 Created container
Normal Started 2m kubelet, 192.168.33.51 Started container
Vậy là ReadinessProbe đã được setting OK. Bây giờ ta cũng làm như khi nãy, xóa file /usr/share/nginx/html/index.html trong container
kubectl exec readiness-check -n kuber-best-practice -- rm /usr/share/nginx/html/index.html
Kiểm tra xem tình trạng Pod thế nào
[vagrant@ci health-probes]$ kubectl describe po/readiness-check -n kuber-best-practice | tail
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 17m default-scheduler Successfully assigned readiness-check to 192.168.33.51
Normal SuccessfulMountVolume 17m kubelet, 192.168.33.51 MountVolume.SetUp succeeded for volume "default-token-tml4h"
Normal Pulling 16m kubelet, 192.168.33.51 pulling image "nginx"
Normal Pulled 16m kubelet, 192.168.33.51 Successfully pulled image "nginx"
Normal Created 16m kubelet, 192.168.33.51 Created container
Normal Started 16m kubelet, 192.168.33.51 Started container
Warning Unhealthy 10s (x23 over 32s) kubelet, 192.168.33.51 Readiness probe failed: HTTP probe failed with statuscode: 403
Vậy là Readiness probe failed và chắc chắn chúng ta sẽ không access được đến service.
Bây giờ để ReadinessProbe check Ok thì ta tiến hành tạo lại file /usr/share/nginx/html/index.html
$ kubectl exec readiness-check -n kuber-best-practice -- sh -c 'echo ok > /usr/share/nginx/html/index.html'
Kiểm tra lại service bạn sẽ thấy không còn lỗi connect nữa. Như vậy chúng ta có thể thấy, Việc rooting của Service sẽ loại những Container nào có ReadinessProbe Unhealthy khỏi đối tượng rooting. Và khi nó Healthy trở lại thì Service sẽ tiến hành rooting đến Pod đó.
So sánh Liveness and Readiness Probes
Chúng ta sẽ so sánh một chút về 2 loại probes này.
url: https://www.weave.works/blog/resilient-apps-with-liveness-and-readiness-probes-in-kubernetes
Khi nào thì sử dụng liveness và readiness probes
Liveness use case
Như đã nói phía trên, các liveness probe được sử dụng để chẩn đoán các container unhealthy. Chúng ta có thể phát hiện sự cố trong dịch vụ của chúng ta khi nó không thể hoạt động OK và sẽ khởi động lại container khi có có vấn đề theo restart policy, hy vọng loại bỏ sự cố dịch vụ.
Ví dụ, bạn có thể muốn bao gồm một liveness probe Exec bên trong container của mình để phát hiện khi một ứng dụng đã chuyển sang trạng thái bị hỏng và không thể phục hồi trừ khi nó khởi động lại:
readiness use case
Mặt khác, readiness probe rất hữu ích trong trường hợp ứng dụng tạm thời không thể phục vụ traffic. Ví dụ, có thể ứng dụng cần tải một tập dữ liệu lớn hoặc một số tệp cấu hình trong giai đoạn khởi động. Mặc dù dịch vụ này đang running nhưng nó chưa fully available và trong trường hợp này, Kubernetes có thể gặp khó khăn khi scaling up và có thể thất bại. Với một readiness probe, Kubernetes đợi cho đến khi dịch vụ được khởi động hoàn toàn trước khi nó gửi traffic truy cập đến bản sao mới.
Ví dụ về Elasticsearch cluster là một điển hình, khi các log được gửi đến liên tục, việc rolling update sẽ tắt và bật các Pod, cho đến ES Pod được khởi động hoàn toàn và có thể nhận traffic, trong thời gian này Service sẽ đưa Pod này ra khỏi đổi tượng nhận traffic.
Kết luận
Tài liệu tham khảo
- https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
- https://www.magalix.com/blog/kubernetes-and-containers-best-practices-health-probes
- https://cstoku.dev/posts/2018/k8sdojo-10/
- https://blog.francium.tech/lifecycle-of-a-kubernetes-pod-1214199ddd2c
- https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-setting-up-health-checks-with-readiness-and-liveness-probes
- https://www.weave.works/blog/resilient-apps-with-liveness-and-readiness-probes-in-kubernetes
- https://bcho.tistory.com/tag/liveness probe
- https://www.redhat.com/en/resources/cloud-native-container-design-whitepaper
- https://viblo.asia/p/zero-downtime-voi-kubernetes-p1-truly-stateless-application-ORNZqjErl0n?fbclid=IwAR0HEFTSHxyRpFq_3DXqwjXJxt-iaUsWbt41EtBOgbeqmkxtVcqpALxn5NE
- https://medium.com/@AADota/kubernetes-liveness-and-readiness-probes-difference-1b659c369e17
- https://medium.com/spire-labs/utilizing-kubernetes-liveness-and-readiness-probes-to-automatically-recover-from-failure-2fe0314f2b2e
- https://itnext.io/exploring-kubernetes-liveness-and-readiness-probes-e9bbc7d899be
- https://www.replex.io/blog/kubernetes-in-production-readiness-checklist-and-best-practiceshttps://blog.colinbreck.com/kubernetes-liveness-and-readiness-probes-how-to-avoid-shooting-yourself-in-the-foot/