feat(charts): add Helm chart for gitks Git bare repository service

- Create Chart.yaml with application metadata and keywords
- Add _helpers.tpl with name, fullname, labels, and DNS template functions
- Generate ConfigMap with all gitks configuration environment variables
- Implement StatefulSet with persistent volume claims for repository data
- Create headless service for pod DNS and cluster communication
- Add gRPC service for client connections and metrics service
- Include HorizontalPodAutoscaler for dynamic scaling
- Add PodDisruptionBudget to maintain cluster availability
- Create ServiceAccount with proper security context
- Add test connection pod using grpcurl for health checks
- Generate NOTES.txt with installation instructions and quick start guide
- Create .helmignore file to exclude common development files
- Configure persistence, resource limits, and security settings
- Add support for cluster mode with etcd service discovery
This commit is contained in:
zhenyi
2026-06-08 21:21:15 +08:00
parent f5044fb099
commit c2487ec0b6
14 changed files with 630 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
Thank you for installing gitks {{ .Chart.AppVersion }}!
gitks is a gRPC-accessible Git bare repository operations service.
{{- if .Values.gitks.etcd.endpoints }}
🚀 Cluster mode: ENABLED
etcd endpoints: {{ .Values.gitks.etcd.endpoints }}
Nodes will discover each other via etcd and elect a PRIMARY.
{{- else }}
⚠️ Cluster mode: DISABLED (gitks.etcd.endpoints is empty)
Running in standalone mode — no automatic failover.
{{- end }}
📦 StatefulSet: {{ include "gitks.fullname" . }}
Replicas: {{ .Values.replicaCount }}
Each pod mounts its own PVC for /data/repos.
🔌 Services:
gRPC: {{ include "gitks.fullname" . }}:{{ .Values.service.port }}
Metrics: {{ include "gitks.fullname" . }}-metrics:{{ .Values.metricsService.port }}
Cluster: {{ include "gitks.headlessServiceName" . }} (headless, pod DNS)
{{- if contains "NodePort" .Values.service.type }}
gRPC NodePort: kubectl get svc {{ include "gitks.fullname" . }} -o jsonpath='{.spec.ports[0].nodePort}'
{{- else if contains "LoadBalancer" .Values.service.type }}
gRPC external IP: kubectl get svc {{ include "gitks.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}"
{{- else }}
Port-forward gRPC:
kubectl port-forward svc/{{ include "gitks.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }}
Port-forward metrics:
kubectl port-forward svc/{{ include "gitks.fullname" . }}-metrics {{ .Values.metricsService.port }}:{{ .Values.metricsService.port }}
{{- end }}
📊 Metrics:
Prometheus endpoint available at :{{ .Values.metricsService.port }}/metrics
Metrics Service annotations include prometheus.io/scrape labels.
💡 Quick start:
# Check pod status
kubectl get pods -l app.kubernetes.io/instance={{ .Release.Name }}
# View logs
kubectl logs -f statefulset/{{ include "gitks.fullname" . }}
# Scale up cluster
helm upgrade {{ .Release.Name }} . --set replicaCount=5
For more information, see the project README.
+75
View File
@@ -0,0 +1,75 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "gitks.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "gitks.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 }}
{{/*
Headless service name (used for StatefulSet pod DNS).
*/}}
{{- define "gitks.headlessServiceName" -}}
{{- printf "%s-headless" (include "gitks.fullname" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "gitks.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "gitks.labels" -}}
helm.sh/chart: {{ include "gitks.chart" . }}
{{ include "gitks.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "gitks.selectorLabels" -}}
app.kubernetes.io/name: {{ include "gitks.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: server
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "gitks.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "gitks.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Pod DNS name template: pod-name.headless-svc.namespace.svc.cluster.local
*/}}
{{- define "gitks.podDnsTemplate" -}}
$(STORAGE_NAME).{{ include "gitks.headlessServiceName" . }}.{{ .Release.Namespace }}.svc.cluster.local
{{- end }}
+35
View File
@@ -0,0 +1,35 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "gitks.fullname" . }}
labels:
{{- include "gitks.labels" . | nindent 4 }}
data:
RUST_LOG: {{ .Values.gitks.rustLog | quote }}
REPO_PREFIX_PATH: {{ .Values.gitks.repoPrefixPath | quote }}
GITKS_HOST: {{ .Values.gitks.grpc.host | quote }}
GITKS_PORT: {{ .Values.gitks.grpc.port | quote }}
GITKS_METRICS_PORT: {{ .Values.gitks.metrics.port | quote }}
GITKS_CLUSTER_PORT: {{ .Values.gitks.cluster.port | quote }}
GITKS_CLUSTER_COOKIE: {{ .Values.gitks.cluster.cookie | quote }}
{{- if .Values.gitks.etcd.endpoints }}
GITKS_ETCD_ENDPOINTS: {{ .Values.gitks.etcd.endpoints | quote }}
{{- end }}
GITKS_ETCD_CONNECT_TIMEOUT: {{ .Values.gitks.etcd.connectTimeout | quote }}
GITKS_LEASE_TTL: {{ .Values.gitks.etcd.leaseTtl | quote }}
GITKS_HEALTH_CHECK_INTERVAL: {{ .Values.gitks.healthCheck.interval | quote }}
GITKS_MAX_HEALTH_FAILURES: {{ .Values.gitks.healthCheck.maxFailures | quote }}
GITKS_DISK_CACHE_ENABLED: {{ .Values.gitks.diskCache.enabled | quote }}
GITKS_DISK_CACHE_MAX_AGE: {{ .Values.gitks.diskCache.maxAge | quote }}
GITKS_PACK_CACHE_ENABLED: {{ .Values.gitks.packCache.enabled | quote }}
GITKS_PACK_CACHE_BACKPRESSURE: {{ .Values.gitks.packCache.backpressure | quote }}
GITKS_HOOKS_ENABLED: {{ .Values.gitks.hooks.enabled | quote }}
GITKS_HOOK_TIMEOUT: {{ .Values.gitks.hooks.timeout | quote }}
GITKS_ALLOW_CUSTOM_HOOKS: {{ .Values.gitks.hooks.allowCustomHooks | quote }}
{{- if .Values.gitks.hooks.serverHooksDir }}
GITKS_SERVER_HOOKS_DIR: {{ .Values.gitks.hooks.serverHooksDir | quote }}
{{- end }}
{{- if .Values.gitks.hooks.callbackAddr }}
GITKS_HOOK_CALLBACK_ADDR: {{ .Values.gitks.hooks.callbackAddr | quote }}
{{- end }}
GITKS_RATE_LIMIT_MAX_CONCURRENT: {{ .Values.gitks.rateLimit.maxConcurrent | quote }}
+29
View File
@@ -0,0 +1,29 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "gitks.headlessServiceName" . }}
labels:
{{- include "gitks.labels" . | nindent 4 }}
{{- with .Values.headlessService.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: ClusterIP
clusterIP: None
publishNotReadyAddresses: true
ports:
- name: grpc
port: {{ .Values.gitks.grpc.port }}
targetPort: grpc
protocol: TCP
- name: metrics
port: {{ .Values.gitks.metrics.port }}
targetPort: metrics
protocol: TCP
- name: cluster
port: {{ .Values.gitks.cluster.port }}
targetPort: cluster
protocol: TCP
selector:
{{- include "gitks.selectorLabels" . | nindent 4 }}
+32
View File
@@ -0,0 +1,32 @@
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "gitks.fullname" . }}
labels:
{{- include "gitks.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: StatefulSet
name: {{ include "gitks.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}
+22
View File
@@ -0,0 +1,22 @@
{{- if .Values.metricsService.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "gitks.fullname" . }}-metrics
labels:
{{- include "gitks.labels" . | nindent 4 }}
app.kubernetes.io/component: metrics
{{- with .Values.metricsService.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.metricsService.type }}
ports:
- port: {{ .Values.metricsService.port }}
targetPort: metrics
protocol: TCP
name: metrics
selector:
{{- include "gitks.selectorLabels" . | nindent 4 }}
{{- end }}
+18
View File
@@ -0,0 +1,18 @@
{{- if .Values.podDisruptionBudget.enabled }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "gitks.fullname" . }}
labels:
{{- include "gitks.labels" . | nindent 4 }}
spec:
{{- with .Values.podDisruptionBudget.minAvailable }}
minAvailable: {{ . }}
{{- end }}
{{- with .Values.podDisruptionBudget.maxUnavailable }}
maxUnavailable: {{ . }}
{{- end }}
selector:
matchLabels:
{{- include "gitks.selectorLabels" . | nindent 6 }}
{{- end }}
+19
View File
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "gitks.fullname" . }}
labels:
{{- include "gitks.labels" . | nindent 4 }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: grpc
protocol: TCP
name: grpc
selector:
{{- include "gitks.selectorLabels" . | nindent 4 }}
+13
View File
@@ -0,0 +1,13 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "gitks.serviceAccountName" . }}
labels:
{{- include "gitks.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
{{- end }}
+131
View File
@@ -0,0 +1,131 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ include "gitks.fullname" . }}
labels:
{{- include "gitks.labels" . | nindent 4 }}
spec:
serviceName: {{ include "gitks.headlessServiceName" . }}
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
podManagementPolicy: Parallel
selector:
matchLabels:
{{- include "gitks.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "gitks.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "gitks.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
terminationGracePeriodSeconds: 30
containers:
- name: gitks
{{- with .Values.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["gitks"]
ports:
- name: grpc
containerPort: {{ .Values.gitks.grpc.port }}
protocol: TCP
- name: metrics
containerPort: {{ .Values.gitks.metrics.port }}
protocol: TCP
- name: cluster
containerPort: {{ .Values.gitks.cluster.port }}
protocol: TCP
envFrom:
- configMapRef:
name: {{ include "gitks.fullname" . }}
env:
# Pod identity — used as STORAGE_NAME and for cluster addressing
- name: STORAGE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
# Advertised gRPC address for remote clients (other nodes use this)
- name: GITKS_ADVERTISE_ADDR
value: "http://{{ include "gitks.podDnsTemplate" . }}:{{ .Values.gitks.grpc.port }}"
# Cluster hostname for ractor TCP connections
- name: GITKS_CLUSTER_HOSTNAME
value: {{ include "gitks.podDnsTemplate" . | quote }}
{{- with .Values.extraEnv }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
livenessProbe:
tcpSocket:
port: grpc
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3
readinessProbe:
tcpSocket:
port: grpc
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
startupProbe:
tcpSocket:
port: grpc
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 30
volumeMounts:
- name: repo-data
mountPath: {{ .Values.gitks.repoPrefixPath | quote }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.persistence.enabled }}
volumeClaimTemplates:
- metadata:
name: repo-data
labels:
{{- include "gitks.labels" . | nindent 10 }}
{{- with .Values.persistence.annotations }}
annotations:
{{- toYaml . | nindent 10 }}
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.accessMode }}
{{- with .Values.persistence.storageClass }}
storageClassName: {{ . | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.size }}
{{- end }}
@@ -0,0 +1,21 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "gitks.fullname" . }}-test-connection"
labels:
{{- include "gitks.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
containers:
- name: grpc-health
image: fullstorydev/grpcurl:latest
command: ['grpcurl']
args:
- -plaintext
- -connect-timeout
- "5"
- {{ include "gitks.fullname" . }}:{{ .Values.service.port }}
- list
restartPolicy: Never