feat(chart): add initial Helm chart for GitData components including apihost, githost, and synchost
ZhenYi committed
Added .gitea/workflows/docker-build-push.yaml .gitea/workflows/docker-build-push.yaml +54 −0 View .gitea/workflows/docker-build-push.yaml
@@ -0,0 +1,54 @@
1name: docker-build-push
2
3on:
4 push:
5 branches: [main, master]
6 tags: ["v*"]
7 workflow_dispatch:
8
9env:
10 IMAGE: harbor.gitdata.me/app/gitdata
11
12jobs:
13 build:
14 runs-on: ubuntu-latest
15 permissions:
16 contents: read
17 steps:
18 - name: Checkout
19 uses: actions/checkout@v4
20
21 - name: Setup Docker Buildx
22 uses: docker/setup-buildx-action@v3
23
24 - name: Login to Harbor
25 uses: docker/login-action@v3
26 with:
27 registry: ${{ secrets.DOCKER_REGISTER || 'harbor.gitdata.me' }}
28 username: ${{ secrets.DOCKER_USERNAME }}
29 password: ${{ secrets.DOCKER_PASSWORD }}
30
31 - name: Compute tags
32 id: meta
33 run: |
34 short="${GITHUB_SHA:0:7}"
35 tag="${GITHUB_REF#refs/tags/}"
36 {
37 echo "tags<<EOF"
38 if [ "$tag" != "$GITHUB_REF" ]; then
39 echo "$IMAGE:$tag"
40 else
41 echo "$IMAGE:sha-$short"
42 fi
43 echo "$IMAGE:latest"
44 echo "EOF"
45 } >> "$GITHUB_OUTPUT"
46
47 - name: Build and push
48 uses: docker/build-push-action@v6
49 with:
50 context: .
51 push: true
52 tags: ${{ steps.meta.outputs.tags }}
53 cache-from: type=registry,ref=harbor.gitdata.me/app/gitdata:buildcache
54 cache-to: type=registry,ref=harbor.gitdata.me/app/gitdata:buildcache,mode=max
Added chart/templates/_helpers.tpl chart/templates/_helpers.tpl +133 −0 View chart/templates/_helpers.tpl
@@ -0,0 +1,133 @@
1{{- define "gitdata.name" -}}
2{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
3{{- end -}}
4
5{{- define "gitdata.fullname" -}}
6{{- if .Values.fullnameOverride -}}
7{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
8{{- else -}}
9{{- $name := default .Chart.Name .Values.nameOverride -}}
10{{- if contains $name .Release.Name -}}
11{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
12{{- else -}}
13{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
14{{- end -}}
15{{- end -}}
16{{- end -}}
17
18{{- define "gitdata.chart" -}}
19{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
20{{- end -}}
21
22{{- define "gitdata.labels" -}}
23helm.sh/chart: {{ include "gitdata.chart" . }}
24app.kubernetes.io/name: {{ include "gitdata.name" . }}
25app.kubernetes.io/instance: {{ .Release.Name }}
26app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
27app.kubernetes.io/managed-by: {{ .Release.Service }}
28{{- end -}}
29
30{{- define "gitdata.selectorLabels" -}}
31app.kubernetes.io/name: {{ include "gitdata.name" . }}
32app.kubernetes.io/instance: {{ .Release.Name }}
33{{- end -}}
34
35{{- define "gitdata.serviceAccountName" -}}
36{{- if .Values.serviceAccount.create -}}
37{{- default (include "gitdata.fullname" .) .Values.serviceAccount.name -}}
38{{- else -}}
39{{- default "default" .Values.serviceAccount.name -}}
40{{- end -}}
41{{- end -}}
42
43{{- define "gitdata.image" -}}
44{{- $tag := default .Chart.AppVersion .Values.image.tag -}}
45{{- printf "%s:%s" .Values.image.repository $tag -}}
46{{- end -}}
47
48{{- define "gitdata.secretName" -}}
49{{- if .Values.secret.existingSecret -}}
50{{- .Values.secret.existingSecret -}}
51{{- else -}}
52{{- printf "%s-env" (include "gitdata.fullname" .) -}}
53{{- end -}}
54{{- end -}}
55
56{{/* 组件通用 env:端口/路径/URL 由 values 结构字段生成,用户 config.env 可覆盖 */}}
57{{- define "gitdata.env" -}}
58- name: APP_APIHOST__PORT
59 value: {{ .Values.apihost.port | quote }}
60- name: APP_GITHOST__HTTP_PORT
61 value: {{ .Values.githost.httpPort | quote }}
62{{- if .Values.githost.ssh.enabled }}
63- name: APP_GIT__SSH__PORT
64 value: {{ .Values.githost.ssh.containerPort | quote }}
65- name: APP_GIT__SSH_CLONE_HOST
66 value: {{ .Values.githost.ssh.cloneHost | quote }}
67- name: APP_GIT__SSH_CLONE_PORT
68 value: {{ .Values.githost.ssh.clonePort | quote }}
69{{- else }}
70- name: APP_GIT__SSH__PORT
71 value: "0"
72{{- end }}
73- name: APP_GIT__REPO_ROOT
74 value: {{ printf "%s/repos" .Values.persistence.repos.mountPath | quote }}
75- name: APP_GIT__OBJECTS_ROOT
76 value: {{ printf "%s/objects" .Values.persistence.repos.mountPath | quote }}
77- name: APP_GIT__SSH__HOST_KEY_PATH
78 value: {{ printf "%s/ssh_host_ed25519" .Values.persistence.repos.mountPath | quote }}
79{{- $base := printf "https://%s" .Values.ingress.host }}
80- name: APP_WEB__WEB_BASE_URL
81 value: {{ default $base .Values.config.env.APP_WEB__WEB_BASE_URL | quote }}
82- name: APP_GIT__BASE_URL
83 value: {{ default $base .Values.config.env.APP_GIT__BASE_URL | quote }}
84- name: APP_GIT__HTTP_CLONE_BASE_URL
85 value: {{ default $base .Values.config.env.APP_GIT__HTTP_CLONE_BASE_URL | quote }}
86{{- if .Values.metrics.otlpEndpoint }}
87- name: OTEL_EXPORTER_OTLP_ENDPOINT
88 value: {{ .Values.metrics.otlpEndpoint | quote }}
89{{- end }}
90{{- range $k, $v := .Values.config.env }}
91{{- if not (hasPrefix "APP_WEB__WEB_BASE_URL" $k) }}
92{{- if not (hasPrefix "APP_GIT__BASE_URL" $k) }}
93- name: {{ $k }}
94 value: {{ $v | quote }}
95{{- end }}
96{{- end }}
97{{- end }}
98{{- end -}}
99
100{{- define "gitdata.envFrom" -}}
101envFrom:
102 - configMapRef:
103 name: {{ printf "%s-env" (include "gitdata.fullname" .) }}
104 - secretRef:
105 name: {{ include "gitdata.secretName" . }}
106 optional: true
107{{- end -}}
108
109{{/* 抗节点故障软反亲和 */}}
110{{- define "gitdata.podAntiAffinity" -}}
111{{- $ctx := .ctx -}}
112podAntiAffinity:
113 {{ if eq .mode "hard" }}requiredDuringSchedulingIgnoredDuringExecution:
114 - labelSelector:
115 matchLabels: {{- include "gitdata.selectorLabels" $ctx | nindent 10 }}
116 app.kubernetes.io/component: {{ .component }}
117 topologyKey: kubernetes.io/hostname
118 {{ else if eq .mode "soft" }}preferredDuringSchedulingIgnoredDuringExecution:
119 - weight: 100
120 podAffinityTerm:
121 labelSelector:
122 matchLabels: {{- include "gitdata.selectorLabels" $ctx | nindent 12 }}
123 app.kubernetes.io/component: {{ .component }}
124 topologyKey: kubernetes.io/hostname
125 {{ end }}
126{{- end -}}
127
128{{- define "gitdata.imagePullSecrets" -}}
129{{- with .Values.imagePullSecrets }}
130imagePullSecrets:
131 {{- toYaml . | nindent 2 }}
132{{- end }}
133{{- end -}}
Added chart/templates/apihost.yaml chart/templates/apihost.yaml +144 −0 View chart/templates/apihost.yaml
@@ -0,0 +1,144 @@
1{{- if .Values.apihost.enabled }}
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: {{ printf "%s-apihost" (include "gitdata.fullname" .) }}
6 labels:
7 {{- include "gitdata.labels" . | nindent 4 }}
8 app.kubernetes.io/component: apihost
9spec:
10 {{- if not .Values.apihost.autoscaling.enabled }}
11 replicas: {{ .Values.apihost.replicaCount }}
12 {{- end }}
13 revisionHistoryLimit: 3
14 strategy:
15 type: RollingUpdate
16 rollingUpdate:
17 maxSurge: {{ .Values.apihost.maxSurge }}
18 maxUnavailable: {{ .Values.apihost.maxUnavailable }}
19 selector:
20 matchLabels:
21 {{- include "gitdata.selectorLabels" . | nindent 6 }}
22 app.kubernetes.io/component: apihost
23 template:
24 metadata:
25 labels:
26 {{- include "gitdata.selectorLabels" . | nindent 8 }}
27 app.kubernetes.io/component: apihost
28 {{- with .Values.podLabels }}
29 {{- toYaml . | nindent 8 }}
30 {{- end }}
31 annotations:
32 checksum/env: {{ toYaml .Values.config.env | sha256sum }}
33 {{- with .Values.podAnnotations }}
34 {{- toYaml . | nindent 8 }}
35 {{- end }}
36 spec:
37 serviceAccountName: {{ include "gitdata.serviceAccountName" . }}
38 {{- include "gitdata.imagePullSecrets" . | nindent 6 }}
39 terminationGracePeriodSeconds: 45
40 securityContext:
41 {{- toYaml .Values.podSecurityContext | nindent 8 }}
42 {{- if or (eq .Values.apihost.podAntiAffinity "soft") (eq .Values.apihost.podAntiAffinity "hard") }}
43 affinity:
44 {{- include "gitdata.podAntiAffinity" (dict "ctx" . "mode" .Values.apihost.podAntiAffinity "component" "apihost") | nindent 8 }}
45 {{- end }}
46 {{- with .Values.nodeSelector }}
47 nodeSelector:
48 {{- toYaml . | nindent 8 }}
49 {{- end }}
50 {{- with .Values.tolerations }}
51 tolerations:
52 {{- toYaml . | nindent 8 }}
53 {{- end }}
54 containers:
55 - name: apihost
56 image: {{ include "gitdata.image" . }}
57 imagePullPolicy: {{ .Values.image.pullPolicy }}
58 args: ["apihost"]
59 {{- include "gitdata.envFrom" . | nindent 10 }}
60 env:
61 {{- include "gitdata.env" . | nindent 12 }}
62 {{- with .Values.apihost.extraEnv }}
63 {{- toYaml . | nindent 12 }}
64 {{- end }}
65 ports:
66 - name: http
67 containerPort: {{ .Values.apihost.port }}
68 livenessProbe:
69 httpGet: { path: /healthz, port: http }
70 initialDelaySeconds: 10
71 periodSeconds: 15
72 timeoutSeconds: 3
73 readinessProbe:
74 httpGet: { path: /readyz, port: http }
75 initialDelaySeconds: 5
76 periodSeconds: 10
77 timeoutSeconds: 3
78 failureThreshold: 3
79 lifecycle:
80 preStop:
81 exec:
82 command: ["/bin/sh", "-c", "sleep 5"]
83 securityContext:
84 {{- toYaml .Values.securityContext | nindent 12 }}
85 resources:
86 {{- toYaml .Values.apihost.resources | nindent 12 }}
87---
88apiVersion: v1
89kind: Service
90metadata:
91 name: {{ printf "%s-apihost" (include "gitdata.fullname" .) }}
92 labels:
93 {{- include "gitdata.labels" . | nindent 4 }}
94 app.kubernetes.io/component: apihost
95spec:
96 type: ClusterIP
97 selector:
98 {{- include "gitdata.selectorLabels" . | nindent 4 }}
99 app.kubernetes.io/component: apihost
100 ports:
101 - name: http
102 port: {{ .Values.apihost.port }}
103 targetPort: http
104{{- if .Values.apihost.autoscaling.enabled }}
105---
106apiVersion: autoscaling/v2
107kind: HorizontalPodAutoscaler
108metadata:
109 name: {{ printf "%s-apihost" (include "gitdata.fullname" .) }}
110 labels:
111 {{- include "gitdata.labels" . | nindent 4 }}
112 app.kubernetes.io/component: apihost
113spec:
114 scaleTargetRef:
115 apiVersion: apps/v1
116 kind: Deployment
117 name: {{ printf "%s-apihost" (include "gitdata.fullname" .) }}
118 minReplicas: {{ .Values.apihost.autoscaling.minReplicas }}
119 maxReplicas: {{ .Values.apihost.autoscaling.maxReplicas }}
120 metrics:
121 - type: Resource
122 resource:
123 name: cpu
124 target:
125 type: Utilization
126 averageUtilization: {{ .Values.apihost.autoscaling.targetCPUUtilizationPercentage }}
127{{- end }}
128{{- if .Values.apihost.pdb.enabled }}
129---
130apiVersion: policy/v1
131kind: PodDisruptionBudget
132metadata:
133 name: {{ printf "%s-apihost" (include "gitdata.fullname" .) }}
134 labels:
135 {{- include "gitdata.labels" . | nindent 4 }}
136 app.kubernetes.io/component: apihost
137spec:
138 minAvailable: {{ .Values.apihost.pdb.minAvailable }}
139 selector:
140 matchLabels:
141 {{- include "gitdata.selectorLabels" . | nindent 6 }}
142 app.kubernetes.io/component: apihost
143{{- end }}
144{{- end }}
Added chart/templates/configmap-env.yaml chart/templates/configmap-env.yaml +8 −0 View chart/templates/configmap-env.yaml
@@ -0,0 +1,8 @@
1apiVersion: v1
2kind: ConfigMap
3metadata:
4 name: {{ printf "%s-env" (include "gitdata.fullname" .) }}
5 labels:
6 {{- include "gitdata.labels" . | nindent 4 }}
7data:
8 RUST_LOG: "info"
Added chart/templates/githost.yaml chart/templates/githost.yaml +163 −0 View chart/templates/githost.yaml
@@ -0,0 +1,163 @@
1{{- if .Values.githost.enabled }}
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: {{ printf "%s-githost" (include "gitdata.fullname" .) }}
6 labels:
7 {{- include "gitdata.labels" . | nindent 4 }}
8 app.kubernetes.io/component: githost
9spec:
10 replicas: {{ .Values.githost.replicaCount }}
11 revisionHistoryLimit: 3
12 # host key 在共享 PVC 上,滚动更新时新旧 Pod 同读一把 key,无冲突
13 strategy:
14 type: RollingUpdate
15 rollingUpdate:
16 maxSurge: 1
17 maxUnavailable: 0
18 selector:
19 matchLabels:
20 {{- include "gitdata.selectorLabels" . | nindent 6 }}
21 app.kubernetes.io/component: githost
22 template:
23 metadata:
24 labels:
25 {{- include "gitdata.selectorLabels" . | nindent 8 }}
26 app.kubernetes.io/component: githost
27 {{- with .Values.podLabels }}
28 {{- toYaml . | nindent 8 }}
29 {{- end }}
30 annotations:
31 checksum/env: {{ toYaml .Values.config.env | sha256sum }}
32 {{- with .Values.podAnnotations }}
33 {{- toYaml . | nindent 8 }}
34 {{- end }}
35 spec:
36 serviceAccountName: {{ include "gitdata.serviceAccountName" . }}
37 {{- include "gitdata.imagePullSecrets" . | nindent 6 }}
38 terminationGracePeriodSeconds: 3660
39 securityContext:
40 {{- toYaml .Values.podSecurityContext | nindent 8 }}
41 {{- if .Values.githost.ssh.enabled }}
42 initContainers:
43 - name: ssh-hostkey
44 image: {{ include "gitdata.image" . }}
45 imagePullPolicy: {{ .Values.image.pullPolicy }}
46 command: ["/bin/sh", "-c"]
47 args:
48 - "test -f {{ .Values.persistence.repos.mountPath }}/ssh_host_ed25519 || ssh-keygen -q -t ed25519 -N '' -f {{ .Values.persistence.repos.mountPath }}/ssh_host_ed25519"
49 volumeMounts:
50 - name: repos
51 mountPath: {{ .Values.persistence.repos.mountPath }}
52 securityContext:
53 {{- toYaml .Values.securityContext | nindent 12 }}
54 {{- end }}
55 containers:
56 - name: githost
57 image: {{ include "gitdata.image" . }}
58 imagePullPolicy: {{ .Values.image.pullPolicy }}
59 args: ["githost"]
60 {{- include "gitdata.envFrom" . | nindent 10 }}
61 env:
62 {{- include "gitdata.env" . | nindent 12 }}
63 {{- with .Values.githost.extraEnv }}
64 {{- toYaml . | nindent 12 }}
65 {{- end }}
66 ports:
67 - name: smart-http
68 containerPort: {{ .Values.githost.httpPort }}
69 {{- if .Values.githost.ssh.enabled }}
70 - name: ssh
71 containerPort: {{ .Values.githost.ssh.containerPort }}
72 {{- end }}
73 # githost 未挂载 /healthz(见 app/githost/src/main.rs),用 TCP 探针
74 livenessProbe:
75 tcpSocket: { port: smart-http }
76 initialDelaySeconds: 15
77 periodSeconds: 20
78 readinessProbe:
79 tcpSocket: { port: smart-http }
80 initialDelaySeconds: 5
81 periodSeconds: 10
82 securityContext:
83 {{- toYaml .Values.securityContext | nindent 12 }}
84 resources:
85 {{- toYaml .Values.githost.resources | nindent 12 }}
86 volumeMounts:
87 - name: repos
88 mountPath: {{ .Values.persistence.repos.mountPath }}
89 volumes:
90 - name: repos
91 {{- if .Values.persistence.repos.existingClaim }}
92 persistentVolumeClaim:
93 claimName: {{ .Values.persistence.repos.existingClaim }}
94 {{- else if .Values.persistence.repos.enabled }}
95 persistentVolumeClaim:
96 claimName: {{ printf "%s-repos" (include "gitdata.fullname" .) }}
97 {{- else }}
98 emptyDir: {}
99 {{- end }}
100---
101apiVersion: v1
102kind: Service
103metadata:
104 name: {{ printf "%s-githost" (include "gitdata.fullname" .) }}
105 labels:
106 {{- include "gitdata.labels" . | nindent 4 }}
107 app.kubernetes.io/component: githost
108spec:
109 type: ClusterIP
110 selector:
111 {{- include "gitdata.selectorLabels" . | nindent 4 }}
112 app.kubernetes.io/component: githost
113 ports:
114 - name: smart-http
115 port: {{ .Values.githost.httpPort }}
116 targetPort: smart-http
117{{- if .Values.githost.ssh.enabled }}
118---
119apiVersion: v1
120kind: Service
121metadata:
122 name: {{ printf "%s-githost-ssh" (include "gitdata.fullname" .) }}
123 labels:
124 {{- include "gitdata.labels" . | nindent 4 }}
125 app.kubernetes.io/component: githost
126 {{- with .Values.githost.ssh.service.annotations }}
127 annotations:
128 {{- toYaml . | nindent 4 }}
129 {{- end }}
130spec:
131 type: {{ .Values.githost.ssh.service.type }}
132 selector:
133 {{- include "gitdata.selectorLabels" . | nindent 4 }}
134 app.kubernetes.io/component: githost
135 {{- with .Values.githost.ssh.service.externalIPs }}
136 externalIPs:
137 {{- toYaml . | nindent 4 }}
138 {{- end }}
139 ports:
140 - name: ssh
141 port: {{ .Values.githost.ssh.service.port }}
142 targetPort: ssh
143 {{- if and (eq .Values.githost.ssh.service.type "NodePort") .Values.githost.ssh.service.nodePort }}
144 nodePort: {{ .Values.githost.ssh.service.nodePort }}
145 {{- end }}
146{{- end }}
147{{- if .Values.githost.pdb.enabled }}
148---
149apiVersion: policy/v1
150kind: PodDisruptionBudget
151metadata:
152 name: {{ printf "%s-githost" (include "gitdata.fullname" .) }}
153 labels:
154 {{- include "gitdata.labels" . | nindent 4 }}
155 app.kubernetes.io/component: githost
156spec:
157 minAvailable: {{ .Values.githost.pdb.minAvailable }}
158 selector:
159 matchLabels:
160 {{- include "gitdata.selectorLabels" . | nindent 6 }}
161 app.kubernetes.io/component: githost
162{{- end }}
163{{- end }}
Added chart/templates/ingress.yaml chart/templates/ingress.yaml +54 −0 View chart/templates/ingress.yaml
@@ -0,0 +1,54 @@
1{{- if .Values.ingress.enabled }}
2{{- $fullName := include "gitdata.fullname" . }}
3{{- $tlsSecret := default (printf "%s-tls" $fullName) .Values.ingress.tls.secretName }}
4{{- $nginxDefaults := dict
5 "nginx.ingress.kubernetes.io/use-regex" "true"
6 "nginx.ingress.kubernetes.io/proxy-body-size" .Values.ingress.proxyBodySize
7 "nginx.ingress.kubernetes.io/proxy-read-timeout" (printf "%v" .Values.ingress.proxyReadTimeout)
8 "nginx.ingress.kubernetes.io/proxy-send-timeout" (printf "%v" .Values.ingress.proxySendTimeout)
9 "nginx.ingress.kubernetes.io/proxy-connect-timeout" (printf "%v" .Values.ingress.proxyConnectTimeout)
10 "nginx.ingress.kubernetes.io/configuration-snippet" "proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection \"upgrade\";" }}
11{{- $annotations := merge (deepCopy .Values.ingress.annotations) (mustFromJson (toJson $nginxDefaults)) }}
12{{- if and .Values.ingress.tls.enabled .Values.ingress.tls.clusterIssuer }}
13{{- $_ := set $annotations "cert-manager.io/cluster-issuer" .Values.ingress.tls.clusterIssuer }}
14{{- end }}
15apiVersion: networking.k8s.io/v1
16kind: Ingress
17metadata:
18 name: {{ $fullName }}
19 labels:
20 {{- include "gitdata.labels" . | nindent 4 }}
21 annotations:
22 {{- toYaml $annotations | nindent 4 }}
23spec:
24 {{- with .Values.ingress.className }}
25 ingressClassName: {{ . }}
26 {{- end }}
27 {{- if .Values.ingress.tls.enabled }}
28 tls:
29 - hosts:
30 - {{ .Values.ingress.host | quote }}
31 secretName: {{ $tlsSecret }}
32 {{- end }}
33 rules:
34 - host: {{ .Values.ingress.host | quote }}
35 http:
36 paths:
37 # *.git 必须路由到 githost(反代契约 §3.1),排在 "/" 之前
38 {{- if .Values.githost.enabled }}
39 - path: {{ .Values.ingress.githostPath | quote }}
40 pathType: ImplementationSpecific
41 backend:
42 service:
43 name: {{ printf "%s-githost" $fullName }}
44 port:
45 name: smart-http
46 {{- end }}
47 - path: /
48 pathType: Prefix
49 backend:
50 service:
51 name: {{ printf "%s-apihost" $fullName }}
52 port:
53 name: http
54{{- end }}
Added chart/templates/mails.yaml chart/templates/mails.yaml +49 −0 View chart/templates/mails.yaml
@@ -0,0 +1,49 @@
1{{- if .Values.mails.enabled }}
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: {{ printf "%s-mails" (include "gitdata.fullname" .) }}
6 labels:
7 {{- include "gitdata.labels" . | nindent 4 }}
8 app.kubernetes.io/component: mails
9spec:
10 replicas: {{ .Values.mails.replicaCount }}
11 revisionHistoryLimit: 3
12 selector:
13 matchLabels:
14 {{- include "gitdata.selectorLabels" . | nindent 6 }}
15 app.kubernetes.io/component: mails
16 template:
17 metadata:
18 labels:
19 {{- include "gitdata.selectorLabels" . | nindent 8 }}
20 app.kubernetes.io/component: mails
21 {{- with .Values.podLabels }}
22 {{- toYaml . | nindent 8 }}
23 {{- end }}
24 annotations:
25 checksum/env: {{ toYaml .Values.config.env | sha256sum }}
26 {{- with .Values.podAnnotations }}
27 {{- toYaml . | nindent 8 }}
28 {{- end }}
29 spec:
30 serviceAccountName: {{ include "gitdata.serviceAccountName" . }}
31 {{- include "gitdata.imagePullSecrets" . | nindent 6 }}
32 securityContext:
33 {{- toYaml .Values.podSecurityContext | nindent 8 }}
34 containers:
35 - name: mails
36 image: {{ include "gitdata.image" . }}
37 imagePullPolicy: {{ .Values.image.pullPolicy }}
38 args: ["mails"]
39 {{- include "gitdata.envFrom" . | nindent 10 }}
40 env:
41 {{- include "gitdata.env" . | nindent 12 }}
42 {{- with .Values.mails.extraEnv }}
43 {{- toYaml . | nindent 12 }}
44 {{- end }}
45 securityContext:
46 {{- toYaml .Values.securityContext | nindent 12 }}
47 resources:
48 {{- toYaml .Values.mails.resources | nindent 12 }}
49{{- end }}
Added chart/templates/migrate-job.yaml chart/templates/migrate-job.yaml +42 −0 View chart/templates/migrate-job.yaml
@@ -0,0 +1,42 @@
1{{- if .Values.migrate.enabled }}
2apiVersion: batch/v1
3kind: Job
4metadata:
5 name: {{ printf "%s-migrate" (include "gitdata.fullname" .) }}
6 labels:
7 {{- include "gitdata.labels" . | nindent 4 }}
8 app.kubernetes.io/component: migrate
9 annotations:
10 "helm.sh/hook": pre-install,pre-upgrade
11 "helm.sh/hook-weight": "-5"
12 "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
13spec:
14 backoffLimit: 3
15 activeDeadlineSeconds: 600
16 template:
17 metadata:
18 labels:
19 {{- include "gitdata.selectorLabels" . | nindent 8 }}
20 app.kubernetes.io/component: migrate
21 spec:
22 restartPolicy: Never
23 serviceAccountName: {{ include "gitdata.serviceAccountName" . }}
24 {{- include "gitdata.imagePullSecrets" . | nindent 6 }}
25 securityContext:
26 {{- toYaml .Values.podSecurityContext | nindent 8 }}
27 containers:
28 - name: migrate
29 image: {{ include "gitdata.image" . }}
30 imagePullPolicy: {{ .Values.image.pullPolicy }}
31 command: ["migrate"]
32 {{- include "gitdata.envFrom" . | nindent 10 }}
33 env:
34 {{- include "gitdata.env" . | nindent 12 }}
35 {{- with .Values.migrate.extraEnv }}
36 {{- toYaml . | nindent 12 }}
37 {{- end }}
38 securityContext:
39 {{- toYaml .Values.securityContext | nindent 12 }}
40 resources:
41 {{- toYaml .Values.migrate.resources | nindent 12 }}
42{{- end }}
Added chart/templates/NOTES.txt chart/templates/NOTES.txt +25 −0 View chart/templates/NOTES.txt
@@ -0,0 +1,25 @@
1GitData {{ .Chart.AppVersion }} deployed as {{ .Release.Name }}.
2
3Endpoints (ingress {{ .Values.ingress.enabled }}):
4{{- if .Values.ingress.enabled }}
5 https://{{ .Values.ingress.host }}/ -> apihost (REST/GraphQL/WS)
6 https://{{ .Values.ingress.host }}/{space}/{repo}.git/ -> githost smart HTTP
7{{- else }}
8 kubectl port-forward svc/{{ .Values.fullnameOverride | default (printf "%s-%s" .Release.Name .Chart.Name) }}-apihost {{ .Values.apihost.port }}:{{ .Values.apihost.port }}
9{{- end }}
10{{- if and .Values.githost.enabled .Values.githost.ssh.enabled }}
11
12Git over SSH ({{ .Values.githost.ssh.service.type }}):
13 git clone {{ .Values.githost.ssh.cloneHost | default "<SSH-LB-IP>" }}:{{ "{{space}}" }}/{{ "{{repo}}" }}.git
14 (* SSH Service 已分配 EXTERNAL-IP 后,把 githost.ssh.cloneHost 设为该地址并 upgrade *)
15{{- end }}
16
17Check:
18 kubectl -n {{ .Release.Namespace }} get pods -l app.kubernetes.io/instance={{ .Release.Name }}
19 kubectl -n {{ .Release.Namespace }} logs job/{{ include "gitdata.fullname" . }}-migrate
20
21Reminders:
22 - secret.env 中 APP_SESSION__KEY / APP_POW__MAC_KEY / APP_AUTH__TOTP_ENCRYPTION_KEY 必填;
23 生产环境建议 --set secret.existingSecret=<name> 并用外部 Secret 管理。
24 - repos PVC 需 RWX(NFS/CephFS/EFS);无 RWX 时将 githost/synchost 各缩到 1 副本并固定同节点。
25 - 磁盘上的 config/local.toml 含真实密钥,部署前请轮换。
Added chart/templates/repos-pvc.yaml chart/templates/repos-pvc.yaml +18 −0 View chart/templates/repos-pvc.yaml
@@ -0,0 +1,18 @@
1{{- if and .Values.persistence.repos.enabled (not .Values.persistence.repos.existingClaim) }}
2apiVersion: v1
3kind: PersistentVolumeClaim
4metadata:
5 name: {{ printf "%s-repos" (include "gitdata.fullname" .) }}
6 labels:
7 {{- include "gitdata.labels" . | nindent 4 }}
8 app.kubernetes.io/component: repos
9spec:
10 accessModes:
11 {{- toYaml .Values.persistence.repos.accessModes | nindent 4 }}
12 {{- if .Values.persistence.repos.storageClassName }}
13 storageClassName: {{ .Values.persistence.repos.storageClassName | quote }}
14 {{- end }}
15 resources:
16 requests:
17 storage: {{ .Values.persistence.repos.size | quote }}
18{{- end }}
Added chart/templates/secret-env.yaml chart/templates/secret-env.yaml +13 −0 View chart/templates/secret-env.yaml
@@ -0,0 +1,13 @@
1{{- if and .Values.secret.create (not .Values.secret.existingSecret) }}
2apiVersion: v1
3kind: Secret
4metadata:
5 name: {{ include "gitdata.secretName" . }}
6 labels:
7 {{- include "gitdata.labels" . | nindent 4 }}
8type: Opaque
9stringData:
10 {{- range $k, $v := .Values.secret.env }}
11 {{ $k }}: {{ $v | quote }}
12 {{- end }}
13{{- end }}
Added chart/templates/serviceaccount.yaml chart/templates/serviceaccount.yaml +12 −0 View chart/templates/serviceaccount.yaml
@@ -0,0 +1,12 @@
1{{- if .Values.serviceAccount.create }}
2apiVersion: v1
3kind: ServiceAccount
4metadata:
5 name: {{ include "gitdata.serviceAccountName" . }}
6 labels:
7 {{- include "gitdata.labels" . | nindent 4 }}
8 {{- with .Values.serviceAccount.annotations }}
9 annotations:
10 {{- toYaml . | nindent 4 }}
11 {{- end }}
12{{- end }}
Added chart/templates/synchost.yaml chart/templates/synchost.yaml +66 −0 View chart/templates/synchost.yaml
@@ -0,0 +1,66 @@
1{{- if .Values.synchost.enabled }}
2apiVersion: apps/v1
3kind: Deployment
4metadata:
5 name: {{ printf "%s-synchost" (include "gitdata.fullname" .) }}
6 labels:
7 {{- include "gitdata.labels" . | nindent 4 }}
8 app.kubernetes.io/component: synchost
9spec:
10 replicas: {{ .Values.synchost.replicaCount }}
11 revisionHistoryLimit: 3
12 selector:
13 matchLabels:
14 {{- include "gitdata.selectorLabels" . | nindent 6 }}
15 app.kubernetes.io/component: synchost
16 template:
17 metadata:
18 labels:
19 {{- include "gitdata.selectorLabels" . | nindent 8 }}
20 app.kubernetes.io/component: synchost
21 {{- with .Values.podLabels }}
22 {{- toYaml . | nindent 8 }}
23 {{- end }}
24 annotations:
25 checksum/env: {{ toYaml .Values.config.env | sha256sum }}
26 {{- with .Values.podAnnotations }}
27 {{- toYaml . | nindent 8 }}
28 {{- end }}
29 spec:
30 serviceAccountName: {{ include "gitdata.serviceAccountName" . }}
31 {{- include "gitdata.imagePullSecrets" . | nindent 6 }}
32 # push 后同步任务含 git 子进程,给足 drain 时间
33 terminationGracePeriodSeconds: 600
34 securityContext:
35 {{- toYaml .Values.podSecurityContext | nindent 8 }}
36 containers:
37 - name: synchost
38 image: {{ include "gitdata.image" . }}
39 imagePullPolicy: {{ .Values.image.pullPolicy }}
40 args: ["synchost"]
41 {{- include "gitdata.envFrom" . | nindent 10 }}
42 env:
43 {{- include "gitdata.env" . | nindent 12 }}
44 {{- with .Values.synchost.extraEnv }}
45 {{- toYaml . | nindent 12 }}
46 {{- end }}
47 # 无监听端口(Redis BRPOP worker),不做端口探针
48 securityContext:
49 {{- toYaml .Values.securityContext | nindent 12 }}
50 resources:
51 {{- toYaml .Values.synchost.resources | nindent 12 }}
52 volumeMounts:
53 - name: repos
54 mountPath: {{ .Values.persistence.repos.mountPath }}
55 volumes:
56 - name: repos
57 {{- if .Values.persistence.repos.existingClaim }}
58 persistentVolumeClaim:
59 claimName: {{ .Values.persistence.repos.existingClaim }}
60 {{- else if .Values.persistence.repos.enabled }}
61 persistentVolumeClaim:
62 claimName: {{ printf "%s-repos" (include "gitdata.fullname" .) }}
63 {{- else }}
64 emptyDir: {}
65 {{- end }}
66{{- end }}
Added chart/.helmignore chart/.helmignore +5 −0 View chart/.helmignore
@@ -0,0 +1,5 @@
1*.tgz
2*.bak
3.git
4.gitignore
5.idea
Added chart/Chart.yaml chart/Chart.yaml +6 −0 View chart/Chart.yaml
@@ -0,0 +1,6 @@
1apiVersion: v2
2name: gitdata
3description: GitData — Rust workspace (apihost / githost / synchost / mails / migrate)
4type: application
5version: 0.1.0
6appVersion: "1.0.0"
Added chart/values.yaml chart/values.yaml +177 −0 View chart/values.yaml
@@ -0,0 +1,177 @@
1# Default values for gitdata.
2nameOverride: ""
3fullnameOverride: ""
4
5image:
6 repository: gitdata
7 # 留空则用 Chart.appVersion 作为 tag
8 tag: ""
9 pullPolicy: IfNotPresent
10imagePullSecrets: []
11
12serviceAccount:
13 create: true
14 name: ""
15 annotations: {}
16
17# ---------------------------------------------------------------------------
18# 运行时配置。全部通过 Figment 的 APP_* 环境变量注入(见 docs/技术架构.md §12)。
19# config.env -> ConfigMap(非敏感)
20# secret.env -> Secret(敏感);生产建议改用 existingSecret + 外部密钥管理
21# ---------------------------------------------------------------------------
22
23# 非敏感配置(string->string,值会被转成 APP_* 环境变量)
24config:
25 env:
26 APP_REDIS__URL: "redis://redis-master:6379"
27 APP_S3__ENDPOINT: ""
28 APP_S3__BUCKET: ""
29 APP_S3__REGION: "us-east-1"
30 APP_S3__PATH_STYLE: "true"
31 # 读写库/副本、邮件、配额等其余段均可在此覆盖,例如:
32 # APP_DATABASE__REPLICAS: '[{url="postgres://readonly@pg:5432/gitdata"}]'
33 APP_EMAIL__ENABLED: "false"
34 APP_EMAIL_QUEUE__ENABLED: "false"
35
36# 敏感配置(渲染为 Secret)。注意 AppConfig 的 Debug 会带出密钥,
37# 切勿在任何日志里 {:?} 打印配置。
38secret:
39 # 留空则不创建 Secret,仅使用 existingSecret
40 create: true
41 existingSecret: ""
42 env:
43 APP_DATABASE__URL: "postgres://postgres:CHANGE_ME@postgres:5432/gitdata"
44 APP_SESSION__KEY: "" # >=64 字节随机串
45 APP_POW__MAC_KEY: "" # base64 >=32 字节
46 APP_AUTH__TOTP_ENCRYPTION_KEY: "" # base64 >=32 字节(实测必填)
47 APP_S3__ACCESS_KEY_ID: ""
48 APP_S3__SECRET_ACCESS_KEY: ""
49 APP_EMAIL__SMTP_PASSWORD: ""
50 APP_CHAT__TICKET_SECRET: ""
51
52podSecurityContext:
53 fsGroup: 10001
54securityContext:
55 runAsNonRoot: true
56 runAsUser: 10001
57 allowPrivilegeEscalation: false
58 capabilities:
59 drop: ["ALL"]
60
61nodeSelector: {}
62tolerations: []
63affinity: {}
64podAnnotations: {}
65podLabels: {}
66
67# ---------------------------------------------------------------------------
68# 组件
69# ---------------------------------------------------------------------------
70
71migrate:
72 enabled: true # pre-install / pre-upgrade hook Job
73 resources:
74 requests: { cpu: 100m, memory: 128Mi }
75 limits: { memory: 512Mi }
76 extraEnv: []
77
78apihost:
79 enabled: true
80 replicaCount: 2
81 port: 3000
82 resources:
83 requests: { cpu: 250m, memory: 256Mi }
84 limits: { memory: 1Gi }
85 autoscaling:
86 enabled: false
87 minReplicas: 2
88 maxReplicas: 8
89 targetCPUUtilizationPercentage: 70
90 maxSurge: 1
91 maxUnavailable: 0
92 podAntiAffinity: soft # soft | hard | ""
93 topologySpreadConstraints: []
94 extraEnv: []
95 pdb:
96 enabled: true
97 minAvailable: 1
98
99githost:
100 enabled: true
101 # SSH host key 落在共享 PVC 上;多副本前请预先放入同一把 key,
102 # 否则每个 Pod 各自生成会导致客户端 known_hosts 抖动
103 replicaCount: 1
104 httpPort: 9418
105 ssh:
106 enabled: true
107 # 非 root 进程绑不了 22,容器内监听 2222,Service 映射 22->2222
108 containerPort: 2222
109 service:
110 type: LoadBalancer
111 port: 22
112 nodePort: "" # type=NodePort 时可选
113 annotations: {}
114 externalIPs: []
115 # clone URL(对外展示/拼接用),一般填 LB 域名或 IP
116 cloneHost: ""
117 clonePort: 22
118 resources:
119 requests: { cpu: 250m, memory: 256Mi }
120 limits: { memory: 1Gi }
121 extraEnv: []
122 pdb:
123 enabled: false
124 minAvailable: 1
125
126synchost:
127 enabled: true
128 replicaCount: 2
129 resources:
130 requests: { cpu: 200m, memory: 192Mi }
131 limits: { memory: 768Mi }
132 extraEnv: []
133
134mails:
135 enabled: true
136 replicaCount: 1
137 resources:
138 requests: { cpu: 50m, memory: 64Mi }
139 limits: { memory: 256Mi }
140 extraEnv: []
141
142# ---------------------------------------------------------------------------
143# 存储:githost 与 synchost 共享 bare 仓库,需要 RWX
144# ---------------------------------------------------------------------------
145persistence:
146 repos:
147 enabled: true
148 size: 50Gi
149 storageClassName: "" # "" = 默认 StorageClass
150 accessModes: ["ReadWriteMany"]
151 existingClaim: ""
152 mountPath: /opt/gitdata
153
154# ---------------------------------------------------------------------------
155# Ingress:同源 TLS 终结;*.git -> githost,其余(含 WS)-> apihost
156# 默认按 ingress-nginx 生成(regex path + ImplementationSpecific)
157# ---------------------------------------------------------------------------
158ingress:
159 enabled: true
160 className: nginx
161 host: gitdata.example.com
162 # githost 路由匹配(ingress-nginx 需 use-regex)。其它控制器可改为独立 host/path
163 githostPath: "/(.*\\.git)(/|$)"
164 annotations: {}
165 tls:
166 enabled: true
167 secretName: "" # 留空 = <fullname>-tls
168 clusterIssuer: "" # 填 cert-manager ClusterIssuer 自动签发
169 # 大文件 push / 长 RPC
170 proxyBodySize: "0" # 0 = 不限制
171 proxyReadTimeout: 3600
172 proxySendTimeout: 3600
173 proxyConnectTimeout: 60
174
175metrics:
176 # OTLP 推送(无 scrape 端点,见 §13)
177 otlpEndpoint: ""
Modified Dockerfile Dockerfile +2 −0 View Dockerfile
@@ -34,10 +34,12 @@
3434########## runtime ##########
3535FROM debian:bookworm-slim
3636
37# git: githost/synchost spawn system git; openssh-client: ssh-keygen for host key
3738RUN apt-get update && apt-get install -y --no-install-recommends \
3839 git \
3940 ca-certificates \
4041 libssl3 \
42 openssh-client \
4143 && rm -rf /var/lib/apt/lists/* \
4244 && useradd --system --create-home --uid 10001 gitdata \
4345 && mkdir -p /opt/gitdata/repos /opt/gitdata/objects \