apiVersion: apps/v1 kind: StatefulSet metadata: name: {{ taskserv.name }} namespace: {{ taskserv.namespace }} labels: app.kubernetes.io/name: {{ taskserv.name }} app.kubernetes.io/managed-by: provisioning spec: serviceName: {{ taskserv.name }} replicas: 1 selector: matchLabels: app.kubernetes.io/name: {{ taskserv.name }} template: metadata: labels: app.kubernetes.io/name: {{ taskserv.name }} app.kubernetes.io/managed-by: provisioning spec: {% if taskserv.registry_secret %} imagePullSecrets: - name: {{ taskserv.registry_secret }} {% endif %} {% if taskserv.placement is defined and taskserv.placement.node_class %} affinity: nodeAffinity: {% if taskserv.placement.mode == "require" %} requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-class.{{ taskserv.placement.node_class.0 }} operator: In values: ["true"] {% else %} preferredDuringSchedulingIgnoredDuringExecution: {% for c in taskserv.placement.node_class %} - weight: {{ 100 - loop.index0 * 10 }} preference: matchExpressions: - key: node-class.{{ c }} operator: In values: ["true"] {% endfor %} {% endif %} {% endif %} securityContext: fsGroup: 1000 terminationGracePeriodSeconds: 60 volumes: - name: data persistentVolumeClaim: claimName: {{ taskserv.name }}-data - name: extra-ini configMap: name: {{ taskserv.name }}-app-ini items: - key: extra.ini path: extra.ini initContainers: - name: merge-extra-ini image: {{ taskserv.image }} imagePullPolicy: IfNotPresent command: - /bin/sh - -c - | set -eu CONF_DIR="{{ taskserv.data_dir }}/conf" APP_INI="$CONF_DIR/app.ini" MARKER_BEGIN="; >>> managed-by: provisioning extra.ini >>>" MARKER_END="; <<< managed-by: provisioning extra.ini <<<" mkdir -p "$CONF_DIR" touch "$APP_INI" # Idempotent re-apply: strip prior managed block, then append current. if grep -qF "$MARKER_BEGIN" "$APP_INI" 2>/dev/null; then sed -i "/$MARKER_BEGIN/,/$MARKER_END/d" "$APP_INI" fi { printf "\n%s\n" "$MARKER_BEGIN" cat /etc/forgejo/extra.ini printf "\n%s\n" "$MARKER_END" } >> "$APP_INI" volumeMounts: - name: data mountPath: {{ taskserv.data_dir }} - name: extra-ini mountPath: /etc/forgejo/extra.ini subPath: extra.ini readOnly: true containers: - name: forgejo image: {{ taskserv.image }} imagePullPolicy: IfNotPresent ports: - containerPort: {{ taskserv.http_port }} name: http protocol: TCP - containerPort: {{ taskserv.ssh_port }} name: ssh protocol: TCP envFrom: - secretRef: name: {{ taskserv.name }}-credentials env: - name: USER_UID value: "1000" - name: USER_GID value: "1000" - name: FORGEJO_WORK_DIR value: {{ taskserv.data_dir }} - name: GITEA_CUSTOM value: {{ taskserv.data_dir }} - name: FORGEJO__server__PROTOCOL value: http - name: FORGEJO__server__HTTP_PORT value: "{{ taskserv.http_port }}" - name: FORGEJO__server__DOMAIN value: "{{ taskserv.domain }}" - name: FORGEJO__server__ROOT_URL value: "https://{{ taskserv.domain }}/" - name: FORGEJO__server__SSH_DOMAIN value: "{% if taskserv.ssh_domain %}{{ taskserv.ssh_domain }}{% else %}{{ taskserv.domain }}{% endif %}" - name: FORGEJO__server__SSH_PORT value: "{% if taskserv.ssh_lb_ip %}{{ taskserv.ssh_port }}{% else %}{{ taskserv.ssh_nodeport }}{% endif %}" - name: FORGEJO__server__SSH_LISTEN_PORT value: "{{ taskserv.ssh_port }}" - name: FORGEJO__server__START_SSH_SERVER value: "true" - name: FORGEJO__server__APP_DATA_PATH value: "{{ taskserv.data_dir }}/data" - name: FORGEJO__repository__ROOT value: "{{ taskserv.repos_dir }}" - name: FORGEJO__database__DB_TYPE value: postgres - name: FORGEJO__database__HOST value: "{{ taskserv.db_host }}:{{ taskserv.db_port }}" - name: FORGEJO__database__NAME value: "{{ taskserv.db_name }}" - name: FORGEJO__database__USER value: "{{ taskserv.db_user }}" - name: FORGEJO__database__PASSWD valueFrom: secretKeyRef: name: {{ taskserv.name }}-credentials key: POSTGRES_PASSWORD {% if taskserv.db_schema %} - name: FORGEJO__database__SCHEMA value: "{{ taskserv.db_schema }}" {% endif %} - name: FORGEJO__database__SSL_MODE value: disable - name: FORGEJO__security__INSTALL_LOCK value: "true" - name: FORGEJO__security__SECRET_KEY valueFrom: secretKeyRef: name: {{ taskserv.name }}-credentials key: FORGEJO_SECRET_KEY - name: FORGEJO__security__INTERNAL_TOKEN valueFrom: secretKeyRef: name: {{ taskserv.name }}-credentials key: FORGEJO_INTERNAL_TOKEN - name: FORGEJO__oauth2__JWT_SECRET valueFrom: secretKeyRef: name: {{ taskserv.name }}-credentials key: FORGEJO_JWT_SECRET - name: FORGEJO__server__LFS_JWT_SECRET valueFrom: secretKeyRef: name: {{ taskserv.name }}-credentials key: FORGEJO_LFS_JWT_SECRET - name: FORGEJO__mailer__USER valueFrom: secretKeyRef: name: {{ taskserv.name }}-credentials key: SMTP_USER optional: true - name: FORGEJO__mailer__PASSWD valueFrom: secretKeyRef: name: {{ taskserv.name }}-credentials key: SMTP_PASS optional: true - name: FORGEJO__service__DISABLE_REGISTRATION value: "true" - name: FORGEJO__log__MODE value: console - name: FORGEJO__log__LEVEL value: Info volumeMounts: - name: data mountPath: {{ taskserv.data_dir }} - name: extra-ini mountPath: /etc/forgejo/extra.ini subPath: extra.ini readOnly: true {% if taskserv.probes is defined and taskserv.probes.readiness is defined %} readinessProbe: {% if taskserv.probes.readiness.type == "tcp" %} tcpSocket: port: {{ taskserv.probes.readiness.port | default(value=taskserv.http_port) }} {% else %} httpGet: path: {{ taskserv.probes.readiness.path }} port: {{ taskserv.probes.readiness.port | default(value=taskserv.http_port) }} {% endif %} initialDelaySeconds: {{ taskserv.probes.readiness.initial_delay }} periodSeconds: {{ taskserv.probes.readiness.period }} failureThreshold: {{ taskserv.probes.readiness.failure_threshold }} {% else %} readinessProbe: httpGet: path: /api/healthz port: http initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 5 {% endif %} {% if taskserv.probes is defined and taskserv.probes.liveness is defined %} livenessProbe: {% if taskserv.probes.liveness.type == "tcp" %} tcpSocket: port: {{ taskserv.probes.liveness.port | default(value=taskserv.http_port) }} {% else %} httpGet: path: {{ taskserv.probes.liveness.path }} port: {{ taskserv.probes.liveness.port | default(value=taskserv.http_port) }} {% endif %} initialDelaySeconds: {{ taskserv.probes.liveness.initial_delay }} periodSeconds: {{ taskserv.probes.liveness.period }} failureThreshold: {{ taskserv.probes.liveness.failure_threshold }} {% else %} livenessProbe: tcpSocket: port: http initialDelaySeconds: 60 periodSeconds: 20 timeoutSeconds: 5 {% endif %} {% if taskserv.resources_effective is defined %} resources: requests: cpu: "{{ taskserv.resources_effective.cpu.request }}" memory: "{{ taskserv.resources_effective.memory.request }}" limits: cpu: "{{ taskserv.resources_effective.cpu.limit }}" memory: "{{ taskserv.resources_effective.memory.limit }}" {% else %} resources: {} {% endif %}