feat: Implement Helm Chart and update CI/CD pipeline
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
This commit is contained in:
@@ -50,33 +50,34 @@ jobs:
|
|||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
# CD PART
|
# CD PART (HELM)
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
- name: Install Kubectl Binary
|
- name: Install Kubectl & Helm
|
||||||
run: |
|
run: |
|
||||||
|
# Install kubectl (ARM64)
|
||||||
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/arm64/kubectl"
|
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/arm64/kubectl"
|
||||||
chmod +x kubectl
|
chmod +x kubectl
|
||||||
sudo mv kubectl /usr/local/bin/
|
sudo mv kubectl /usr/local/bin/
|
||||||
|
|
||||||
- name: Deploy to Kubernetes and Update
|
# Install Helm
|
||||||
|
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||||
|
|
||||||
|
- name: Deploy with Helm
|
||||||
run: |
|
run: |
|
||||||
# 1. Write Kubeconfig content to file
|
# 1. Write Kubeconfig content to file
|
||||||
echo "${{ secrets.KUBE_CONFIG }}" > /tmp/kubeconfig.yaml
|
echo "${{ secrets.KUBE_CONFIG }}" > /tmp/kubeconfig.yaml
|
||||||
|
|
||||||
# 2. Get the new image Digests
|
# 2. Deploy using Helm Upgrade
|
||||||
BACKEND_DIGEST="${{ vars.GITEA_REGISTRY_URL }}/${{ github.repository }}/backend@${{ steps.docker_build_backend.outputs.digest }}"
|
# We pass the image repository and tag explicitly to ensure we use the Gitea registry
|
||||||
FRONTEND_DIGEST="${{ vars.GITEA_REGISTRY_URL }}/${{ github.repository }}/frontend@${{ steps.docker_build_frontend.outputs.digest }}"
|
helm upgrade --install evrak ./deploy/charts/evrak \
|
||||||
|
--kubeconfig /tmp/kubeconfig.yaml \
|
||||||
|
--namespace default \
|
||||||
|
--set backend.image.repository=${{ vars.GITEA_REGISTRY_URL }}/${{ github.repository }}/backend \
|
||||||
|
--set backend.image.tag=latest \
|
||||||
|
--set frontend.image.repository=${{ vars.GITEA_REGISTRY_URL }}/${{ github.repository }}/frontend \
|
||||||
|
--set frontend.image.tag=latest \
|
||||||
|
--set postgres.auth.password=${{ secrets.DB_PASSWORD }}
|
||||||
|
|
||||||
# 3. Update Deployment
|
# 3. Force restart to pick up latest image if tag is 'latest' (Helm doesn't always redeploy if values didn't change)
|
||||||
kubectl set image deployment/evrak-backend backend=${BACKEND_DIGEST} \
|
kubectl rollout restart deployment/evrak-backend --kubeconfig /tmp/kubeconfig.yaml -n default
|
||||||
--kubeconfig=/tmp/kubeconfig.yaml -n default
|
kubectl rollout restart deployment/evrak-frontend --kubeconfig /tmp/kubeconfig.yaml -n default
|
||||||
|
|
||||||
kubectl set image deployment/evrak-frontend frontend=${FRONTEND_DIGEST} \
|
|
||||||
--kubeconfig=/tmp/kubeconfig.yaml -n default
|
|
||||||
|
|
||||||
# 4. Rollout Restart to ensure fresh pods
|
|
||||||
kubectl rollout restart deployment/evrak-backend \
|
|
||||||
--kubeconfig=/tmp/kubeconfig.yaml -n default
|
|
||||||
|
|
||||||
kubectl rollout restart deployment/evrak-frontend \
|
|
||||||
--kubeconfig=/tmp/kubeconfig.yaml -n default
|
|
||||||
|
|||||||
6
deploy/charts/evrak/Chart.yaml
Normal file
6
deploy/charts/evrak/Chart.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: evrak
|
||||||
|
description: A Helm chart for Evrak Project Management System
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "0.1.0"
|
||||||
43
deploy/charts/evrak/templates/_helpers.tpl
Normal file
43
deploy/charts/evrak/templates/_helpers.tpl
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "evrak.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).
|
||||||
|
*/}}
|
||||||
|
{{- define "evrak.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 }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "evrak.labels" -}}
|
||||||
|
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{ include "evrak.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "evrak.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "evrak.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
54
deploy/charts/evrak/templates/backend.yaml
Normal file
54
deploy/charts/evrak/templates/backend.yaml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "evrak.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.backend.replicas }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "evrak.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: backend
|
||||||
|
image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- containerPort: {{ .Values.backend.service.port }}
|
||||||
|
env:
|
||||||
|
- name: DB_HOST
|
||||||
|
value: {{ include "evrak.fullname" . }}-postgres
|
||||||
|
- name: DB_PORT
|
||||||
|
value: {{ .Values.backend.env.dbPort | quote }}
|
||||||
|
- name: DB_USERNAME
|
||||||
|
value: {{ .Values.postgres.auth.username | quote }}
|
||||||
|
- name: DB_DATABASE
|
||||||
|
value: {{ .Values.postgres.auth.database | quote }}
|
||||||
|
- name: DB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "evrak.fullname" . }}-db-secret
|
||||||
|
key: password
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "evrak.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.backend.service.port }}
|
||||||
|
targetPort: {{ .Values.backend.service.port }}
|
||||||
|
selector:
|
||||||
|
{{- include "evrak.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
40
deploy/charts/evrak/templates/frontend.yaml
Normal file
40
deploy/charts/evrak/templates/frontend.yaml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "evrak.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.frontend.replicas }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "evrak.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: frontend
|
||||||
|
image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- containerPort: {{ .Values.frontend.service.port }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "evrak.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.frontend.service.port }}
|
||||||
|
targetPort: {{ .Values.frontend.service.port }}
|
||||||
|
selector:
|
||||||
|
{{- include "evrak.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
32
deploy/charts/evrak/templates/ingress.yaml
Normal file
32
deploy/charts/evrak/templates/ingress.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{{- if .Values.ingress.enabled -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "evrak.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.global.domain }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /api
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "evrak.fullname" . }}-backend
|
||||||
|
port:
|
||||||
|
number: {{ .Values.backend.service.port }}
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "evrak.fullname" . }}-frontend
|
||||||
|
port:
|
||||||
|
number: {{ .Values.frontend.service.port }}
|
||||||
|
{{- end }}
|
||||||
70
deploy/charts/evrak/templates/postgres.yaml
Normal file
70
deploy/charts/evrak/templates/postgres.yaml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "evrak.fullname" . }}-postgres
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "evrak.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
image: "{{ .Values.postgres.image.repository }}:{{ .Values.postgres.image.tag }}"
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
value: {{ .Values.postgres.auth.username | quote }}
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
value: {{ .Values.postgres.auth.database | quote }}
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "evrak.fullname" . }}-db-secret
|
||||||
|
key: password
|
||||||
|
ports:
|
||||||
|
- containerPort: 5432
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "evrak.fullname" . }}-postgres-pvc
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "evrak.fullname" . }}-postgres
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 5432
|
||||||
|
targetPort: 5432
|
||||||
|
selector:
|
||||||
|
{{- include "evrak.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: {{ include "evrak.fullname" . }}-postgres-pvc
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: {{ .Values.postgres.storage.className }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.postgres.storage.size }}
|
||||||
13
deploy/charts/evrak/templates/secrets.yaml
Normal file
13
deploy/charts/evrak/templates/secrets.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "evrak.fullname" . }}-db-secret
|
||||||
|
labels:
|
||||||
|
{{- include "evrak.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
# In a real scenario, you'd want to generate this or pass it in.
|
||||||
|
# For now, we'll use the value from values.yaml (base64 encoded automatically by Helm if we used stringData, but here we do it manually or let user provide it)
|
||||||
|
# Better approach: use stringData
|
||||||
|
stringData:
|
||||||
|
password: {{ .Values.postgres.auth.password | default "postgres" | quote }}
|
||||||
43
deploy/charts/evrak/values.yaml
Normal file
43
deploy/charts/evrak/values.yaml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
global:
|
||||||
|
domain: evrak.konstantiniyye.studio
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image:
|
||||||
|
repository: git.konstantiniyye.studio/muhammed/evrak/backend
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: Always
|
||||||
|
replicas: 1
|
||||||
|
service:
|
||||||
|
port: 3000
|
||||||
|
env:
|
||||||
|
dbPort: 5432
|
||||||
|
dbDatabase: evrak
|
||||||
|
# dbHost, dbUsername, dbPassword will be injected via secrets/templates
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image:
|
||||||
|
repository: git.konstantiniyye.studio/muhammed/evrak/frontend
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: Always
|
||||||
|
replicas: 1
|
||||||
|
service:
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image:
|
||||||
|
repository: postgres
|
||||||
|
tag: "14-alpine"
|
||||||
|
storage:
|
||||||
|
size: 5Gi
|
||||||
|
className: "local-path" # Based on your cluster info
|
||||||
|
auth:
|
||||||
|
username: evrak_user
|
||||||
|
database: evrak
|
||||||
|
# Password should be managed via secrets, but for simplicity in values we can set a default or require it to be passed
|
||||||
|
# In production, use --set postgres.auth.password=...
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: traefik
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod # Assuming you have this, or remove if not
|
||||||
Reference in New Issue
Block a user