Reverse engineering of a Helm chart
Today we are going to run a very basic Helm chart in Docker Desktop and try to identify the connection between that Helm chart, the Docker image it has used and the service included in that Docker image.
As for the start, lets get to know our environment. This is my development and testing environment.
- Docker Desktop for Mac : Version 4.9.0
- Kubernetes version (Client & Server) : v1.24.0
- Helm version : v3.9.0
I am trying out anujarosha/hello-go chart from the Artifact HUB. Firstly I’ll add the Helm repository to my local machine using following command.
helm repo add hello-go https://anujarosha.github.io/hello-go/artifacts
Then I’ll be deploying the chart to a new namespace
helm install my-hello-go hello-go/hello-go --version 0.2.1 -n medium --create-namespace
As per now, only endpoints that you can check are /hi and /hello. So, you will be able to visit following link from your web browser.
http://localhost:8081/hi
Then you will get an output like this.
Now we have run a simple helm chart and then we need to understand about following questions.
- If you aware at least the basics of Helm charts, a chart consists of bunch of configuration files. Then where this simple web service comes from?
- Why this 8081 port?
- Why this /hi endpoint?
You may have several other questions. Lets try to figure these one by one. As an start, lets see what components has deployed in our namespace.
There you can see, the service has used LoadBalancer as the service type and it assigned localhost as external IP and 8081 as the port. That’s why you able to directly load the service from your web browser.
Lets explore deeper. To that, you can either download the Helm chart source, extract it and investigate the configuration files or you can use kubectl commands like I do for the rest of the post here. As a start, we will see the deployment details.
kubectl describe deployment my-hello-go -n medium
I am not going to paste full output here, instead I’ll post a screenshot of related properties that I’m going to explain.
As you can see, we are referring an image with a particular tag to create a container inside a Pod. If you search this image you should be able to find it in Docker Hub. In that docker image page, it has mentioned what are the ports that are exposed and the service endpoints. So, when we package this Docker image inside our Helm chart, we have to make sure those services and endpoints are reachable using the given ports. That is why we override necessary details in the Helm chart values.yaml file.
Other than the values.yaml file, you have to update the deployment.yaml template as well to open the container port and the liveliness and readiness probes.
I believe now you got some understanding the connection between the Helm chart and the related Docker image. Now the time is to find the relationship with the Docker image and the service that runs inside it.
If you click on the docker image tag and the inspect the layers, you will be able to understand the details such as, service written using Go language, the version of the Go, exposed ports and so on. Following is the code used in Go application.
func main() {
http.HandleFunc("/hi", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hej")
})
log.Fatal(http.ListenAndServe(":8081", nil))
}
To summarize, what we write as a service will decide the platform application runs, dependencies or the frameworks, endpoints and ports. We have to containerized those things with a help of containerized application like Docker and then we need to orchestrate it in an environment with the help of an application like Kubernetes.