apiVersion: v1 kind: Namespace metadata: name: cube-notes --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: notes-data namespace: cube-notes spec: accessModes: - ReadWriteOnce resources: requests: storage: 30Gi --- apiVersion: apps/v1 kind: Deployment metadata: name: notes namespace: cube-notes labels: app: notes spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: notes template: metadata: labels: app: notes spec: imagePullSecrets: - name: registry-creds initContainers: # lark-cli auth 分两处: # ~/.lark-cli/config.json — app id / open id 索引 # ~/.local/share/lark-cli/*.enc + master.key — 加密的 OAuth user token # secret volume 只读但 lark-cli 跑时要刷 token 写回。先 cp 到 PVC 让它可写。 # 已存在不覆盖:保留运行时 refresh 过的 token,免每次重启回滚到老 token。 - name: lark-config-init image: busybox:1.36 command: - sh - -c - | mkdir -p /data/lark-cli /data/lark-share if [ ! -f /data/lark-cli/config.json ]; then cp /secrets/lark-cli/config.json /data/lark-cli/config.json echo "seeded ~/.lark-cli/config.json" fi for f in master.key appsecret_cli_a3f21503fbb8900e.enc cli_a3f21503fbb8900e_ou_1d4fb299843b6a341c1942b056181ca8.enc; do if [ ! -f "/data/lark-share/$f" ]; then cp "/secrets/lark-cli/$f" "/data/lark-share/$f" echo "seeded ~/.local/share/lark-cli/$f" fi done chmod -R 600 /data/lark-cli /data/lark-share 2>/dev/null || true volumeMounts: - name: lark-cli-secret mountPath: /secrets/lark-cli readOnly: true - name: data mountPath: /data containers: - name: notes image: registry.famzheng.me/mochi/notes:latest imagePullPolicy: IfNotPresent ports: - containerPort: 8080 name: http env: - name: DB_PATH value: /data/app.db - name: BLOBS_DIR value: /data/blobs - name: LLM_GATEWAY value: http://3.135.65.204:8848/v1 - name: LLM_MODEL value: gemma-4-31b-it - name: PASSPHRASE valueFrom: secretKeyRef: name: notes-creds key: passphrase - name: LLM_TOKEN valueFrom: secretKeyRef: name: notes-creds key: llm_token - name: FEISHU_URL value: http://localhost:8002 readinessProbe: httpGet: { path: /healthz, port: http } initialDelaySeconds: 1 periodSeconds: 5 livenessProbe: httpGet: { path: /healthz, port: http } initialDelaySeconds: 5 periodSeconds: 15 resources: requests: { cpu: 10m, memory: 32Mi } limits: { cpu: 1000m, memory: 512Mi } volumeMounts: - name: data mountPath: /data - name: feishu image: registry.famzheng.me/mochi/notes-feishu:latest imagePullPolicy: IfNotPresent ports: - containerPort: 8002 name: feishu env: - name: ASR_URL value: http://18.159.112.195:8848/v1/audio/transcriptions - name: ASR_TOKEN valueFrom: secretKeyRef: name: notes-creds key: asr_token - name: LLM_GATEWAY value: http://3.135.65.204:8848/v1 - name: LLM_MODEL value: gemma-4-31b-it - name: LLM_TOKEN valueFrom: secretKeyRef: name: notes-creds key: llm_token readinessProbe: httpGet: { path: /healthz, port: feishu } initialDelaySeconds: 3 periodSeconds: 10 livenessProbe: httpGet: { path: /healthz, port: feishu } initialDelaySeconds: 30 periodSeconds: 30 resources: requests: { cpu: 20m, memory: 64Mi } limits: { cpu: 500m, memory: 384Mi } volumeMounts: - name: data mountPath: /data - name: data mountPath: /root/.lark-cli subPath: lark-cli - name: data mountPath: /root/.local/share/lark-cli subPath: lark-share volumes: - name: data persistentVolumeClaim: claimName: notes-data - name: lark-cli-secret secret: secretName: lark-cli-creds # 默认挂全部 keys(config.json + master.key + 两个 .enc) --- apiVersion: v1 kind: Service metadata: name: notes namespace: cube-notes spec: selector: app: notes ports: - name: http port: 80 targetPort: 8080 --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: bodylimit namespace: cube-notes spec: buffering: maxRequestBodyBytes: 629145600 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: notes namespace: cube-notes annotations: traefik.ingress.kubernetes.io/router.middlewares: cube-notes-bodylimit@kubernetescrd spec: ingressClassName: traefik rules: - host: notes.famzheng.me http: paths: - path: / pathType: Prefix backend: service: name: notes port: number: 80