Github Pages as Helm Chart Repository
Helm, a powerful package manager for Kubernetes, simplifies application deployment and management. GitHub Pages provides an easy and free hosting solution for Helm charts. This guide will walk you through setting up a Helm chart repository using GitHub Pages and uploading your charts.
GitHub offers a comprehensive solution for managing Kubernetes applications. By leveraging GitHub Pages for Helm charts and GitHub Container Registry for Docker images, you can centralize your application assets and automate your deployment workflows. This GitHub-centric approach creates a robust GitOps pipeline, streamlining development, deployment, and dependency management.
Create a simple Flask Application
To demonstrate this setup, let’s start with a minimal web application built with Flask. The application will be packaged and deployed via Helm charts.
app.py
import json
from flask import Flask, jsonify
app = Flask(__name__)
products = [
{ 'id': 1, 'name': 'Cakes' },
{ 'id': 2, 'name': 'Cookies' },
{ 'id': 3, 'name': 'Chocolates' },
{ 'id': 4, 'name': 'Milk' },
{ 'id': 5, 'name': 'Coffee' },
{ 'id': 6, 'name': 'Soft Drinks' },
{ 'id': 7, 'name': 'Ice cream' }
]
@app.route('/api/products', methods=['GET'])
def get_products():
return jsonify(products)
if __name__ == '__main__':
app.run(debug=True)
This application provides a simple API endpoint (/api/products
) that returns a list of products, making it ideal for testing Helm and Docker integration.
requirements.txt
This file specifies the Python dependencies needed for the Flask application.
flask
Containerize the Flask Application
Now, we’ll create a Docker image for the Flask app to ensure consistent behavior across environments.
Dockerfile
The Dockerfile specifies the instructions for creating the Docker image.
# syntax=docker/dockerfile:1
FROM python:3.12.4-slim
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip3 install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD [ "python", "-m" , "flask", "run", "--host=0.0.0.0"]
This Dockerfile uses a lightweight Python base image, sets up a working directory, installs Flask, exposes port 5000, and runs the app.
Create Helm Chart for the Application
To package the application for Kubernetes deployment, we'll create a Helm chart. Use the Helm command to generate a new chart.
helm create charts/python-api
This command generates a Helm chart structure. We’ll keep only the relevant files for this setup:
python-api/
├── Chart.yaml
├── values.yaml
└── templates/
├── deployment.yaml
└── service.yaml
└── ingress.yaml
Chart.yaml
Chart.yaml includes the chart’s name, description, version, and application version. These fields provide essential metadata for Helm.
apiVersion: v2
name: python-api
description: A Helm chart for python-api demo
type: application
version: 0.1.1
appVersion: "0.1.1"
maintainers:
- name: sarubhai
email: saurav.karate@gmail.com
keywords:
- helm-ghcr-gh-pages-demo
- python-api-demo
values.yaml
This YAML file configures the Helm chart, with default values including details like replica count, service type, and ingress.
replicaCount: 1
imagePullSecrets: []
image:
repository: ""
tag: ""
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: python-api.local
paths:
- path: /
pathType: Prefix
tls:
- secretName: python-api-tls
hosts:
- python-api.local
deployment.yaml
This YAML file defines the deployment of the Flask application on Kubernetes, specifying the number of replicas and container image
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-api-deployment
labels:
app: python-api-deployment
app.kubernetes.io/name: python-api-deployment
app.kubernetes.io/version: v1.0
spec:
replicas: \{\{ .Values.replicaCount }}
selector:
matchLabels:
app: python-api
app.kubernetes.io/name: python-api
template:
metadata:
labels:
app: python-api
app.kubernetes.io/name: python-api
spec:
\{\{- with .Values.imagePullSecrets }}
imagePullSecrets:
\{\{- toYaml . | nindent 8 }}
\{\{- end }}
containers:
- name: python-api
image: "\{\{ .Values.image.repository }}:\{\{ .Values.image.tag }}"
imagePullPolicy: \{\{ .Values.image.pullPolicy }}
ports:
- containerPort: 5000
name: flask
protocol: TCP
service.yaml
This YAML file defines a Kubernetes service that exposes the Flask application through a port.
apiVersion: v1
kind: Service
metadata:
name: python-api-service
labels:
app: python-api-service
app.kubernetes.io/name: python-api-service
app.kubernetes.io/version: v1.0
spec:
type: \{\{ .Values.service.type }}
selector:
app: python-api
ports:
- name: http
protocol: TCP
port: \{\{ .Values.service.port }}
targetPort: 5000
ingress.yaml
This YAML file defines an Ingress resource that provides an external entrypoint for the application through a hostname and path.
\{\{- if .Values.ingress.enabled -}}
\{\{- $svcPort := .Values.service.port -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: python-api-ingress
namespace: backend-api
labels:
app: python-api-ingress
app.kubernetes.io/name: python-api-ingress
app.kubernetes.io/version: v1.0
\{\{- with .Values.ingress.annotations }}
annotations:
\{\{- toYaml . | nindent 4 }}
\{\{- end }}
spec:
ingressClassName: \{\{ .Values.ingress.className }}
rules:
\{\{- range .Values.ingress.hosts }}
- host: \{\{ .host }}
http:
paths:
\{\{- range .paths }}
- backend:
service:
name: python-api-service
port:
number: \{\{ $svcPort }}
path: \{\{ .path }}
pathType: \{\{ .pathType }}
\{\{- end }}
\{\{- end }}
\{\{- if .Values.ingress.tls }}
tls:
\{\{- range .Values.ingress.tls }}
- hosts:
\{\{- range .hosts }}
- \{\{ . }}
\{\{- end }}
secretName: \{\{ .secretName }}
\{\{- end }}
\{\{- end }}
\{\{- end }}
Setup GitHub Repository for Helm Charts
- Create a new GitHub repository (e.g., helm-repo-with-gh-pages-gcr). This will serve as both our Helm repository and the project’s source code. This can be private or public.
- Next create a branch named "gh-pages" for publishing the helm charts.
- Finally we will configure the Github Pages:
In your repository, go toSettings > Pages
, select your branchgh-pages
, and set
as the source directory./root
Now that we have our main branch where it receives the helms charts and gh-pages branch where the index will be published.
GitHub Container Registry provides a straightforward way to host Docker images within GitHub. This integration enables you to manage your Docker containers and Helm Charts in a unified workflow.
Automate Publishing with GitHub Actions
GitHub Actions can automate the building and publishing Docker images and Helm charts, whenever you push changes to the repository.
.github/workflows/release.yaml
name: Release Helm Chart
on:
push:
branches:
- main
env:
REGISTRY: ghcr.io
IMAGE_NAME: $\{\{ github.repository }}
jobs:
build:
name: Github Pages as Helm Chart Repository
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: $\{\{ env.REGISTRY }}
username: $\{\{ github.actor }}
password: $\{\{ secrets.GITHUB_TOKEN }}
- name: Build and Push Docker image to GitHub Container Registry
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
$\{\{ env.REGISTRY }}/$\{\{ env.IMAGE_NAME }}:latest
$\{\{ env.REGISTRY }}/$\{\{ env.IMAGE_NAME }}:$\{\{ github.sha }}
- name: Install YQ
uses: dcarbone/install-yq-action@v1.2.0
- name: Update values.yaml with Latest Image Tag
run: |
yq eval --inplace ".image.repository = \"$\{\{ env.REGISTRY }}/$\{\{ env.IMAGE_NAME }}\"" charts/python-api/values.yaml
yq eval --inplace ".image.tag = \"$\{\{ github.sha }}\"" charts/python-api/values.yaml
- name: Configure Git
run: |
git config user.name "GitHub Action"
git config user.email "action@github.com"
- name: Install Helm
uses: azure/setup-helm@v3
with:
version: v3.7.0
- name: Run chart-releaser to Package and Release Helm Charts
uses: helm/chart-releaser-action@v1.6.0
env:
CR_TOKEN: $\{\{ secrets.GITHUB_TOKEN }}
The workflow uses various actions to:
- Login to GitHub Container Registry
- Build and push Docker image to the registry
- Update the
file with the latest image tagvalues.yaml
- Install Helm and use
to package and release Helm charts tochart-releaser
gh-pages
branch
Deploy the Helm Chart to Kubernetes
Once the Helm chart is published to GitHub Pages, you can install it in your Kubernetes cluster:
helm repo add gh-pages-as-helm-repo https://sarubhai.github.io/gh-pages-as-helm-repo
helm search repo gh-pages-as-helm-repo
With the repository added, install the chart in your Kubernetes cluster. Customize deployment options using Helm values (e.g., replica count, ingress)
helm upgrade --install python-api python-api \
--repo https://sarubhai.github.io/gh-pages-as-helm-repo --version 0.1.2 \
--namespace backend-api --create-namespace \
--set replicaCount=2 \
--set ingress.enabled=true \
--set ingress.className=nginx \
--set ingress.annotations."nginx\.ingress\.kubernetes\.io/backend-protocol"=HTTP \
--set-string ingress.annotations."nginx\.ingress\.kubernetes\.io/force-ssl-redirect"=true \
--set "ingress.hosts[0].host=python-api.local" \
--set "ingress.hosts[0].paths[0].path=/,ingress.hosts[0].paths[0].pathType=Prefix" \
--set "ingress.tls[0].hosts[0]=python-api.local" \
--set "ingress.tls[0].secretName=python-api-tls"
Deploy the Helm Chart using ArgoCD
Alternatively you can configure ArgoCD to automatically deploy the Kubernetes resources from the GitHub-hosted Helm repository. Below is an example application.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: python-api
spec:
destination:
name: ''
namespace: backend-api
server: https://kubernetes.default.svc
source:
path: ''
repoURL: https://sarubhai.github.io/gh-pages-as-helm-repo
targetRevision: 0.1.2
chart: python-api
helm:
parameters:
- name: replicaCount
value: '2'
- name: ingress.enabled
value: 'true'
- name: ingress.className
value: nginx
- name: ingress.annotations.nginx\.ingress\.kubernetes\.io/backend-protocol
value: HTTP
- name: ingress.annotations.nginx\.ingress\.kubernetes\.io/force-ssl-redirect
value: '"true"'
- name: ingress.hosts[0].host
value: python-api.local
- name: ingress.hosts[0].paths[0].path
value: /
- name: ingress.hosts[0].paths[0].pathType
value: Prefix
- name: ingress.tls[0].hosts[0]
value: python-api.local
- name: ingress.tls[0].secretName
value: python-api-tls
sources: []
project: default
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
This integrated approach simplifies version control, access management, and automates deployments, making it ideal for small teams and open-source projects. By leveraging Helm charts on GitHub Pages and Docker images in the Github Container Registry, you can efficiently manage your Kubernetes applications and accelerate your CI/CD pipeline.
You can use this https://github.com/sarubhai/gh-pages-as-helm-repo GitHub repository for your reference.