From 01d1a49a59d81a2206e14d629c1f116abc44eb49 Mon Sep 17 00:00:00 2001 From: abearixong Date: Wed, 14 Jan 2026 12:37:31 +0800 Subject: [PATCH] update --- .cnb.yml | 43 ++++ .gitignore | 1 + PRD.md | 54 +++++ docker/Dockerfile | 22 +++ package.json | 13 ++ pocketbase/.helmignore | 23 +++ pocketbase/Chart.yaml | 16 ++ pocketbase/README.md | 71 +++++++ pocketbase/templates/NOTES.txt | 25 +++ pocketbase/templates/_helpers.tpl | 49 +++++ pocketbase/templates/configmap.yaml | 24 +++ pocketbase/templates/deployment.yaml | 185 ++++++++++++++++++ pocketbase/templates/hpa.yaml | 40 ++++ pocketbase/templates/httproute.yaml | 29 +++ pocketbase/templates/ingress.yaml | 54 +++++ pocketbase/templates/service.yaml | 27 +++ pocketbase/templates/serviceaccount.yaml | 23 +++ .../templates/tests/test-connection.yaml | 24 +++ pocketbase/values-production.yaml | 82 ++++++++ pocketbase/values.yaml | 101 ++++++++++ readme.md | 110 +++++++++++ 常用命令.md | 21 ++ 22 files changed, 1037 insertions(+) create mode 100644 .cnb.yml create mode 100644 .gitignore create mode 100644 PRD.md create mode 100644 docker/Dockerfile create mode 100644 package.json create mode 100644 pocketbase/.helmignore create mode 100644 pocketbase/Chart.yaml create mode 100644 pocketbase/README.md create mode 100644 pocketbase/templates/NOTES.txt create mode 100644 pocketbase/templates/_helpers.tpl create mode 100644 pocketbase/templates/configmap.yaml create mode 100644 pocketbase/templates/deployment.yaml create mode 100644 pocketbase/templates/hpa.yaml create mode 100644 pocketbase/templates/httproute.yaml create mode 100644 pocketbase/templates/ingress.yaml create mode 100644 pocketbase/templates/service.yaml create mode 100644 pocketbase/templates/serviceaccount.yaml create mode 100644 pocketbase/templates/tests/test-connection.yaml create mode 100644 pocketbase/values-production.yaml create mode 100644 pocketbase/values.yaml create mode 100644 readme.md create mode 100644 常用命令.md diff --git a/.cnb.yml b/.cnb.yml new file mode 100644 index 0000000..7276c88 --- /dev/null +++ b/.cnb.yml @@ -0,0 +1,43 @@ +# .cnb.yml +include: + - https://cnb.cool/kevisual/cnb/-/blob/main/.cnb/template.yml + +.common_env: &common_env + env: + TO_REPO: kevisual/cnb + TO_URL: git.xiongxiao.me + imports: + - https://cnb.cool/kevisual/env/-/blob/main/.env.development + +$: + vscode: + - docker: + image: docker.cnb.cool/kevisual/dev-env:latest + services: + - vscode + - docker + imports: !reference [.common_env, imports] + # 开发环境启动后会执行的任务 + # stages: + # - name: pnpm install + # script: pnpm install + +.common_sync_to_gitea: &common_sync_to_gitea + - <<: *common_env + services: !reference [.common_sync_to_gitea_template, services] + stages: !reference [.common_sync_to_gitea_template, stages] + +.common_sync_from_gitea: &common_sync_from_gitea + - <<: *common_env + services: !reference [.common_sync_from_gitea_template, services] + stages: !reference [.common_sync_from_gitea_template, stages] + +main: + web_trigger_sync_to_gitea: + - <<: *common_sync_to_gitea + web_trigger_sync_from_gitea: + - <<: *common_sync_from_gitea + api_trigger_sync_to_gitea: + - <<: *common_sync_to_gitea + api_trigger_sync_from_gitea: + - <<: *common_sync_from_gitea \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/PRD.md b/PRD.md new file mode 100644 index 0000000..24dbc14 --- /dev/null +++ b/PRD.md @@ -0,0 +1,54 @@ +# PocketBase Helm Chart 设计文档 + +## 概述 + +使用 Helm Chart 管理多个 PocketBase 实例,每个实例对应独立的域名。 + +使用k3s集群部署,Traefik作为Ingress控制器,SQLite作为本地存储。 + +## 需求 + +- 批量部署多个 PocketBase Pod +- 每个实例绑定独立域名:`{id}.pb.xiongxiao.me` +- 使用 Traefik 作为反向代理和入口控制器 +- 通过 Helm 实现统一配置管理 +- 使用 SQLite 本地存储(默认) + +## 架构 + +``` +Traefik Ingress + │ + ▼ +┌─────────────────────────────────────┐ +│ Helm Release (values.id) │ +│ ├── pocketbase-{id} Service │ +│ │ │ │ +│ │ ▼ │ +│ │ pocketbase-{id} Pod │ +│ │ │ │ +│ └─────────┼──→ {id}.pb.xiongxiao.me + │ + ▼ + SQLite (本地存储) +``` + +## 配置方式 + +通过 `values.yaml` 配置实例列表: + +```yaml +instances: + - id: "app1" + domain: "app1.pb.xiongxiao.me" + replicaCount: 1 + - id: "app2" + domain: "app2.pb.xiongxiao.me" + replicaCount: 1 +``` + +## 部署命令 + +```bash +helm install pocketbase ./pocketbase -f values.yaml +``` diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..63c870c --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,22 @@ +FROM alpine:latest + +ARG PB_VERSION=0.35.1 + +RUN apk add --no-cache \ + unzip \ + ca-certificates + +# download and unzip PocketBase +ADD https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip /tmp/pb.zip +RUN unzip /tmp/pb.zip -d /pb/ + +# uncomment to copy the local pb_migrations dir into the image +# COPY ./pb_migrations /pb/pb_migrations + +# uncomment to copy the local pb_hooks dir into the image +# COPY ./pb_hooks /pb/pb_hooks + +EXPOSE 8080 + +# start PocketBase +CMD ["/pb/pocketbase", "serve", "--http=0.0.0.0:8080"] \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..c1155cc --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "datapod-helm", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "packageManager": "pnpm@10.26.0" +} diff --git a/pocketbase/.helmignore b/pocketbase/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/pocketbase/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/pocketbase/Chart.yaml b/pocketbase/Chart.yaml new file mode 100644 index 0000000..ac3c7ae --- /dev/null +++ b/pocketbase/Chart.yaml @@ -0,0 +1,16 @@ +apiVersion: v2 +name: pocketbase +description: PocketBase Helm Chart - Deploy multiple PocketBase instances with Traefik ingress +type: application +version: 0.1.0 +appVersion: "0.35.1" +home: https://pocketbase.io/ +icon: https://pocketbase.io/images/logo.png +keywords: + - pocketbase + - backend + - database + - traefik +maintainers: + - name: datapod + email: admin@xiongxiao.me diff --git a/pocketbase/README.md b/pocketbase/README.md new file mode 100644 index 0000000..905de66 --- /dev/null +++ b/pocketbase/README.md @@ -0,0 +1,71 @@ +# PocketBase Helm Chart + +部署多个 PocketBase 实例,支持 Traefik ingress。 + +## 前置条件 + +- Kubernetes 1.19+ +- Helm 3.2.0+ +- Traefik ingress 控制器 +- StorageClass(用于持久化存储) + +## 安装 + +```bash +helm install my-pocketbase ./pocketbase -f values.yaml +``` + +## 配置 + +### instances + +部署的 PocketBase 实例列表: + +```yaml +instances: + - id: "app1" + domain: "app1.pb.xiongxiao.me" + replicaCount: 1 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + - id: "app2" + domain: "app2.pb.xiongxiao.me" + replicaCount: 1 +``` + +### persistence + +持久化配置: + +```yaml +persistence: + enabled: true + storageClass: "local-path" + size: 5Gi + accessMode: ReadWriteOnce +``` + +## 升级 + +```bash +helm upgrade my-pocketbase ./pocketbase -f values.yaml +``` + +## 卸载 + +```bash +helm uninstall my-pocketbase +``` + +这将删除所有 PocketBase 实例及其 PVC。 + +## 技术说明 + +- **数据库**: 使用 SQLite 本地存储,数据保存在 `/pb/pb_data` 目录 +- **持久化**: 通过 PVC 实现数据持久化 +- **入口**: 使用 Traefik IngressRoute 配置路由 diff --git a/pocketbase/templates/NOTES.txt b/pocketbase/templates/NOTES.txt new file mode 100644 index 0000000..fae81f0 --- /dev/null +++ b/pocketbase/templates/NOTES.txt @@ -0,0 +1,25 @@ +PocketBase Helm Chart + +{{- if not .Values.instances }} +WARNING: No instances configured! Add instances to your values.yaml file. + +Example: +instances: + - id: "app1" + domain: "app1.pb.xiongxiao.me" + replicaCount: 1 +{{- else }} +{{- range .Values.instances }} +PocketBase instance "{{ .id }}" has been deployed! + +Access it at: https://{{ .domain }} + +Admin UI: https://{{ .domain }}/_/ + - Email: Check the secret: pocketbase-{{ .id }}-secrets + - Password: Check the secret: pocketbase-{{ .id }}-secrets + +To get the admin password: + kubectl get secret pocketbase-{{ .id }}-secrets -o jsonpath='{.data.admin-password}' | base64 -d + +{{- end }} +{{- end }} diff --git a/pocketbase/templates/_helpers.tpl b/pocketbase/templates/_helpers.tpl new file mode 100644 index 0000000..c03b21e --- /dev/null +++ b/pocketbase/templates/_helpers.tpl @@ -0,0 +1,49 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "pocketbase.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "pocketbase.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 }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "pocketbase.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "pocketbase.labels" -}} +helm.sh/chart: {{ include "pocketbase.chart" . }} +{{ include "pocketbase.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "pocketbase.selectorLabels" -}} +app.kubernetes.io/name: {{ include "pocketbase.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/pocketbase/templates/configmap.yaml b/pocketbase/templates/configmap.yaml new file mode 100644 index 0000000..1c4b2b3 --- /dev/null +++ b/pocketbase/templates/configmap.yaml @@ -0,0 +1,24 @@ +{{- /* + Generate config for each PocketBase instance +*/ -}} +{{- range .Values.instances }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: pocketbase-{{ .id }}-config + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $ | nindent 4 }} +data: + PB_DATA: /pb/pb_data + PB_STATIC: /pb/static + # SMTP Configuration (optional) + {{- if .smtp }} + PB_EMAIL_SMTP_HOST: {{ .smtp.host | quote }} + PB_EMAIL_SMTP_PORT: {{ .smtp.port | quote }} + PB_EMAIL_SMTP_USERNAME: {{ .smtp.username | quote }} + PB_EMAIL_SMTP_PASSWORD: {{ .smtp.password | quote }} + {{- end }} +{{- end }} diff --git a/pocketbase/templates/deployment.yaml b/pocketbase/templates/deployment.yaml new file mode 100644 index 0000000..d013d15 --- /dev/null +++ b/pocketbase/templates/deployment.yaml @@ -0,0 +1,185 @@ +{{- /* + Generate deployments for each PocketBase instance +*/ -}} +{{- $global := .Values.global }} +{{- $image := .Values.image }} +{{- $persistence := .Values.persistence }} +{{- $securityContext := .Values.securityContext }} +{{- $podSecurityContext := .Values.podSecurityContext }} +{{- $resources := .Values.resources }} +{{- range .Values.instances }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pocketbase-{{ .id }} + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $ | nindent 4 }} +spec: + replicas: {{ .replicaCount | default 1 }} + selector: + matchLabels: + app: pocketbase + instance: {{ .id }} + template: + metadata: + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $ | nindent 8 }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") $ | sha256sum }} + spec: + {{- $instanceId := .id }} + {{- with $.Values.serviceAccount }} + {{- $serviceAccountName := $.Values.serviceAccount.name }} + {{- if not $serviceAccountName }} + {{- $serviceAccountName = printf "pocketbase-%s" $instanceId }} + {{- end }} + serviceAccountName: {{ $serviceAccountName }} + {{- end }} + {{- with $global.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml $podSecurityContext | nindent 8 }} + containers: + - name: pocketbase + image: {{ $image.repository }}:{{ $image.tag }} + imagePullPolicy: {{ $image.pullPolicy }} + command: + - /pocketbase + - serve + - --http=0.0.0.0:8090 + ports: + - name: http + containerPort: 8090 + protocol: TCP + env: + # Admin email (optional - set via admin creation API) + - name: PB_ADMIN_EMAIL + value: "admin@{{ .domain }}" + - name: PB_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: pocketbase-{{ .id }}-secrets + key: admin-password + {{- if $persistence.enabled }} + volumeMounts: + - name: data + mountPath: /pb/pb_data + - name: static + mountPath: /pb/static + {{- end }} + livenessProbe: + httpGet: + path: /api/health + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /api/health + port: http + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + {{- if .resources }} + resources: + {{- toYaml .resources | nindent 12 }} + {{- else }} + resources: + {{- toYaml $resources | nindent 12 }} + {{- end }} + securityContext: + {{- toYaml $securityContext | nindent 12 }} + {{- if $persistence.enabled }} + volumes: + - name: data + persistentVolumeClaim: + claimName: pocketbase-{{ .id }}-pvc + - name: static + persistentVolumeClaim: + claimName: pocketbase-{{ .id }}-static-pvc + {{- end }} + {{- with $.Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $.Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $.Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $.Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} +--- +{{- /* + Create Secret for each instance +*/ -}} +apiVersion: v1 +kind: Secret +metadata: + name: pocketbase-{{ .id }}-secrets + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $ | nindent 4 }} +type: Opaque +stringData: + admin-password: {{ randAlphaNum 16 | quote }} +--- +{{- /* + Create PVC for each instance +*/ -}} +{{- if $persistence.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pocketbase-{{ .id }}-pvc + labels: + app: pocketbase + instance: {{ .id }} + type: data + {{- include "pocketbase.labels" $ | nindent 4 }} +spec: + accessModes: + - {{ $persistence.accessMode | default "ReadWriteOnce" }} + resources: + requests: + storage: {{ $persistence.size | default "1Gi" }} + {{- if $persistence.storageClass }} + storageClassName: {{ $persistence.storageClass }} + {{- end }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pocketbase-{{ .id }}-static-pvc + labels: + app: pocketbase + instance: {{ .id }} + type: static + {{- include "pocketbase.labels" $ | nindent 4 }} +spec: + accessModes: + - {{ $persistence.accessMode | default "ReadWriteOnce" }} + resources: + requests: + storage: 100Mi + {{- if $persistence.storageClass }} + storageClassName: {{ $persistence.storageClass }} + {{- end }} +{{- end }} +{{- end }} diff --git a/pocketbase/templates/hpa.yaml b/pocketbase/templates/hpa.yaml new file mode 100644 index 0000000..8553546 --- /dev/null +++ b/pocketbase/templates/hpa.yaml @@ -0,0 +1,40 @@ +{{- /* + Generate HPA for each PocketBase instance +*/ -}} +{{- if .Values.autoscaling.enabled }} +{{- range .Values.instances }} +--- +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: pocketbase-{{ .id }} + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $ | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: pocketbase-{{ .id }} + minReplicas: {{ .replicaCount | default 1 }} + 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 }} +{{- end }} diff --git a/pocketbase/templates/httproute.yaml b/pocketbase/templates/httproute.yaml new file mode 100644 index 0000000..3a84ff3 --- /dev/null +++ b/pocketbase/templates/httproute.yaml @@ -0,0 +1,29 @@ +{{- /* + HTTPRoute for Gateway API (alternative to IngressRoute) + Unused when Traefik IngressRoute is enabled +*/ -}} +{{- /* +{{- range .Values.instances }} +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: pocketbase-{{ .id }} + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $ | nindent 4 }} +spec: + parentRefs: + - name: {{ $.Values.httpRoute.gatewayName | default "traefik-gateway" }} + hostnames: + - {{ .domain }} + rules: + - matches: + - path: + value: / + backendRefs: + - name: pocketbase-{{ .id }} + port: 80 +{{- end }} +*/ -}} diff --git a/pocketbase/templates/ingress.yaml b/pocketbase/templates/ingress.yaml new file mode 100644 index 0000000..4e9e969 --- /dev/null +++ b/pocketbase/templates/ingress.yaml @@ -0,0 +1,54 @@ +{{- /* + Generate IngressRoute for Traefik for each PocketBase instance +*/ -}} +{{- $ingress := .Values.ingress }} +{{- range .Values.instances }} +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: pocketbase-{{ .id }} + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $ | nindent 4 }} + {{- with $ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + entryPoints: + - web + - websecure + routes: + - match: Host(`{{ .domain }}`) + kind: Rule + services: + - name: pocketbase-{{ .id }} + port: 80 + middlewares: + - name: pocketbase-{{ .id }}-headers + namespace: default +--- +{{- /* + Middleware for security headers +*/ -}} +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: pocketbase-{{ .id }}-headers + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $ | nindent 4 }} +spec: + headers: + stsSeconds: 31536000 + stsIncludeSubdomains: true + stsPreload: true + forceSTSHeader: true + contentTypeNosniff: true + browserXssFilter: true + referrerPolicy: "strict-origin-when-cross-origin" + customFrameOptionsValue: "SAMEORIGIN" +{{- end }} diff --git a/pocketbase/templates/service.yaml b/pocketbase/templates/service.yaml new file mode 100644 index 0000000..22a8ec2 --- /dev/null +++ b/pocketbase/templates/service.yaml @@ -0,0 +1,27 @@ +{{- /* + Generate services for each PocketBase instance +*/ -}} +{{- $root := . }} +{{- range .Values.instances }} +--- +apiVersion: v1 +kind: Service +metadata: + name: pocketbase-{{ .id }} + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $root | nindent 4 }} + annotations: + {{- toYaml $root.Values.ingress.annotations | nindent 4 }} +spec: + type: ClusterIP + selector: + app: pocketbase + instance: {{ .id }} + ports: + - name: http + port: 80 + targetPort: http + protocol: TCP +{{- end }} diff --git a/pocketbase/templates/serviceaccount.yaml b/pocketbase/templates/serviceaccount.yaml new file mode 100644 index 0000000..b26ddd1 --- /dev/null +++ b/pocketbase/templates/serviceaccount.yaml @@ -0,0 +1,23 @@ +{{- /* + Generate ServiceAccount for each PocketBase instance +*/ -}} +{{- if .Values.serviceAccount.create }} +{{- range .Values.instances }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pocketbase-{{ .id }} + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $ | nindent 4 }} + {{- with $.Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if $.Values.serviceAccount.automount }} +automountServiceAccountToken: {{ $.Values.serviceAccount.automount }} + {{- end }} +{{- end }} +{{- end }} diff --git a/pocketbase/templates/tests/test-connection.yaml b/pocketbase/templates/tests/test-connection.yaml new file mode 100644 index 0000000..1759588 --- /dev/null +++ b/pocketbase/templates/tests/test-connection.yaml @@ -0,0 +1,24 @@ +{{- /* + Test connection to PocketBase instances + Run with: helm test +*/ -}} +{{- range .Values.instances }} +--- +apiVersion: v1 +kind: Pod +metadata: + name: "{{ $.Release.Name }}-test-connection-{{ .id }}" + labels: + app: pocketbase + instance: {{ .id }} + {{- include "pocketbase.labels" $ | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['-q', '--spider', 'http://pocketbase-{{ .id }}/api/health'] + restartPolicy: Never +{{- end }} diff --git a/pocketbase/values-production.yaml b/pocketbase/values-production.yaml new file mode 100644 index 0000000..ac150f5 --- /dev/null +++ b/pocketbase/values-production.yaml @@ -0,0 +1,82 @@ +# Production values.yaml example +# Copy this file and modify as needed + +global: + domainSuffix: "pb.xiongxiao.me" + +image: + repository: pocketbase/pocketbase + tag: "0.22.21" + pullPolicy: IfNotPresent + +# List of PocketBase instances +instances: + - id: "app1" + domain: "app1.pb.xiongxiao.me" + replicaCount: 2 + resources: + requests: + cpu: 200m + memory: 512Mi + limits: + cpu: 1000m + memory: 1Gi + - id: "app2" + domain: "app2.pb.xiongxiao.me" + replicaCount: 1 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + - id: "test" + domain: "test.pb.xiongxiao.me" + replicaCount: 1 + +# Resource settings for instances without explicit resources +resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + +# Persistence +persistence: + enabled: true + storageClass: "local-path" + size: 5Gi + accessMode: ReadWriteOnce + +# PostgreSQL +postgresql: + enabled: false + host: "postgresql.postgres.svc.cluster.local" + port: 5432 + database: "pocketbase" + username: "postgres" + passwordSecret: + name: "postgresql-credentials" + key: "password" + +# Traefik Ingress +ingress: + className: "traefik" + enabled: true + annotations: {} + +# Security +podSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + +securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: false + capabilities: + drop: + - ALL diff --git a/pocketbase/values.yaml b/pocketbase/values.yaml new file mode 100644 index 0000000..b9c400e --- /dev/null +++ b/pocketbase/values.yaml @@ -0,0 +1,101 @@ +# Default configuration for PocketBase instances +# Customize this file or override with your own values.yaml + +# Global settings +global: + imageRegistry: "" + imagePullSecrets: [] + storageClass: "" + domainSuffix: "pb.xiongxiao.me" + +# Image configuration +image: + repository: pocketbase/pocketbase + tag: "0.35.1" + pullPolicy: IfNotPresent + +# Service account configuration +serviceAccount: + create: true + name: "" + annotations: {} + +# List of PocketBase instances to deploy +# instances: [] +# Example: +# - id: "app1" +# domain: "app1.pb.xiongxiao.me" +# replicaCount: 1 +# resources: +# requests: +# cpu: 100m +# memory: 256Mi +# limits: +# cpu: 500m +# memory: 512Mi +# - id: "app2" +# domain: "app2.pb.xiongxiao.me" +# replicaCount: 1 +instances: + - id: "app1" + domain: "app1.pb.xiongxiao.me" + replicaCount: 1 + - id: "app2" + domain: "app2.pb.xiongxiao.me" + replicaCount: 1 + +# Default resource settings (applied to all instances unless overridden) +resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + +# Persistence configuration (SQLite data storage) +persistence: + enabled: false + storageClass: "" + size: 1Gi + accessMode: ReadWriteOnce + +# Traefik IngressRoute configuration +ingress: + className: "traefik" + enabled: true + annotations: {} + +# Pod security context +podSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + +# Container security context +securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: false + capabilities: + drop: + - ALL + +# Node selector +nodeSelector: {} + +# Tolerations +tolerations: [] + +# Affinity +affinity: {} + +# Topology spread constraints +topologySpreadConstraints: [] + +# Autoscaling configuration +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 10 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..92f2fa1 --- /dev/null +++ b/readme.md @@ -0,0 +1,110 @@ +# datapod-helm + +Kubernetes Helm Charts 部署配置。 + +## PocketBase Chart + +部署多个 PocketBase 实例,支持 Traefik ingress。 + +### 前置条件 + +- Kubernetes 1.19+ +- Helm 3.2.0+ +- Traefik ingress 控制器 +- StorageClass(用于持久化存储) + +### 快速开始 + +```bash +# 安装 Helm +brew install helm +``` + +### 部署 PocketBase + +1. **配置实例** 编辑 `pocketbase/values.yaml`: + +```yaml +instances: + - id: "app1" + domain: "app1.pb.xiongxiao.me" + replicaCount: 1 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + - id: "app2" + domain: "app2.pb.xiongxiao.me" + replicaCount: 1 +``` + +2. **安装** chart: + +```bash +# 本地 chart 安装 +helm install my-pocketbase ./pocketbase -f pocketbase/values.yaml + +# 使用生产环境配置 +helm install my-pocketbase ./pocketbase -f pocketbase/values-production.yaml +``` +首次安装 +``` +helm install my-pocketbase ./pocketbase -f pocketbase/values.yaml +``` + +3. **获取 admin 密码**: + +```bash +kubectl get secret pocketbase-app1-secrets -o jsonpath='{.data.admin-password}' | base64 -d +``` + +4. **访问** Admin UI: + - 地址: `https://app1.pb.xiongxiao.me/_/` + - 邮箱: 查看 secret + - 密码: 查看 secret + +### 配置参数 + +| 参数 | 说明 | 默认值 | +|------|------|--------| +| `instances` | PocketBase 实例列表 | `[]` | +| `instances[].id` | 实例唯一标识 | - | +| `instances[].domain` | 实例完整域名 | - | +| `instances[].replicaCount` | 副本数量 | `1` | +| `persistence.enabled` | 启用数据持久化 | `true` | +| `persistence.size` | PVC 大小 | `1Gi` | +| `persistence.storageClass` | StorageClass 名称 | - | + +### 升级 + +```bash +helm upgrade my-pocketbase ./pocketbase -f pocketbase/values.yaml +``` + +### 卸载 + +```bash +helm uninstall my-pocketbase +``` + +### 常用命令 + +```bash +# Lint 检查 +helm lint ./pocketbase + +# 模板渲染测试 +helm template test-release ./pocketbase -f ./pocketbase/values-production.yaml + +# 模拟安装(调试模式) +helm install --dry-run --debug my-pocketbase ./pocketbase -f ./pocketbase/values-production.yaml +``` + +### 技术说明 + +- **数据库**: 使用 SQLite 本地存储,数据保存在 `/pb/pb_data` 目录 +- **持久化**: 通过 PVC 实现数据持久化 +- **入口**: 使用 Traefik IngressRoute 配置路由 diff --git a/常用命令.md b/常用命令.md new file mode 100644 index 0000000..226f1d1 --- /dev/null +++ b/常用命令.md @@ -0,0 +1,21 @@ +kubectl get pods -l app.kubernetes.io/instance=my-pocketbase + +# 查看 app1 日志 +kubectl logs -l app=my-pocketbase-app1 -f + +# 查看 Helm 部署状态详情 +helm status my-pocketbase -n default + + +# 查看所有资源 +kubectl get all -n default -l app.kubernetes.io/instance=my-pocketbase + +kubectl get pods -n default | grep pocketbase + +kubectl get pods -n default -o wide | grep -E "pocketbase|app1|app2" + + +kubectl get deployment pocketbase-app1 pocketbase-app2 -n default -o yaml | grep -A 50 "conditions:" + +helm install my-pocketbase ./pocketbase -f pocketbase/values.yaml +helm upgrade my-pocketbase pocketbase/ -n default \ No newline at end of file