The concept of hooks is well-known in the tech world. Events usually trigger hooks, and they allow developers to react to those events and run some custom code. Let's take a simple user interface with a button and a text box. There might be multiple events that developers might be interested in handling (i.e., running some code whenever the event happens). One of these events could be the onClick event. You could write an onClick handler that gets called whenever a user clicks a button.
Another popular example of hooks is webhooks. For example, your e-commerce website can define webhooks that can send you a JSON payload with the purchase information to a URL you specified whenever a sale occurs. You write a handler (in this case, it could be a serverless function) and set your serverless function as a handler for an event. This allows you to loosely couple the functionality and handle events that happen on a different system.
Similarly, Kubernetes provides so-called container hooks. The container hooks allow you to react to container lifecycle events. There are two hooks you can use, the PostStart and PreStop.
Kubernetes executes the PostStart hook as soon as the container is created. However, there's no guarantee that the hook runs before the containers' ENTRYPOINT command is called (they fire asynchronously). Note that if the hook handler hangs, it will prevent the container from reaching a running state.
Kubernetes calls the PreStop hook before a container gets terminated. For the container to stop, the hook needs to complete executing. If the code in the handler hangs, your Pod will remain in the Terminating state until it gets killed.
If either of the hook handlers fails, the container will get killed. If you decide on using these hooks, try to make your code as lightweight as possible, so your containers can start/stop quickly.
As for the handlers, you can use a command that gets executed inside the container (e.g. myscript.sh) or send an HTTP request to a specific endpoint on the container (e.g. /shutdown).
The most common scenarios you'd use the hooks for are performing some cleanup or saving the state before the container is terminated (PreStop) or configure application startup once the container starts (PostStart).
We've talked about init containers, and there are differences between the two:
Init containers have their image while lifecycle hooks are executed inside the parent containers
Init containers are defined at the Pod level, while lifecycle hooks are defined per each container
Init containers are guaranteed to execute before the application containers start, while the PostStart hook might not execute before the ENTRYPOINT is called
Let's look at an example to see how these lifecycle handlers work.
In this Pod YAML, we define both hooks. In the postStart hook, we are writing "Hello postStart!" to a file in the container (/var/tmp/hello.txt). The Save the above YAML contents to hooks-pod.yaml and create the Pod:
$ kubectl apply -f hooks-pod.yaml
Once the Pod is running, we can check the contents of the hello.txt file inside the container:
If you delete the Pod, you will also notice that it takes an extra 10 seconds for Kubernetes to delete it.
How about the preStart hook?
You might be wondering why there's no preStart hook. Even though there's an existing issue opened since 2014 that talks about omplementing the PreStart and PostStop hooks, however, there's no updates on it.
The latest guidance is that if you want to implement a PreStart hook, you should implement it in the init container. To learn how Init containers work, check out the Kubernetes Init Containers blog post.
Join the discussion
SHARE THIS ARTICLE
Peter Jausovec is a platform advocate at Solo.io. He has more than 15 years of experience in the field of software development and tech, in various roles such as QA (test), software engineering and leading tech teams. He's been working in the cloud-native space, focusing on Kubernetes and service meshes, and delivering talks and workshops around the world. He authored and co-authored a couple of books, latest being Cloud Native: Using Containers, Functions, and Data to Build Next-Generation Applications.