mirror of
https://github.com/GothenburgBitFactory/taskchampion-sync-server.git
synced 2026-07-16 16:35:41 +00:00
Compare commits
2 Commits
240af34978
...
taskchampi
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f78f2d4c5 | |||
| b5eb61a43d |
2
.github/workflows/helm-test.yml
vendored
2
.github/workflows/helm-test.yml
vendored
@ -49,7 +49,6 @@ jobs:
|
||||
grep -q 'kind: Deployment' /tmp/helm-sqlite.yaml
|
||||
grep -q 'kind: Service' /tmp/helm-sqlite.yaml
|
||||
grep -q 'kind: Ingress' /tmp/helm-sqlite.yaml
|
||||
grep -q 'kind: ServiceAccount' /tmp/helm-sqlite.yaml
|
||||
|
||||
# Verify SQLite-specific rendering
|
||||
grep -q 'emptyDir' /tmp/helm-sqlite.yaml
|
||||
@ -82,7 +81,6 @@ jobs:
|
||||
grep -q 'kind: Deployment' /tmp/helm-postgres.yaml
|
||||
grep -q 'kind: Service' /tmp/helm-postgres.yaml
|
||||
grep -q 'kind: Secret' /tmp/helm-postgres.yaml
|
||||
grep -q 'kind: ServiceAccount' /tmp/helm-postgres.yaml
|
||||
|
||||
# Verify PostgreSQL-specific rendering
|
||||
grep -q 'kind: HTTPRoute' /tmp/helm-postgres.yaml
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# Patterns to ignore when building the Helm chart
|
||||
.git
|
||||
.gitignore
|
||||
*.md
|
||||
examples/
|
||||
.DS_Store
|
||||
*.tgz
|
||||
|
||||
@ -2,7 +2,7 @@ apiVersion: v2
|
||||
name: taskchampion-sync-server
|
||||
description: A Helm chart for deploying TaskChampion Sync Server on Kubernetes
|
||||
type: application
|
||||
version: 0.1.2
|
||||
version: 0.2.1
|
||||
appVersion: "0.7.0"
|
||||
keywords:
|
||||
- taskchampion
|
||||
|
||||
@ -10,9 +10,12 @@ postgres:
|
||||
clientIdSecret: "taskchampion-client-ids"
|
||||
|
||||
env:
|
||||
RUST_LOG: debug
|
||||
LISTEN: "0.0.0.0:8080"
|
||||
CREATE_CLIENTS: "false"
|
||||
- name: RUST_LOG
|
||||
value: debug
|
||||
- name: LISTEN
|
||||
value: "0.0.0.0:8080"
|
||||
- name: CREATE_CLIENTS
|
||||
value: "false"
|
||||
|
||||
replicas:
|
||||
enabled: true
|
||||
@ -20,7 +23,7 @@ replicas:
|
||||
|
||||
image:
|
||||
pullSecrets:
|
||||
- my-registry-secret
|
||||
- name: my-registry-secret
|
||||
|
||||
httpRoute:
|
||||
enabled: true
|
||||
|
||||
@ -12,9 +12,12 @@ postgres:
|
||||
clientIdSecret: "taskchampion-client-ids"
|
||||
|
||||
env:
|
||||
RUST_LOG: info
|
||||
LISTEN: "0.0.0.0:8080"
|
||||
CREATE_CLIENTS: "false"
|
||||
- name: RUST_LOG
|
||||
value: info
|
||||
- name: LISTEN
|
||||
value: "0.0.0.0:8080"
|
||||
- name: CREATE_CLIENTS
|
||||
value: "false"
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
|
||||
46
helm/taskchampion-sync-server/templates/NOTES.txt
Normal file
46
helm/taskchampion-sync-server/templates/NOTES.txt
Normal file
@ -0,0 +1,46 @@
|
||||
Thank you for installing {{ .Chart.Name }} — version {{ .Chart.Version }} (app: {{ .Chart.AppVersion }}).
|
||||
|
||||
## Storage Backend
|
||||
|
||||
{{- if eq .Values.sqlite.enabled true }}
|
||||
**SQLite** — Data is stored at `{{ .Values.sqlite.dataDir }}`.
|
||||
{{- if .Values.sqlite.persistence.enabled }}
|
||||
PersistentVolumeClaim: `{{ include "taskchampion-sync-server.fullname" . }}-pvc`
|
||||
{{- else if .Values.sqlite.existingPV }}
|
||||
Using existing PVC: `{{ .Values.sqlite.existingPV }}`
|
||||
{{- else }}
|
||||
Using an emptyDir volume (ephemeral — data is lost on pod restart).
|
||||
Set `sqlite.persistence.enabled=true` for persistent storage.
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if eq .Values.postgres.enabled true }}
|
||||
**PostgreSQL** — Connection URI stored in Secret `{{ include "taskchampion-sync-server.postgres-secret-name" . }}`.
|
||||
Host: {{ .Values.postgres.host }}:{{ .Values.postgres.port }}
|
||||
Database: {{ .Values.postgres.database }}
|
||||
{{- end }}
|
||||
|
||||
## Verify the Deployment
|
||||
|
||||
kubectl get pods -l {{ include "taskchampion-sync-server.selectorLabels" . | replace ": " "=" | replace "\n" "," | trimSuffix "," }}
|
||||
|
||||
## Check Pod Logs
|
||||
|
||||
kubectl logs -l {{ include "taskchampion-sync-server.selectorLabels" . | replace ": " "=" | replace "\n" "," | trimSuffix "," }}
|
||||
|
||||
## Test the API
|
||||
|
||||
kubectl port-forward svc/{{ include "taskchampion-sync-server.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }}
|
||||
curl http://localhost:{{ .Values.service.port }}/
|
||||
|
||||
## View Connection Secret (PostgreSQL only)
|
||||
|
||||
{{- if eq .Values.postgres.enabled true }}
|
||||
kubectl get secret {{ include "taskchampion-sync-server.postgres-secret-name" . }} -o jsonpath="{.data.connection}" | base64 -d
|
||||
{{- end }}
|
||||
|
||||
## Configuration
|
||||
|
||||
For full configuration options, see:
|
||||
|
||||
https://github.com/GothenburgBitFactory/taskchampion-sync-server
|
||||
@ -23,6 +23,7 @@ taskchampion-sync-server helpers
|
||||
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
app.kubernetes.io/name: {{ include "taskchampion-sync-server.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: server
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
@ -32,13 +33,6 @@ app.kubernetes.io/name: {{ include "taskchampion-sync-server.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "taskchampion-sync-server.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "taskchampion-sync-server.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "taskchampion-sync-server.postgres-connection" -}}
|
||||
{{- $host := .Values.postgres.host -}}
|
||||
@ -99,4 +93,8 @@ app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
|
||||
{{- define "taskchampion-sync-server.postgres-secret-name" -}}
|
||||
{{- printf "%s-connection" .Release.Name -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "taskchampion-sync-server.serviceAccountName" -}}
|
||||
{{- default (include "taskchampion-sync-server.fullname" .) .Values.serviceAccount.name -}}
|
||||
{{- end -}}
|
||||
@ -18,10 +18,13 @@ spec:
|
||||
labels:
|
||||
{{- include "taskchampion-sync-server.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
|
||||
{{- with .Values.image.pullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
serviceAccountName: {{ include "taskchampion-sync-server.fullname" . }}
|
||||
{{- else if .Values.serviceAccount.name }}
|
||||
serviceAccountName: {{ .Values.serviceAccount.name }}
|
||||
serviceAccountName: {{ include "taskchampion-sync-server.serviceAccountName" . }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 8 }}
|
||||
@ -32,6 +35,8 @@ spec:
|
||||
imagePullPolicy: {{ .Values.postgres.initContainer.imagePullPolicy }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
runAsUser: 999
|
||||
env:
|
||||
- name: PGURI
|
||||
valueFrom:
|
||||
@ -90,11 +95,18 @@ spec:
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1092
|
||||
readOnlyRootFilesystem: true
|
||||
{{- if eq .Values.postgres.enabled true }}
|
||||
command:
|
||||
- /bin/taskchampion-sync-server-postgres
|
||||
{{- else }}
|
||||
command:
|
||||
- /bin/taskchampion-sync-server
|
||||
{{- end }}
|
||||
env:
|
||||
{{- range $name, $value := .Values.env }}
|
||||
- name: {{ $name }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- toYaml .Values.env | nindent 12 }}
|
||||
{{- if .Values.clientIdSecret }}
|
||||
- name: CLIENT_ID
|
||||
valueFrom:
|
||||
@ -117,9 +129,24 @@ spec:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.targetPort }}
|
||||
protocol: TCP
|
||||
{{- with .Values.resources }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
{{- if eq .Values.postgres.enabled true }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- toYaml .Values.postgres.resources | nindent 12 }}
|
||||
{{- else }}
|
||||
resources:
|
||||
{{- toYaml .Values.sqlite.resources | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if eq .Values.sqlite.enabled true }}
|
||||
volumeMounts:
|
||||
|
||||
@ -18,7 +18,10 @@ spec:
|
||||
{{- toYaml .Values.ingress.tls | nindent 4 }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- $svcName := include "taskchampion-sync-server.fullname" . -}}
|
||||
{{- $svcPort := $.Values.service.port -}}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
{{- if kindIs "string" . }}
|
||||
- host: {{ . | quote }}
|
||||
http:
|
||||
paths:
|
||||
@ -26,8 +29,30 @@ spec:
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "taskchampion-sync-server.fullname" $ }}
|
||||
name: {{ $svcName }}
|
||||
port:
|
||||
number: {{ $.Values.service.port }}
|
||||
number: {{ $svcPort }}
|
||||
{{- else }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path | default "/" | quote }}
|
||||
pathType: {{ .pathType | default "Prefix" }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ $svcName }}
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
{{- else }}
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: {{ $svcName }}
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@ -2,37 +2,8 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "taskchampion-sync-server.fullname" . }}
|
||||
labels:
|
||||
{{- include "taskchampion-sync-server.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ include "taskchampion-sync-server.fullname" . }}-secret-manager
|
||||
labels:
|
||||
{{- include "taskchampion-sync-server.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create", "get", "update", "patch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ include "taskchampion-sync-server.fullname" . }}-secret-binding
|
||||
labels:
|
||||
{{- include "taskchampion-sync-server.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: {{ include "taskchampion-sync-server.fullname" . }}-secret-manager
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "taskchampion-sync-server.fullname" . }}
|
||||
name: {{ include "taskchampion-sync-server.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end -}}
|
||||
labels:
|
||||
{{- include "taskchampion-sync-server.labels" . | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
{{- /* Validate imagePullSecrets entries are objects (not plain strings) */ -}}
|
||||
{{- range $i, $secret := .Values.image.pullSecrets -}}
|
||||
{{- if not (kindIs "map" $secret) -}}
|
||||
{{- fail (printf "ERROR: image.pullSecrets[%d] is a string (%q). Each entry must be an object with a 'name' key, e.g.\n image:\n pullSecrets:\n - name: %s" $i $secret $secret) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- if and (eq .Values.sqlite.enabled false) (eq .Values.postgres.enabled false) -}}
|
||||
{{- fail "ERROR: Exactly one storage backend must be enabled. Either sqlite.enabled or postgres.enabled must be true." -}}
|
||||
{{- end -}}
|
||||
|
||||
@ -9,6 +9,9 @@ image:
|
||||
tag: "0.7.0"
|
||||
pullPolicy: IfNotPresent
|
||||
pullSecrets: []
|
||||
# pullSecrets expects a list of objects with a "name" key:
|
||||
# pullSecrets:
|
||||
# - name: my-registry-cred
|
||||
|
||||
# Existing secret containing client IDs (comma-separated UUIDs)
|
||||
# Expected key: client-ids
|
||||
@ -16,10 +19,19 @@ clientIdSecret: ""
|
||||
|
||||
# Environment variables passed directly to the container
|
||||
# NOTE: DATA_DIR and CONNECTION are set automatically based on backend
|
||||
# To add secret/configMap references, use valueFrom:
|
||||
# - name: MY_SECRET_VAR
|
||||
# valueFrom:
|
||||
# secretKeyRef:
|
||||
# name: my-secret
|
||||
# key: my-key
|
||||
env:
|
||||
RUST_LOG: info
|
||||
LISTEN: "0.0.0.0:8080"
|
||||
CREATE_CLIENTS: "true"
|
||||
- name: RUST_LOG
|
||||
value: info
|
||||
- name: LISTEN
|
||||
value: "0.0.0.0:8080"
|
||||
- name: CREATE_CLIENTS
|
||||
value: "true"
|
||||
|
||||
# Service configuration
|
||||
service:
|
||||
@ -28,6 +40,14 @@ service:
|
||||
targetPort: 8080
|
||||
|
||||
# Ingress configuration
|
||||
# Each host can be a string (simple) or a map with path rules:
|
||||
# hosts:
|
||||
# - host: app.example.com
|
||||
# paths:
|
||||
# - path: /
|
||||
# pathType: Prefix
|
||||
# - path: /api
|
||||
# pathType: Exact
|
||||
ingress:
|
||||
enabled: false
|
||||
className: ""
|
||||
@ -71,20 +91,21 @@ httpRoute:
|
||||
path: "/"
|
||||
port: 8080
|
||||
|
||||
# Resource limits and requests
|
||||
resources: {}
|
||||
# limits:
|
||||
# memory: 128Mi
|
||||
# cpu: 100m
|
||||
# requests:
|
||||
# memory: 64Mi
|
||||
# cpu: 50m
|
||||
|
||||
# Replica configuration (only applies when postgres is enabled)
|
||||
replicas:
|
||||
enabled: false
|
||||
count: 1
|
||||
|
||||
# ServiceAccount configuration
|
||||
# The app does not access the Kubernetes API, so no RBAC permissions are needed.
|
||||
# A dedicated ServiceAccount is created to give the pod a stable identity
|
||||
# for network policies, pod security, or future RBAC.
|
||||
serviceAccount:
|
||||
# create specifies whether a ServiceAccount should be created
|
||||
create: true
|
||||
# name sets the ServiceAccount name
|
||||
name: taskchampion-sync-server
|
||||
|
||||
# Security context for the pod
|
||||
# NOTE: runAsUser and runAsGroup are intentionally unset.
|
||||
# The Docker entrypoint requires root to chown the data directory and then
|
||||
@ -96,6 +117,15 @@ securityContext:
|
||||
sqlite:
|
||||
enabled: false
|
||||
dataDir: /var/lib/taskchampion-sync-server/data
|
||||
# Resource limits and requests
|
||||
resources:
|
||||
limits:
|
||||
memory: 25Mi
|
||||
cpu: 100m
|
||||
requests:
|
||||
# 5Mi is sufficient for the SQLite image
|
||||
memory: 5Mi
|
||||
cpu: 10m
|
||||
existingPV: ""
|
||||
emptyDir:
|
||||
sizeLimit: ""
|
||||
@ -107,12 +137,6 @@ sqlite:
|
||||
storageClass: ""
|
||||
existingClaim: ""
|
||||
|
||||
# Service account configuration
|
||||
serviceAccount:
|
||||
create: true # Default: automatically create service account
|
||||
name: "" # Optional: use existing service account
|
||||
annotations: {}
|
||||
|
||||
# PostgreSQL configuration
|
||||
postgres:
|
||||
enabled: false
|
||||
@ -134,3 +158,12 @@ postgres:
|
||||
# Override the schema URL. Defaults to the official schema for this chart's appVersion.
|
||||
# e.g. https://raw.githubusercontent.com/GothenburgBitFactory/taskchampion-sync-server/v0.7.0/postgres/schema.sql
|
||||
schemaUrl: ""
|
||||
# Resource limits and requests
|
||||
resources:
|
||||
limits:
|
||||
memory: 100Mi
|
||||
cpu: 100m
|
||||
requests:
|
||||
# 20Mi is the minimum for the Postgres image
|
||||
memory: 20Mi
|
||||
cpu: 10m
|
||||
|
||||
Reference in New Issue
Block a user