zheludov.com:/$ blog creating-generic-helm-chart-for-web-app
// 2023-11-20
This blog post will guide you through creating a Helm chart for a generic web application. We'll cover how to include a deployment, service, NGINX ingress, and a horizontal pod autoscaler in your Helm chart.
Helm is a Kubernetes package manager that simplifies deploying and managing applications. Helm charts are templates used to deploy applications, defining necessary Kubernetes resources.
First, ensure Helm is installed:
helm version
Then, create a new chart:
helm create webapp
This command creates a new directory webapp with the structure for your chart.
Chart.yaml
: Contains metadata about your chart.values.yaml
: Defines default values for your chart.templates/
: Kubernetes resource templates.This Helm chart contains several key Kubernetes resources, each serving a specific purpose in deploying and managing your web application. Below is a breakdown of these resources and the modifications we'll make:
Deployment: The Deployment resource is crucial for managing the stateless pods of your web application. It ensures that a specified number of pod replicas are running and handles rolling updates to your application. In the deployment.yaml
file, we will customize the container image, set the desired number of replicas, and define necessary environment variables for your application.
Service: The Service resource exposes your application within the Kubernetes cluster or to the external world. It provides a stable endpoint for accessing the pods managed by the Deployment. In the service.yaml
file, we'll specify the type of service (like ClusterIP or LoadBalancer) and configure the ports through which the application is accessible.
Ingress: If external access to your web application is required, the Ingress resource comes into play. It manages external access to the services in the cluster, providing load balancing, SSL termination, and host-based routing. In the ingress.yaml
file, we'll define the rules for routing external traffic to your service, including hostnames and paths.
Horizontal Pod Autoscaler (HPA): The HPA automatically adjusts the number of pod replicas in the Deployment based on observed CPU utilization or other selected metrics. This ensures that your application scales properly in response to traffic. In the hpa.yaml
file, we'll set up scaling policies, including the minimum and maximum number of replicas and the target CPU utilization for scaling.
Each of these resources is defined in a template file in the templates/
directory of your Helm chart. We'll make specific changes to these files to tailor the deployment process of your web application. These changes will ensure that your application is deployed with the right settings, resources, and scaling behavior to meet your requirements.
With these resources and configurations in place, your Helm chart will be a powerful tool for deploying and managing your web application in a Kubernetes environment.
Now, let's dive into the specifics of customizing each resource...
Location: templates/deployment.yaml
Parameters:
Container Image: Define the Docker image for your web application's container.
Replica Count: Set the number of pod replicas to run.
Environment Variables: Configure environment variables as key-value pairs.
Resource Requests and Limits: Specify the CPU and memory usage for the container.
Readiness and Liveness Probes: Set up health checks for your application.
Volume Mounts: Configure one or more volumes for your container.
Example Deployment Configuration:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "webapp.fullname" . }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ include "webapp.fullname" . }}
template:
metadata:
labels:
app: {{ include "webapp.fullname" . }}
spec:
containers:
- name: {{ .Values.container.name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: {{ .Values.container.port }}
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value }}
{{- end }}
resources:
requests:
memory: {{ .Values.resources.requests.memory }}
cpu: {{ .Values.resources.requests.cpu }}
limits:
memory: {{ .Values.resources.limits.memory }}
cpu: {{ .Values.resources.limits.cpu }}
livenessProbe:
httpGet:
path: {{ .Values.livenessProbe.path }}
port: {{ .Values.livenessProbe.port }}
readinessProbe:
httpGet:
path: {{ .Values.readinessProbe.path }}
port: {{ .Values.readinessProbe.port }}
volumeMounts:
{{- range .Values.volumes }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
{{- end }}
volumes:
{{- range .Values.volumes }}
- name: {{ .name }}
{{- with .configMap }}
configMap:
name: {{ .name }}
items:
{{- range .items }}
- key: {{ .key }}
path: {{ .path }}
{{- end }}
{{- end }}
{{- end }}
Example Values Configuration for deployment:
In values.yaml
, define the values for images, environment variables, resources, probes, and volumes for potentially multiple containers:
replicaCount: 3
container:
name: webapp
port: 80
image:
repository: your-webapp-image
tag: latest
env:
ENV_VAR_NAME: "Value"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
path: /health
port: 80
readinessProbe:
path: /health
port: 80
volumes:
- name: config-vol
mountPath: /etc/config
configMap:
name: log-config
items:
- key: log_level
path: log_level
Location: templates/service.yaml
Parameters:
Service Type: Specify the type of service (e.g., ClusterIP, NodePort, LoadBalancer).
Port Configuration: Define the ports and target ports for the service.
Example Service Configuration:
apiVersion: v1
kind: Service
metadata:
name: {{ include "webapp.fullname" . }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.container.port }}
protocol: TCP
selector:
app: {{ include "webapp.fullname" . }}
Example Values Configuration for Service:
service:
type: ClusterIP
port: 80
Location: templates/ingress.yaml
Parameters:
Hosts: Define the hostnames for the ingress rules.
Paths: Specify the paths and corresponding backend services.
Example Ingress Configuration:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "webapp.fullname" . }}
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: Prefix
backend:
service:
name: {{ include "webapp.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
Example Values Configuration for Ingress:
ingress:
hosts:
- host: "example.com"
paths:
- path: "/"
Location: templates/hpa.yaml
Parameters:
Example HPA Configuration:
apiVersion: autoscaling/v2beta2
kind: HorizontalPod Autoscaler
metadata:
name: {{ include "webapp.fullname" . }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "webapp.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
Example Values Configuration for HPA:
autoscaling:
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
targetMemoryUtilizationPercentage: 75
When effectively utilizing an HPA for a web application, it's crucial to consider both the application's resource usage patterns and its request volume. Initially, you should set the HPA metrics (CPU and memory utilization percentages) based on typical usage under average load. Monitoring tools can help you understand these patterns. For instance, if your application is memory-intensive, setting a lower target for memory utilization in the HPA configuration will ensure timely scaling. Conversely, for CPU-intensive applications, the CPU utilization threshold is more critical. Additionally, it's important to consider the request volume. Metrics like the number of concurrent users or requests per second can be indicative of the load. Using custom metrics from Kubernetes metrics servers can provide more insight into scaling based on request volume. I will dive into scaling web application based on custom metrics in the future article.
Before deploying your Helm chart, it's essential to test it to ensure that it generates the correct Kubernetes resources. You can do this using the helm template
command. This command renders your templates locally and outputs the generated Kubernetes manifests, allowing you to verify their correctness.
Run the following command in the root directory of your Helm chart:
helm template .
Examine the output to ensure that all resources (Deployments, Services, Ingress, and HPA) are correctly configured and that values from values.yaml are properly substituted. Pay special attention to your customizations, like environment variables, resource requests and limits, and metrics for HPA.
Once you're satisfied with the output of the helm template command, you can proceed to deploy your Helm chart in your Kubernetes cluster. Use the helm install
command for this purpose:
helm install my-webapp-release .
Replace my-webapp-release
with a name for your deployment. This command deploys your web application to the Kubernetes cluster, creating all the necessary resources as defined in your chart.
Creating a Helm chart for a web application involves careful planning and attention to detail. By customizing your chart for Deployments, Services, Ingress, and HPAs, you can ensure that your application scales efficiently and remains stable under different loads. Testing the chart with helm template helps catch issues before deployment, and careful monitoring after deployment ensures optimal performance. Remember, Helm charts are not only about deploying your application but also about maintaining it effectively in a Kubernetes environment. With this Helm chart in place, you have taken a significant step towards a robust and scalable deployment strategy for your web application.
Full helm chart can be found here: https://github.com/alex-zheludov/helm-generic-web
Type 'blog' + Enter -- to get a list of my blog posts.