{"id":518,"date":"2025-08-04T16:01:42","date_gmt":"2025-08-04T16:01:42","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=518"},"modified":"2025-08-04T16:01:42","modified_gmt":"2025-08-04T16:01:42","slug":"kubernetes-pod-graceful-shutdown","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=518","title":{"rendered":"Kubernetes Pod Graceful Shutdown with SIGTERM &#038; preStop Hooks"},"content":{"rendered":"<p>In this guide, I have explained how to handle <a href=\"https:\/\/devopscube.com\/kubernetes-pod\/\" rel=\"noreferrer\">Kubernetes pod<\/a> graceful shutdown using SIGTERM and preStop hooks, with practical examples.<\/p>\n<p>One of the fundamental concepts in Kubernetes is Pod Graceful Shutdown. It plays a key role in application reliability.<\/p>\n<p>While modern application architectures often use&nbsp;<strong>patterns like circuit breakers, retries, and timeouts<\/strong>&nbsp;to handle failures gracefully, graceful pod shutdown acts as the last line of defense.<\/p>\n<p>By the end of this guide, you will have learned,<\/p>\n<ul>\n<li>What are SIGTERM and SIGKILL<\/li>\n<li>How Kubernetes handles SIGTERM and SIGKILL<\/li>\n<li>Practically understand how to handle SIGTERM in applications.<\/li>\n<li>The role of PreStop hooks and why it matters<\/li>\n<li>The link between SIGTERM and container PID 1<\/li>\n<\/ul>\n<p>Lets get started.<\/p>\n<h2 id=\"kubernetes-sigterm\">Kubernetes &amp; SIGTERM<\/h2>\n<p>When a pod shuts down in Kubernetes (due to scaling, update, or any reason), it sends a <strong>SIGTERM signal<\/strong> to the app inside. <\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udca1<\/div>\n<div class=\"kg-callout-text\">A signal is a way Linux Kernel to talk to (sending an interrupt) to a running process. Each signal has a unique number.<\/p>\n<p><b><strong style=\"white-space: pre-wrap;\">SIGTERM (Signal 15)<\/strong><\/b>&nbsp;is used to request the termination of a process.<\/p>\n<p><b><strong style=\"white-space: pre-wrap;\">SIGKILL (Signal 9)<\/strong><\/b>&nbsp;forces an immediate termination of a process .<\/div>\n<\/div>\n<p>If your app does not handle <strong>SIGTERM<\/strong> properly, it might stop in the middle of serving a user request or processing a file (by <strong>SIGKILL<\/strong>), leading to <strong>data loss or a bad user experience<\/strong>. <\/p>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udca1<\/div>\n<div class=\"kg-callout-text\">SIGTERM runs at the process level<\/div>\n<\/div>\n<p>For example, let&#8217;s say an app is handling file uploads or user payments. <\/p>\n<p>If the pod shuts down without waiting, files may be incomplete, or payments may fail. It could lead to <\/p>\n<ol>\n<li><code>ECONNRESET<\/code> errors for clients with in-flight requests<\/li>\n<li>HTTP 5xx errors (typically 502 Bad Gateway or 503 Service Unavailable)<\/li>\n<li>Database connections remain open until the timeout, etc.<\/li>\n<\/ol>\n<p>By catching SIGTERM, you can,<\/p>\n<ul>\n<li>Finish the current request<\/li>\n<li>Save important state<\/li>\n<li>Notify other services<\/li>\n<\/ul>\n<h2 id=\"kubernetes-graceful-pod-termination-process\">Kubernetes Graceful Pod Termination Process<\/h2>\n<p>First lets look at how Kubernetes handles SIGTERM.<\/p>\n<p>The following diagram shows the graceful pod termination process in Kubernetes.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/07\/image-229.png\" class=\"kg-image\" alt=\"Kubernetes Graceful Pod Shutdown Process\" loading=\"lazy\" width=\"2000\" height=\"1701\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/07\/image-229.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/07\/image-229.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/07\/image-229.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w2400\/2025\/07\/image-229.png 2400w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Here is how it works.<\/p>\n<ol>\n<li>A pod deletion request is sent to Kubernetes via kubectl pod delete or the API server sends a deletion event.<\/li>\n<li>Then the kubelet sends a SIGTERM to the application process container. When there are multiple containers in a pod, Kubernetes sends SIGTERM to all containers simultaneously.<\/li>\n<li>Once the application receives the SIGTERM, it has <strong>30 seconds by default<\/strong> to handle the signal and shutdown gracefully. (The grace period is a configurable value using <strong>terminationGracePeriodSeconds<\/strong>)<\/li>\n<li>Now, the application SIGTERM handler stops accepting new requests, finishes processing in-flight requests, closes database connections, and so on.<\/li>\n<li>If the SIGTERM handler executes all the graceful shutdown activities the applications shuts down gracefully.<\/li>\n<li>If the application process does not exit within the grace period, Kubernetes sends a SIGKILL signal to terminate it forcefully.<\/li>\n<\/ol>\n<div class=\"kg-card kg-callout-card kg-callout-card-blue\">\n<div class=\"kg-callout-emoji\">\ud83d\udca1<\/div>\n<div class=\"kg-callout-text\">The <b><strong style=\"white-space: pre-wrap;\">terminationGracePeriodSeconds<\/strong><\/b> timer starts at the same time the containers recives the SIGTERM<\/div>\n<\/div>\n<p>Is 30 seconds <code>terminationGracePeriodSeconds<\/code> ideal?<\/p>\n<p>There is no definitive answer. The&nbsp;<strong>30 seconds<\/strong>&nbsp;(the Kubernetes default) works for most cases.<\/p>\n<p>However, for databases or heavy processing apps, you may have to use&nbsp;<strong>60-120 seconds<\/strong>&nbsp;and for batch jobs or data processing, you might need&nbsp;<strong>300+ seconds<\/strong>&nbsp;to finish their work properly. So it depends on the applications.<\/p>\n<h2 id=\"handling-sigterm-in-an-application\">Handling SIGTERM in an Application<\/h2>\n<p>To understand Graceful Pod Shutdown using SIGTERM, let&#8217;s build a <strong>Flask app<\/strong> that performs the following tasks.<\/p>\n<ul>\n<li>Takes a few seconds to process a request (simulates real work)<\/li>\n<li>Handles the SIGTERM signal properly.<\/li>\n<li>Cleans up before shutting down.<\/li>\n<\/ul>\n<p>The workflow remains the same for all types of apps. The libraries and their implementation will change based on the use case.<\/p>\n<p>Create a Python file <code>app.py<\/code> and copy the below content.<\/p>\n<pre><code class=\"language-python\">from flask import Flask\nimport signal\nimport time\nimport sys\n\napp = Flask(__name__)\nis_shutting_down = False\n\ndef handle_sigterm(signum, frame):\n    global is_shutting_down\n    print(\"\\n[SHUTDOWN] SIGTERM signal received.\")\n    is_shutting_down = True\n    print(\"[SHUTDOWN] Finishing remaining tasks before exit...\")\n    time.sleep(1)\n    print(\"[SHUTDOWN] Saving in-progress orders to database...\")\n    time.sleep(1)\n    print(\"[SHUTDOWN] Notifying other services that shutdown is happening...\")\n    time.sleep(1)\n    print(\"[SHUTDOWN] Cleanup complete. Shutting down gracefully.\")\n    \n    sys.exit(0)\n\nsignal.signal(signal.SIGTERM, handle_sigterm)\n\n@app.route(\"\/work\")\ndef do_work():\n    if is_shutting_down:\n        print(\"[WORK] Rejected request: shutting down.\")\n        return \"Server is shutting down. Try again later.\\n\", 503\n\n    print(\"[WORK] New order processing started...\")\n    time.sleep(3)\n    print(\"[WORK] Validating order data...\")\n    time.sleep(2)\n    print(\"[WORK] Writing order to database...\")\n    time.sleep(2)\n    print(\"[WORK] Order processed successfully.\")\n    return \"Order processed successfully!\\n\"\n\n@app.route(\"\/\")\ndef home():\n    return \"Welcome to the Order Processing App\\n\"\n\nif __name__ == \"__main__\":\n    print(\"[APP] Starting Flask app...\")\n    app.run(host=\"0.0.0.0\", port=5000)\n<\/code><\/pre>\n<p>Here is the Dockerfile to <a href=\"https:\/\/devopscube.com\/build-docker-image\/\" rel=\"noreferrer\">build the application image<\/a>. If you dont want to build a image, use our <code>devopscube\/python-app:1.0.0<\/code> image for testing.<\/p>\n<pre><code class=\"language-docker\">FROM python:3.9-slim\n\nWORKDIR \/app\nCOPY app.py .\n\nRUN pip3 install flask\n\nCMD [\"python3\", \"app.py\"]\n<\/code><\/pre>\n<p>Once you have the image ready in a Docker registry, deploy it using the following <a href=\"https:\/\/devopscube.com\/kubernetes-deployment-tutorial\/\" rel=\"noreferrer\">Deployment<\/a> manifest.<\/p>\n<p>Create <code>graceful-pod.yaml<\/code> and copy the following manifest.<\/p>\n<pre><code class=\"language-yaml\">apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: graceful-app\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: graceful-app\n  template:\n    metadata:\n      labels:\n        app: graceful-app\n    spec:\n      containers:\n      - name: graceful-app\n        image: devopscube\/python-app:1.0.0\n        ports:\n        - containerPort: 5000\n        terminationMessagePath: \"\/dev\/termination-log\"\n      terminationGracePeriodSeconds: 60\n<\/code><\/pre>\n<p>In the above YAML mainifest <code>terminationMessagePath<\/code> is the default path inside the container where termination messages are written by the pod. It tells Kubernetes where it can find termination messages.<\/p>\n<p>As we learned before, <code>terminationGracePeriodSeconds<\/code> tells Kubernetes to wait up to 60 seconds (default is 30) before forcefully deleting the pod.<\/p>\n<p>If the pod is not shutdown within the grace period, it deletes the pods forcefully.<\/p>\n<p>Lets deploy the manifest.<\/p>\n<pre><code>kubectl apply -f graceful-pod.yaml<\/code><\/pre>\n<h2 id=\"validate-graceful-shutdown\">Validate Graceful Shutdown<\/h2>\n<p>The next step is to validate the graceful shutdown. Follow the steps below for validation.<\/p>\n<h3 id=\"step-1-tail-the-logs\">Step 1: Tail the Logs<\/h3>\n<p>Tail the logs of the pods to watch the logs in real-time and to watch the logs of the running pod run the following commands:<\/p>\n<pre><code class=\"language-bash\">POD_NAME=$(kubectl get pods -l app=graceful-app -o jsonpath='{.items[0].metadata.name}')\n\nkubectl logs -f $POD_NAME<\/code><\/pre>\n<h3 id=\"step-2-send-test-requests\">Step 2: Send Test Requests<\/h3>\n<p>While the logs are tailing, you could <code>kubectl port-forward<\/code> and send <code>curl<\/code> request continuously to see if it&#8217;s being processed.<\/p>\n<p>Or use Apache benchmark to send requests continuously.<\/p>\n<p>Open a new terminal and run the following command to port-forward the pod.<\/p>\n<pre><code class=\"language-bash\">kubectl port-forward pod\/&lt;pod-name&gt; 5000:5000<\/code><\/pre>\n<p>Now, open a new terminal and run the following command to send curl requests to the pod continuously.<\/p>\n<pre><code class=\"language-bash\">while true; do curl -s http:\/\/localhost:5000\/work; echo; sleep 1; done<\/code><\/pre>\n<h3 id=\"step-3-delete-the-pod\">Step 3: Delete the Pod<\/h3>\n<p>Now, delete the pod to check how Sigterm gracefully deletes it.<\/p>\n<p>You will get the log as follows.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/04\/image-27.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"1656\" height=\"510\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/04\/image-27.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/04\/image-27.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/04\/image-27.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/04\/image-27.png 1656w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>Here is what you just saw.<\/p>\n<ul>\n<li>Kubernetes sent <code>SIGTERM<\/code> when you deleted the Pod.<\/li>\n<li>Flask app caught the signal.<\/li>\n<li>Finish In-Flight Work &#8211; Allowing ongoing tasks\/requests to complete.<\/li>\n<li>Clean Up Resources: Close database connections, files, network listeners, etc.<\/li>\n<\/ul>\n<h2 id=\"using-prestop-hook-for-buffer-time\">Using PreStop Hook for Buffer Time<\/h2>\n<p>When you delete a Pod, Kubernetes sends a SIGTERM signal to your app.<\/p>\n<p>The problem is, while your app is starting to shut down, things like&nbsp;<strong>Kube-Proxy, Ingress controllers, or external load balancers&nbsp;<\/strong>(like AWS ALB) might still be routing traffic to that Pod.<\/p>\n<p>This delay happens because it takes time to,<\/p>\n<ol>\n<li>Remove the Pod from the service endpoints (update takes time to propagate)<\/li>\n<li>Update kube-proxy iptables rules<\/li>\n<li>External load balancers (like AWS ALB) also need time to remove the Pod from their target list.<\/li>\n<\/ol>\n<p>So if your app shuts down too quickly, clients might still get routed to it and end up with \u201c<strong><em>connection refused<\/em><\/strong>\u201d errors.<\/p>\n<p>At the same time, there is no mechanism to control how fast other components (like Kube-Proxy, Ingress, etc.) stop sending traffic to the Pod.<\/p>\n<p>But you can slow down your apps shutdown a bit using a&nbsp;<code>preStop<\/code>&nbsp;hook. The&nbsp;<code>preStop<\/code>&nbsp;hook runs&nbsp;<strong>before<\/strong>&nbsp;Kubernetes sends SIGTERM.<\/p>\n<p>For example, adding a simple&nbsp;<code>sleep 10<\/code>&nbsp;in the&nbsp;<code>preStop<\/code>&nbsp;gives your app a 10-second buffer to let traffic stop flowing before it shuts down.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/08\/image-20.png\" class=\"kg-image\" alt=\"Graceful pod shutdown prestop hook\" loading=\"lazy\" width=\"1920\" height=\"917\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/08\/image-20.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/08\/image-20.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/08\/image-20.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/08\/image-20.png 1920w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>This gives time for Kube-Proxy to update iptables rules or an external Load balancer (Eg, AWS ALB <a href=\"https:\/\/devopscube.com\/setup-ingress-kubernetes-nginx-controller\/\" rel=\"noreferrer\">ingress controller<\/a>) to stop forwarding requests to that pod.<\/p>\n<p>Here is an example of a Deployment YAML with the&nbsp;<code>preStop<\/code>&nbsp;lifecycle hook highlighted.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/08\/image-21.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"1920\" height=\"2496\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/08\/image-21.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/08\/image-21.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/08\/image-21.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/08\/image-21.png 1920w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<h2 id=\"sigterm-pid\">SIGTERM &amp; PID<\/h2>\n<p>Kubernetes sends&nbsp;<code>SIGTERM<\/code>&nbsp;to the process with&nbsp;<code>PID<\/code>&nbsp;1 inside the container. If your app is not running as &nbsp;<code>PID<\/code>&nbsp;1, it will not receive the signal, and the code to handle graceful termination will not execute.<\/p>\n<p>For example, if the Dockerfile runs a shell script that starts your app as a child process, the script becomes PID\u202f1, not your app.<\/p>\n<p>Look at the following example.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/08\/image-22.png\" class=\"kg-image\" alt=\"PID 1 and shell script\" loading=\"lazy\" width=\"1262\" height=\"414\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/08\/image-22.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/08\/image-22.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/08\/image-22.png 1262w\" sizes=\"auto, (min-width: 720px) 720px\"><\/figure>\n<p>However, if you need a shell script, use&nbsp;<code>exec<\/code>&nbsp;to replace the shell process.<\/p>\n<figure class=\"kg-card kg-image-card\"><img decoding=\"async\" src=\"https:\/\/media.beehiiv.com\/cdn-cgi\/image\/fit=scale-down,format=auto,onerror=redirect,quality=80\/uploads\/asset\/file\/fc0a3188-8061-461f-b142-0f5bd63d73f9\/image.png?t=1753880395\" class=\"kg-image\" alt=\"PID 1 and shell script with exec\" loading=\"lazy\" width=\"1693\" height=\"546\"><\/figure>\n<p>To check this, you can use the following command inside the pod.<\/p>\n<pre><code class=\"language-bash\">ps -e -o pid,ppid,cmd<\/code><\/pre>\n<p>Here is an example of a pod where <code>app.py<\/code> is assigned PID 1 because it is started using <code>exec<\/code> in the shell scrip<\/p>\n<pre><code class=\"language-bash\">\u279c k exec -it graceful-app-pid1-8649dfbf5c-v48tv -- bash\n\nroot@graceful-app-pid1-86\nroot@graceful-app-pid1-8649dfbf5c-v48tv:\/app# ps -e -o pid,ppid,cmd\n    PID    PPID CMD\n      1       0 python3 app.py\n      7       0 bash\n     14       7 ps -e -o pid,ppid,cmd\nroot@graceful-app-pid1-8649dfbf5c-v48tv:\/app# <\/code><\/pre>\n<p>The following example shows PID 1 assigned to the shell script because it was started without using <code>exec<\/code><\/p>\n<pre><code>\u279c k exec -it graceful-app-no-pid1-5d7b6bfdf7-2xffr -- bash\n\nroot@graceful-app-no-pid1-5d7b6bfdf7-2xffr:\/app# ps -e -o pid,ppid,cmd\n    PID    PPID CMD\n      1       0 \/bin\/bash .\/start-without-exec.sh\n      7       1 python3 app.py\n      8       0 bash\n     14       8 ps -e -o pid,ppid,cmd<\/code><\/pre>\n<p>This applies to&nbsp;<code>CMD<\/code>&nbsp;as well. In a <a href=\"https:\/\/devopscube.com\/build-docker-image-kubernetes-pod\/\" rel=\"noreferrer\">Dockerfile<\/a>, how you write the&nbsp;<code>CMD<\/code>&nbsp;instruction affects how&nbsp;<code>SIGTERM<\/code>&nbsp;is handled.<\/p>\n<p>For example,<\/p>\n<ul>\n<li><code>CMD [\"python3\", \"app.py\"]<\/code>&nbsp;&#8211; This is the exec form.&nbsp;<code>python3<\/code>&nbsp;becomes the PID 1 (first process) inside the container.<\/li>\n<li><code>CMD python3 app.py<\/code>&nbsp;&#8211; This is the shell form. Docker runs it as:<br \/><code>\/bin\/sh -c \"python3 app.py\"<\/code>&nbsp;In this case, the shell (<code>sh<\/code>) becomes PID 1, and&nbsp;<code>python3<\/code>&nbsp;is just a child process.<\/li>\n<\/ul>\n<h2 id=\"modern-frameworks-handle-sigterm-for-you\">Modern frameworks handle SIGTERM for you<\/h2>\n<p>Popular frameworks include built-in support for graceful shutdown<\/p>\n<p>For example,<\/p>\n<p>In Spring Boot (Java), just set&nbsp;<code>server.shutdown=graceful<\/code>&nbsp;and it stops accepting new traffic and waits for ongoing requests before exiting<\/p>\n<p>Go&#8217;s&nbsp;<code>http.Server<\/code>&nbsp;includes a&nbsp;<code>Shutdown()<\/code>&nbsp;method that handles graceful shutdown properly.<\/p>\n<p>These usually handle the common logic, such as,<\/p>\n<ul>\n<li>Stop accepting new requests.<\/li>\n<li>Waits for active HTTP requests to finish etc<\/li>\n<\/ul>\n<p>However, you may need to&nbsp;<strong>perform special cleanup actions<\/strong>: e.g., deregister from a service, send metrics, flush caches, commit state to the database etc.<\/p>\n<h2 id=\"wrapping-up\">Wrapping Up<\/h2>\n<p>We have covered almost all the key concepts in Kubernetes pod graceful termination.<\/p>\n<p>Here are the key takeaways.<\/p>\n<ul>\n<li>Handle SIGTERM properly with a suitable termination grace period.<\/li>\n<li>Ensure your application process runs as PID 1 in the container to receive the SIGTERM signal<\/li>\n<li>Use PreStop hooks for graceful shutdown buffer time.<\/li>\n<\/ul>\n<p>Over to you.<\/p>\n<p>What problems did you face (or think you might face) when trying to safely shut down a Kubernetes pod?<\/p>\n<p>Comment below.<\/p>\n<\/p>\n<h2 id=\"\"><\/h2>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/kubernetes-pod-graceful-shutdown\/\" target=\"_blank\" rel=\"noopener noreferrer\">Kubernetes Pod Graceful Shutdown with SIGTERM &amp; preStop Hooks \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/kubernetes-pod-graceful-shutdown\/<\/p>\n","protected":false},"author":1,"featured_media":519,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-518","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/518","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=518"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/518\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/519"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=518"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=518"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=518"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}