Skip to content

Commit 48fef7a

Browse files
authored
feat(infra): add ledger helm chart with lint and kubeconform ci (#147)
Service chart deploy/helm/ledger (Deployment with probes + hardened distroless securityContext + /tmp emptyDir for read-only root, ClusterIP Service, autoscaling/v2 HPA min1/max10/cpu70, ConfigMap, ServiceAccount). Secrets via secretKeyRef to an existing Secret, never templated. Rewires helm-test to helm lint + helm template piped to pinned kubeconform, dropping the kind install that cannot pull the unpushed image. Closes #68.
1 parent bbf01f1 commit 48fef7a

11 files changed

Lines changed: 294 additions & 20 deletions

File tree

.github/workflows/helm-test.yml

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,35 @@ permissions:
1919

2020
jobs:
2121
chart-test:
22-
name: Lint & Install (kind)
22+
name: Lint & Validate
2323
runs-on: ubuntu-latest
2424

2525
permissions:
2626
contents: read
2727

28+
env:
29+
KUBECONFORM_VERSION: v0.6.7
30+
KUBERNETES_VERSION: "1.31.0"
31+
2832
steps:
2933
- name: Checkout
3034
uses: actions/checkout@v4
31-
with:
32-
fetch-depth: 0
3335

3436
- name: Set up Helm
3537
uses: azure/setup-helm@v4
3638
with:
3739
version: "v3.16.4"
3840

39-
- name: Set up chart-testing (ct)
40-
uses: helm/chart-testing-action@v2
41-
42-
- name: Run chart linting
43-
run: ct lint --chart-dirs deploy/helm --all
41+
- name: Helm lint
42+
run: helm lint deploy/helm/ledger
4443

45-
- name: Create kind cluster
46-
uses: helm/kind-action@v1
47-
with:
48-
cluster_name: fincore-test
49-
50-
- name: Run chart-testing (install)
51-
run: ct install --chart-dirs deploy/helm --all --debug
44+
- name: Install kubeconform
45+
run: |
46+
curl -sSL "https://github.com/yannh/kubeconform/releases/download/${KUBECONFORM_VERSION}/kubeconform-linux-amd64.tar.gz" \
47+
| tar -xz kubeconform
48+
sudo mv kubeconform /usr/local/bin/
5249
53-
- name: Helm template render check
50+
- name: Helm template and validate manifests
5451
run: |
55-
helm template fincore-test deploy/helm/fincore-engine \
56-
--set global.image.tag=ci \
57-
--debug \
58-
> /dev/null
52+
helm template ledger deploy/helm/ledger --set image.tag=test \
53+
| kubeconform -strict -summary -kubernetes-version "$KUBERNETES_VERSION"

deploy/helm/ledger/.helmignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.DS_Store
2+
.git/
3+
.gitignore
4+
*.tmp
5+
*.bak
6+
*.swp

deploy/helm/ledger/Chart.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: v2
2+
name: ledger
3+
description: FinCore ledger service, a double-entry accounting core
4+
type: application
5+
version: 0.1.0
6+
appVersion: "0.1.0"
7+
home: https://github.com/tiana-code/fincore-engine
8+
sources:
9+
- https://github.com/tiana-code/fincore-engine
10+
maintainers:
11+
- name: FinCore Engine Authors
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
The ledger service has been deployed as release {{ .Release.Name }}.
2+
3+
Service (ClusterIP) reachable in-cluster at:
4+
{{ include "ledger.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }}
5+
6+
Probe a pod locally with port-forward:
7+
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "ledger.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }}
8+
curl http://localhost:{{ .Values.service.port }}/actuator/health/readiness
9+
10+
{{- if not .Values.existingSecret }}
11+
12+
WARNING: existingSecret is empty. Set existingSecret to a Secret holding keys
13+
"{{ .Values.secretKeys.datasourcePassword }}" and "{{ .Values.secretKeys.keycloakClientSecret }}" before running against a real database.
14+
{{- end }}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{{- define "ledger.name" -}}
2+
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
3+
{{- end -}}
4+
5+
{{- define "ledger.fullname" -}}
6+
{{- if .Values.fullnameOverride -}}
7+
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
8+
{{- else -}}
9+
{{- printf "%s-%s" .Release.Name (include "ledger.name" .) | trunc 63 | trimSuffix "-" -}}
10+
{{- end -}}
11+
{{- end -}}
12+
13+
{{- define "ledger.chart" -}}
14+
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
15+
{{- end -}}
16+
17+
{{- define "ledger.selectorLabels" -}}
18+
app.kubernetes.io/name: {{ include "ledger.name" . }}
19+
app.kubernetes.io/instance: {{ .Release.Name }}
20+
{{- end -}}
21+
22+
{{- define "ledger.labels" -}}
23+
helm.sh/chart: {{ include "ledger.chart" . }}
24+
{{ include "ledger.selectorLabels" . }}
25+
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
26+
app.kubernetes.io/managed-by: {{ .Release.Service }}
27+
{{- end -}}
28+
29+
{{- define "ledger.serviceAccountName" -}}
30+
{{- if .Values.serviceAccount.create -}}
31+
{{- default (include "ledger.fullname" .) .Values.serviceAccount.name -}}
32+
{{- else -}}
33+
{{- default "default" .Values.serviceAccount.name -}}
34+
{{- end -}}
35+
{{- end -}}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
name: {{ include "ledger.fullname" . }}
5+
labels:
6+
{{- include "ledger.labels" . | nindent 4 }}
7+
data:
8+
SPRING_PROFILES_ACTIVE: {{ .Values.config.springProfilesActive | quote }}
9+
KEYCLOAK_ISSUER_URI: {{ .Values.config.keycloakIssuerUri | quote }}
10+
OTLP_TRACING_ENDPOINT: {{ .Values.config.otlpTracingEndpoint | quote }}
11+
FINCORE_LEDGER_CLEANUP_ENABLED: {{ .Values.config.cleanupEnabled | quote }}
12+
SPRING_DATASOURCE_URL: {{ .Values.config.datasourceUrl | quote }}
13+
SPRING_DATASOURCE_USERNAME: {{ .Values.config.datasourceUsername | quote }}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: {{ include "ledger.fullname" . }}
5+
labels:
6+
{{- include "ledger.labels" . | nindent 4 }}
7+
spec:
8+
{{- if not .Values.autoscaling.enabled }}
9+
replicas: {{ .Values.replicaCount }}
10+
{{- end }}
11+
selector:
12+
matchLabels:
13+
{{- include "ledger.selectorLabels" . | nindent 6 }}
14+
template:
15+
metadata:
16+
labels:
17+
{{- include "ledger.labels" . | nindent 8 }}
18+
spec:
19+
serviceAccountName: {{ include "ledger.serviceAccountName" . }}
20+
{{- with .Values.imagePullSecrets }}
21+
imagePullSecrets:
22+
{{- toYaml . | nindent 8 }}
23+
{{- end }}
24+
securityContext:
25+
{{- toYaml .Values.podSecurityContext | nindent 8 }}
26+
containers:
27+
- name: ledger
28+
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
29+
imagePullPolicy: {{ .Values.image.pullPolicy }}
30+
securityContext:
31+
{{- toYaml .Values.securityContext | nindent 12 }}
32+
ports:
33+
- name: http
34+
containerPort: {{ .Values.service.port }}
35+
protocol: TCP
36+
envFrom:
37+
- configMapRef:
38+
name: {{ include "ledger.fullname" . }}
39+
{{- if .Values.existingSecret }}
40+
env:
41+
- name: SPRING_DATASOURCE_PASSWORD
42+
valueFrom:
43+
secretKeyRef:
44+
name: {{ .Values.existingSecret }}
45+
key: {{ .Values.secretKeys.datasourcePassword }}
46+
- name: KEYCLOAK_CLIENT_SECRET
47+
valueFrom:
48+
secretKeyRef:
49+
name: {{ .Values.existingSecret }}
50+
key: {{ .Values.secretKeys.keycloakClientSecret }}
51+
{{- end }}
52+
livenessProbe:
53+
httpGet:
54+
path: /actuator/health/liveness
55+
port: http
56+
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
57+
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
58+
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
59+
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
60+
readinessProbe:
61+
httpGet:
62+
path: /actuator/health/readiness
63+
port: http
64+
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
65+
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
66+
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
67+
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
68+
resources:
69+
{{- toYaml .Values.resources | nindent 12 }}
70+
volumeMounts:
71+
- name: tmp
72+
mountPath: /tmp
73+
volumes:
74+
- name: tmp
75+
emptyDir: {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{{- if .Values.autoscaling.enabled }}
2+
apiVersion: autoscaling/v2
3+
kind: HorizontalPodAutoscaler
4+
metadata:
5+
name: {{ include "ledger.fullname" . }}
6+
labels:
7+
{{- include "ledger.labels" . | nindent 4 }}
8+
spec:
9+
scaleTargetRef:
10+
apiVersion: apps/v1
11+
kind: Deployment
12+
name: {{ include "ledger.fullname" . }}
13+
minReplicas: {{ .Values.autoscaling.minReplicas }}
14+
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
15+
metrics:
16+
- type: Resource
17+
resource:
18+
name: cpu
19+
target:
20+
type: Utilization
21+
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
22+
{{- end }}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
name: {{ include "ledger.fullname" . }}
5+
labels:
6+
{{- include "ledger.labels" . | nindent 4 }}
7+
spec:
8+
type: {{ .Values.service.type }}
9+
ports:
10+
- name: http
11+
port: {{ .Values.service.port }}
12+
targetPort: http
13+
protocol: TCP
14+
selector:
15+
{{- include "ledger.selectorLabels" . | nindent 4 }}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{{- if .Values.serviceAccount.create }}
2+
apiVersion: v1
3+
kind: ServiceAccount
4+
metadata:
5+
name: {{ include "ledger.serviceAccountName" . }}
6+
labels:
7+
{{- include "ledger.labels" . | nindent 4 }}
8+
{{- end }}

0 commit comments

Comments
 (0)