helm updates, build updates
Build and Publish Docker Image / Build and Push Docker Image (push) Successful in 1m8s Details

This commit is contained in:
Isaac Johnson 2026-07-24 06:17:10 -05:00
parent 62e55446fe
commit 68d0c8aad4
15 changed files with 427 additions and 86 deletions

View File

@ -0,0 +1,90 @@
name: Build and Publish Docker Image
on:
push:
branches:
- main
jobs:
build-and-push:
name: Build and Push Docker Image
runs-on: my_custom_label
container: node:22
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Prepare Env for Docker
run: |
whoami
which docker || true
apt update
cat /etc/os-release
apt install -y ca-certificates curl gnupg
mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
focal stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
DEBIAN_FRONTEND=noninteractive apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
- name: Get Version from version.ini
id: get_version
run: |
# Extract version value from version.ini
VERSION=$(awk -F'=[ \t]*' '/^version[ \t]*=/ {gsub(/[ \t"'\''\r]/, "", $2); print $2}' version.ini)
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Build Dockerfile
run: |
export BUILDIMGTAG="`cat Dockerfile | tail -n1 | sed 's/^.*\///g'`"
docker build -t $BUILDIMGTAG:${{ env.VERSION }} .
docker images
- name: Tag and Push (Harbor)
run: |
export BUILDIMGTAG="`cat Dockerfile | tail -n1 | sed 's/^.*\///g'`"
export FINALBUILDTAG="`cat Dockerfile | tail -n1 | sed 's/^#//g'`"
docker tag $BUILDIMGTAG:${{ env.VERSION }} $FINALBUILDTAG:${{ env.VERSION }}
docker images
echo $CR_PAT | docker login harbor.freshbrewed.science -u $CR_USER --password-stdin
docker push $FINALBUILDTAG:${{ env.VERSION }}
env: # Or as an environment variable
CR_PAT: ${{ secrets.CR_PAT }}
CR_USER: ${{ secrets.CR_USER }}
- name: Tag and Push (Dockerhub)
run: |
export BUILDIMGTAG="`cat Dockerfile | tail -n1 | sed 's/^.*\///g'`"
docker tag $BUILDIMGTAG:${{ env.VERSION }} $DHUSER/$BUILDIMGTAG:${{ env.VERSION }}
docker images
echo $DHPAT | docker login -u $DHUSER --password-stdin
docker push $DHUSER/$BUILDIMGTAG:${{ env.VERSION }}
env: # Or as an environment variable
DHPAT: ${{ secrets.DHPAT }}
DHUSER: ${{ secrets.DHUSER }}
- name: Prepare Env for Helm OCI Push (Helm v3 reference only)
run: |
if [ ! -f /tmp/linux-amd64/helm ]; then
apt update
DEBIAN_FRONTEND=noninteractive apt-get install -y unzip curl || true
wget https://get.helm.sh/helm-v3.14.0-linux-amd64.tar.gz -O /tmp/helm.tar.gz || true
cd /tmp
tar xzvf helm.tar.gz
chmod +x linux-amd64/helm
fi
- name: Package Helm Chart
run: |
set -x
/tmp/linux-amd64/helm package ./helm-chart
export HLMPKG=`ls -tr *.tgz | tail -n1 | tr -d '\n'`
/tmp/linux-amd64/helm registry login harbor.freshbrewed.science -u $CR_USER -p $CR_PAT
/tmp/linux-amd64/helm push ./$HLMPKG oci://harbor.freshbrewed.science/chartrepo/k8s-pulse
env: # Or as an environment variable
CR_PAT: ${{ secrets.CR_PAT }}
CR_USER: ${{ secrets.CR_USER }}

View File

@ -10,3 +10,4 @@ COPY . .
EXPOSE 5000 EXPOSE 5000
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"] CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
#harbor.freshbrewed.science/library/k8s-pulse

13
docker-compose.yml Normal file
View File

@ -0,0 +1,13 @@
services:
k8s-pulse:
build:
context: .
dockerfile: Dockerfile
container_name: k8s-pulse
ports:
- "5000:5000"
environment:
- KUBECONFIG=/root/.kube/config
volumes:
- ${KUBECONFIG:-~/.kube/config}:/root/.kube/config:ro
restart: unless-stopped

View File

@ -1,6 +1,6 @@
apiVersion: v2 apiVersion: v2
name: K8sMonitor name: k8s-pulse
description: A Helm chart for a containerized python web app. description: A Helm chart for k8s-pulse, a Kubernetes cluster resource visualizer.
type: Project type: application
version: 0.1.0 version: 0.1.0
appVersion: "1.0.0" appVersion: "1.0.0"

View File

@ -1,78 +1,79 @@
# K8sMonitor Helm Chart # k8s-pulse Helm Chart
This Helm chart provides a standardized way to deploy the **K8sMonitor** python web application on a Kubernetes cluster. This Helm chart provides a production-ready Kubernetes deployment for **k8s-pulse**, a Python web application that visualizes cluster metrics and resource usage.
## Prerequisites ## Prerequisites
- A running Kubernetes cluster. - A running Kubernetes cluster (v1.19+ recommended).
- [Helm](https://helm.sh/) installed on your local machine or CI/CD runner. - [Helm v3](https://helm.sh/) installed.
- Access to a container registry where the `python-web-app` image is stored (if using a custom image). - (Optional) Metrics Server installed in your cluster for detailed container CPU & memory usage.
## Getting Started ## Quick Start
### 1. Prepare the Configuration ### 1. Install the Chart
The default configuration can be found in `values.yaml`. You can override any value here before installing or pass them via `--set` or `-f <file>`.
Example of modifying ingress annotations: To install the chart with default release name `k8s-pulse`:
```yaml
ingress:
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
```
### 2. Install the Chart
To install the chart using the default values:
```bash ```bash
helm install k8smonitor ./helm-chart helm install k8s-pulse ./helm-chart
``` ```
To install with a custom values file: ### 2. Custom Configuration
You can override default settings by passing a custom `values.yaml` file or using `--set`:
```bash ```bash
helm install k8smonitor ./helm-chart -f custom-values.yaml helm install k8s-pulse ./helm-chart -f custom-values.yaml
``` ```
### 3. Upgrade the Chart Example: Enable Ingress and change image tag:
To update your installation with newer configuration or version:
```bash ```bash
helm upgrade k8smonitor ./helm-chart helm install k8s-pulse ./helm-chart \
--set image.tag="1.0.0" \
--set ingress.enabled=true \
--set ingress.hosts[0].host="k8s-pulse.example.com"
``` ```
## Configuration Options ### 3. Upgrade the Release
| Value | Description | Default | ```bash
|------|-------------|---------| helm upgrade k8s-pulse ./helm-chart
| `replicaCount` | Number of desired pods | 2 | ```
| `image.repository` | The Docker image to pull | python-web-app |
| `service.port` | The port the service listens on | 80 | ### 4. Uninstall
| `ingress.enabled` | Enable or disable Ingress | true |
| `persistence.size` | Size of the PersistentVolumeClaim | 1Gi | ```bash
helm uninstall k8s-pulse
```
## Configuration Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `replicaCount` | Number of application replicas | `1` |
| `image.repository` | Docker image repository | `k8s-pulse` |
| `image.tag` | Docker image tag | `latest` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
| `service.type` | Kubernetes service type | `ClusterIP` |
| `service.port` | Service port exposed | `80` |
| `service.targetPort` | Container application port | `5000` |
| `rbac.create` | Create ClusterRole & ClusterRoleBinding for K8s API access | `true` |
| `serviceAccount.create` | Create ServiceAccount for the deployment | `true` |
| `serviceAccount.name` | Explicit ServiceAccount name | `""` |
| `ingress.enabled` | Enable Ingress resource | `false` |
| `resources` | Pod CPU/Memory resource limits & requests | `{ limits: { cpu: 200m, memory: 256Mi }, requests: { cpu: 100m, memory: 128Mi } }` |
| `persistence.enabled` | Enable optional PersistentVolumeClaim | `false` |
## RBAC Requirements
`k8s-pulse` requires read access to cluster nodes, pods, and `metrics.k8s.io` custom objects. By default, `rbac.create: true` creates a `ClusterRole` and `ClusterRoleBinding` bound to the pod's `ServiceAccount`.
## Verification ## Verification
Once installed, you can check the status of your deployment: Check the deployment status:
```bash ```bash
# List all pods for the app kubectl get pods -l app.kubernetes.io/name=k8s-pulse
kubectl get pods -l app=k8smonitor kubectl get svc -l app.kubernetes.io/name=k8s-pulse
# Check the service
kubectl get svc k8smonitor
# Check the ingress
kubectl get ingress k8smonitor
```
## Troubleshooting
If the pod is not running, check the logs:
```bash
kubectl logs -l app=k8smonitor
```
Check for events in the namespace:
```bash
kubectl get events --sort-by=.metadata.creationTimestamp
``` ```

View File

@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "k8s-pulse.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "k8s-pulse.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "k8s-pulse.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "k8s-pulse.labels" -}}
helm.sh/chart: {{ include "k8s-pulse.chart" . }}
{{ include "k8s-pulse.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "k8s-pulse.selectorLabels" -}}
app.kubernetes.io/name: {{ include "k8s-pulse.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "k8s-pulse.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "k8s-pulse.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,15 @@
{{- if .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "k8s-pulse.fullname" . }}
labels:
{{- include "k8s-pulse.labels" . | nindent 4 }}
rules:
- apiGroups: [""]
resources: ["nodes", "pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["metrics.k8s.io"]
resources: ["nodes", "pods"]
verbs: ["get", "list"]
{{- end }}

View File

@ -0,0 +1,16 @@
{{- if .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "k8s-pulse.fullname" . }}
labels:
{{- include "k8s-pulse.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "k8s-pulse.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "k8s-pulse.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}

View File

@ -1,29 +1,74 @@
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: {{ include "k8smonitor.fullname" . }} name: {{ include "k8s-pulse.fullname" . }}
labels: labels:
{{- include "k8smonitor.selectorLabels" . | nindent 4 }} {{- include "k8s-pulse.labels" . | nindent 4 }}
spec: spec:
replicas: {{ .Values.replicaCount }} replicas: {{ .Values.replicaCount }}
selector: selector:
matchLabels: matchLabels:
{{- include "k8smonitor.selectorLabels" . | nindent 6 }} {{- include "k8s-pulse.selectorLabels" . | nindent 6 }}
template: template:
metadata: metadata:
labels: labels:
{{- include "k8smonitor.selectorLabels" . | nindent 8 }} {{- include "k8s-pulse.selectorLabels" . | nindent 8 }}
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec: spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "k8s-pulse.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers: containers:
- name: {{ .Chart.Name }} - name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports: ports:
- name: http - name: http
containerPort: {{ .Values.service.port }} containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
periodSeconds: 10
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- if .Values.persistence.enabled }}
volumeMounts: volumeMounts:
- name: data - name: data
mountPath: /app/data mountPath: /app/data
{{- end }}
{{- if .Values.persistence.enabled }}
volumes: volumes:
- name: data - name: data
persistentVolumeClaim: persistentVolumeClaim:
claimName: {{ include "k8smonitor.fullname" . }}-data claimName: {{ include "k8s-pulse.fullname" . }}-data
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@ -1,18 +1,45 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "k8s-pulse.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
metadata: metadata:
name: {{ include "k8smonitor.fullname" . }} name: {{ $fullName }}
labels:
{{- include "k8s-pulse.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations: annotations:
{{- toYaml .Values.ingress.annotations | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }}
spec: spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules: rules:
- host: {{ index .Values.ingress.hosts 0 .host | default "k8smonitor.local" }} {{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http: http:
path: paths:
- path: / {{- range .paths }}
pathType: ImplementationSpecific - path: {{ .path }}
{{- if .pathType }}
pathType: {{ .pathType }}
{{- end }}
backend: backend:
service: service:
name: {{ include "k8smonitor.fullname" . }} name: {{ $fullName }}
port: port:
number: {{ .Values.service.port }} number: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -1,10 +1,17 @@
{{- if .Values.persistence.enabled -}}
apiVersion: v1 apiVersion: v1
kind: PersistentVolumeClaim kind: PersistentVolumeClaim
metadata: metadata:
name: {{ include "k8smonitor.fullname" . }}-data name: {{ include "k8s-pulse.fullname" . }}-data
labels:
{{- include "k8s-pulse.labels" . | nindent 4 }}
spec: spec:
accessModes: accessModes:
- ReadWriteOnce - {{ .Values.persistence.accessMode | default "ReadWriteOnce" }}
resources: resources:
requests: requests:
storage: {{ .Values.persistence.size }} storage: {{ .Values.persistence.size }}
{{- if .Values.persistence.storageClassName }}
storageClassName: {{ .Values.persistence.storageClassName | quote }}
{{- end }}
{{- end }}

View File

@ -1,12 +1,19 @@
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: {{ include "k8smonitor.fullname" . }} name: {{ include "k8s-pulse.fullname" . }}
labels:
{{- include "k8s-pulse.labels" . | nindent 4 }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec: spec:
type: {{ .Values.service.type }} type: {{ .Values.service.type }}
ports: ports:
- name: http - port: {{ .Values.service.port }}
port: {{ .Values.service.port }} targetPort: {{ .Values.service.targetPort }}
targetPort: http protocol: TCP
name: http
selector: selector:
{{- include "k8smonitor.selectorLabels" . | nindent 6 }} {{- include "k8s-pulse.selectorLabels" . | nindent 4 }}

View File

@ -0,0 +1,12 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "k8s-pulse.serviceAccountName" . }}
labels:
{{- include "k8s-pulse.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@ -1,25 +1,68 @@
replicaCount: 2 # Default values for k8s-pulse.
replicaCount: 1
image: image:
repository: python-web-app repository: k8s-pulse
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "latest" tag: "latest"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
rbac:
create: true
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext: {}
securityContext: {}
service: service:
type: ClusterIP type: ClusterIP
port: 80 port: 80
targetPort: 5000
annotations: {}
ingress: ingress:
enabled: true enabled: false
className: ""
annotations: {}
hosts: hosts:
- host: k8smonitor.local - host: k8s-pulse.local
paths: paths:
- path: / - path: /
pathType: ImplementationSpecific pathType: Prefix
annotations: tls: []
kubernetes.io/ingress.nginx._tls.k8smonitor.local: "cert-manager-challenge"
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
persistence: persistence:
enabled: true enabled: false
size: 1Gi size: 1Gi
storageClassName: standard accessMode: ReadWriteOnce
storageClassName: ""
nodeSelector: {}
tolerations: []
affinity: {}

2
version.ini Normal file
View File

@ -0,0 +1,2 @@
[metadata]
version = 0.1