- TechOps Examples
- Posts
- How to use One Helm Chart for EKS and GKE
How to use One Helm Chart for EKS and GKE
Today’s Agenda :
How to use One Helm Chart for EKS and GKE
Kubernetes RBAC Best Practices and Tooling Collection
Useful Git Shortcuts and Autocomplete for Windows Bash Terminal
Red Hat OpenShift GitOps 1.12: Key Updates and Enhancements
Google Cloud Functions and Docker Engine Critical Flaws Exposed
Read Time: 4 minutes
How to use One Helm Chart for EKS and GKE
Namasthe 🙏 TechOps Soldiers !
I get this question a lot: "Can we use a single Helm chart for both EKS and GKE?"
The answer is a resounding yes!
Today, I'm going to walk you through how to do just that with a real-world example of an e-commerce application called ecom-app
.
First, let's break down the sample structure of a Helm chart and understand the role of each file.

Helm Chart Structure
Now, let's dive into the actual code that makes all this happen.
chart.yaml:
This file is like the blueprint of our Helm chart. It gives Kubernetes all the information it needs about our chart.
apiVersion: v2
name: ecom-app
description: A Helm chart for a production-grade e-commerce application
type: application
version: 1.0.0
appVersion: "1.0"
values.yaml:
Here, we define the default configuration values. These are the settings that work for both EKS and GKE unless overridden.
replicaCount: 3
backend:
image:
repository: ecom-app/backend
tag: "1.0.0"
pullPolicy: Always
frontend:
image:
repository: nginx
tag: "1.19.0"
pullPolicy: IfNotPresent
service:
type: LoadBalancer
port: 80
ingress:
enabled: true
annotations: {}
hosts:
- host: ecom.example.com
paths:
- /
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "200m"
nodeSelector: {}
tolerations: []
affinity: {}
persistence:
enabled: true
accessMode: ReadWriteOnce
size: 10Gi
deployment-backend.yaml:
This template is for deploying our backend service. It ensures our backend containers run smoothly, with all the necessary configurations.
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "ecom-app.fullname" . }}-backend
labels:
app: {{ include "ecom-app.name" . }}
tier: backend
release: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ include "ecom-app.name" . }}
tier: backend
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ include "ecom-app.name" . }}
tier: backend
release: {{ .Release.Name }}
spec:
containers:
- name: backend
image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}"
imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
resources:
requests:
memory: {{ .Values.resources.requests.memory }}
cpu: {{ .Values.resources.requests.cpu }}
limits:
memory: {{ .Values.resources.limits.memory }}
cpu: {{ .Values.resources.limits.cpu }}
deployment-frontend.yaml:
Our frontend service uses Nginx. This deployment template handles all the settings needed to run our frontend containers.
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "ecom-app.fullname" . }}-frontend
labels:
app: {{ include "ecom-app.name" . }}
tier: frontend
release: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ include "ecom-app.name" . }}
tier: frontend
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ include "ecom-app.name" . }}
tier: frontend
release: {{ .Release.Name }}
spec:
containers:
- name: frontend
image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}"
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
ports:
- containerPort: 80
service.yaml:
This template sets up the Kubernetes Service. It defines how our application will be accessible over the network.
apiVersion: v1
kind: Service
metadata:
name: {{ include "ecom-app.fullname" . }}
labels:
app: {{ include "ecom-app.name" . }}
release: {{ .Release.Name }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: 80
selector:
app: {{ include "ecom-app.name" . }}
release: {{ .Release.Name }}
ingress.yaml:
Ingress resources control external access to our services. This template handles the settings needed to expose our application outside the Kubernetes cluster.
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "ecom-app.fullname" . }}
annotations:
{{- range $key, $value := .Values.ingress.annotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
spec:
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host }}
http:
paths:
{{- range .paths }}
- path: {{ . }}
pathType: Prefix
backend:
service:
name: {{ include "ecom-app.fullname" $ }}
port:
number: 80
{{- end }}
{{- end }}
{{- end }}
pvc.yaml:
This template defines the PersistentVolumeClaim, which is used to request storage resources in Kubernetes.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "ecom-app.fullname" . }}-pvc
labels:
app: {{ include "ecom-app.name" . }}
release: {{ .Release.Name }}
spec:
accessModes:
- {{ .Values.persistence.accessMode }}
resources:
requests:
storage: {{ .Values.persistence.size }}
_helpers.tpl:
This file contains reusable code snippets. It helps keep our templates DRY (Don't Repeat Yourself) by providing common functions.
{{- define "ecom-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "ecom-app.fullname" -}}
{{- printf "%s-%s" .Release.Name (include "ecom-app.name" .) | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "ecom-app.chart" -}}
{{- .Chart.Name | replace "-" " " | title | replace " " "-" -}}
{{- end -}}
values-eks.yaml:
These are the settings specific to EKS. They override the defaults in values.yaml
to suit AWS's Kubernetes service.
replicaCount: 3
service:
type: LoadBalancer
persistence:
storageClass: gp2
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "500m"
values-gke.yaml:
Similarly, these are the settings specific to GKE. They make sure our application runs smoothly on Google's Kubernetes service.
replicaCount: 3
service:
type: LoadBalancer
persistence:
storageClass: standard
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "500m"
Ready to deploy? Here’s how you can get your e-commerce app up and running on both EKS and GKE.
To deploy on EKS:
helm install ecom-app ./ecom-app -f values-eks.yaml
To deploy on GKE:
helm install ecom-app ./ecom-app -f values-gke.yaml
By using this structure and configuration, you can efficiently manage your Kubernetes deployments across both EKS and GKE with a single Helm chart.
Happy deploying!
📖 Resources & Tutorials
📈 Trends & Updates
The ConfusedFunction vulnerability in Google Cloud Functions allows attackers to escalate privileges and access sensitive data. Google's recent updates mitigate the issue for new deployments, but existing instances remain vulnerable.
The 1.12 release of Red Hat OpenShift GitOps introduces ArgoCD CLI support, enhanced NotificationsConfiguration, and critical fixes for TLS policies and secure authentication. These updates improve automation, security, and user experience for cloud-native deployments.
Docker has identified a critical vulnerability, CVE-2024-41110, allowing attackers to bypass authorization plugins and escalate privileges in certain versions of Docker Engine. With a maximum CVSS score of 10.0, this flaw has been patched in recent updates, and users are urged to upgrade to prevent potential exploits.
Want To Advertise in TechOps Examples ?
Our newsletter puts your products and services in front of the right people - engineering leaders and senior engineers - who make important tech decisions and big purchases.
Did someone forward this email to you? Sign up here