apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }}-{{ .Chart.Name }}-deployment labels: app: {{ .Release.Name }}-{{ .Chart.Name }} spec: replicas: {{ include "patchmon.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.patchmon.server.replicas) }} selector: matchLabels: app: {{ .Release.Name }}-{{ .Chart.Name }} template: metadata: name: {{ .Release.Name }}-{{ .Chart.Name }} labels: app: {{ .Release.Name }}-{{ .Chart.Name }} spec: automountServiceAccountToken: false # Pin a stable pod hostname: the server identifies itself in the agent # presence registry (Redis) by hostname, and a Deployment pod's default # hostname changes on every rollout, which would leave stale presence # records behind (upstream pins "patchmon-server" in its compose file # for the same reason). hostname: {{ .Release.Name }}-{{ .Chart.Name }}-server securityContext: {{- toYaml .Values.patchmon.server.securityContext.pod | nindent 8 }} containers: - name: {{ .Release.Name }}-{{ .Chart.Name }}-server image: "ghcr.io/patchmon/patchmon-server:{{ .Chart.AppVersion }}" imagePullPolicy: IfNotPresent securityContext: {{- toYaml .Values.patchmon.server.securityContext.container | nindent 12 }} ports: - containerPort: 3000 protocol: TCP name: http env: - name: DATABASE_URL valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-postgres-secret key: database-url - name: REDIS_HOST valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-redis-secret key: host - name: REDIS_PORT valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-redis-secret key: port - name: REDIS_USER valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-redis-secret key: username - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-redis-secret key: password - name: REDIS_DB valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-redis-secret key: db - name: JWT_SECRET valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-patchmon-secret key: jwt-secret - name: AI_ENCRYPTION_KEY valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-patchmon-secret key: encryption-key - name: SESSION_SECRET valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-patchmon-secret key: session-secret - name: OIDC_ENABLED value: "true" - name: OIDC_ISSUER_URL valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret key: issuer-url - name: OIDC_CLIENT_ID valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret key: client-id - name: OIDC_CLIENT_SECRET valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret key: client-secret - name: OIDC_REDIRECT_URI valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret key: redirect-uri - name: OIDC_SCOPES valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret key: requested-scopes - name: OIDC_AUTO_CREATE_USERS value: "true" # 2.x role vocabulary: superadmin, admin, host_manager, readonly, # user. "viewer" (the 1.x default of this chart) no longer exists; # readonly is its least-privilege equivalent. - name: OIDC_DEFAULT_ROLE value: "readonly" - name: OIDC_DISABLE_LOCAL_AUTH value: "true" - name: OIDC_BUTTON_TEXT valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret key: button-text - name: OIDC_SYNC_ROLES value: "true" - name: OIDC_USER_GROUP valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret key: user-group-name - name: OIDC_ADMIN_GROUP valueFrom: secretKeyRef: name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret key: admin-group-name - name: CORS_ORIGIN value: "https://{{ required "A Domain/Host must be provided" .Values.ingress.domain }}" # Renamed upstream in 2.x (was TRUST_PROXIES= in 1.x): the # server sits behind the ingress-nginx reverse proxy. - name: TRUST_PROXY value: "true" {{- if .Values.patchmon.guacd.enabled }} - name: GUACD_ADDRESS value: "127.0.0.1:4822" {{- end }} # The server exposes GET /health returning {"status": "ok"}. The # 2.x server rejects requests whose Host header is neither loopback # nor a CORS_ORIGIN host with 403 — kubelet probes target the pod # IP, so they must send the public hostname as Host header. livenessProbe: httpGet: path: /health port: 3000 httpHeaders: - name: Host value: {{ .Values.ingress.domain }} periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /health port: 3000 httpHeaders: - name: Host value: {{ .Values.ingress.domain }} periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 # The startup probe gates liveness/readiness. The server waits for # the database and runs migrations on startup; upstream warns that # the first 2.x boot rebuilds database indexes, which can take # minutes on slow storage: budget 10s * 60 = 600s. startupProbe: httpGet: path: /health port: 3000 httpHeaders: - name: Host value: {{ .Values.ingress.domain }} periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 60 resources: {{- include "patchmon.resources" .Values.patchmon.server.resources | nindent 12 }} volumeMounts: # The image is stateless, but the Go server needs a writable /tmp # for scratch files with a read-only root filesystem. - name: tmp mountPath: /tmp {{- if .Values.patchmon.guacd.enabled }} - name: {{ .Release.Name }}-{{ .Chart.Name }}-guacd image: {{ .Values.patchmon.guacd.image }} imagePullPolicy: IfNotPresent securityContext: {{- toYaml .Values.patchmon.guacd.securityContext.container | nindent 12 }} ports: - containerPort: 4822 protocol: TCP name: guacd livenessProbe: tcpSocket: port: 4822 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: tcpSocket: port: 4822 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 startupProbe: tcpSocket: port: 4822 periodSeconds: 5 timeoutSeconds: 5 failureThreshold: 30 resources: {{- include "patchmon.resources" .Values.patchmon.guacd.resources | nindent 12 }} volumeMounts: - name: guacd-tmp mountPath: /tmp {{- end }} restartPolicy: Always volumes: - name: tmp emptyDir: {} {{- if .Values.patchmon.guacd.enabled }} - name: guacd-tmp emptyDir: {} {{- end }}