Templates

  • This is a template for most self-hosted apps without its own charts
  • with substitute support, non-sensitive but repeative environments are set in configMap:cluster-settings;
  • sensitive environments could be set using label: override.substitution.flux.home.arpa/enabled=true and substituteFrom secrets;
# ks.yaml
---
# yaml-language-server: $schema=https://kubernetes-schemas.noirprime.com/kustomize.toolkit.fluxcd.io/kustomization_v1.json
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: &appname example-app-1
  namespace: &namespace example-ns-1
  labels:
    override.substitution.flux.home.arpa/enabled: "true"
spec:
  targetNamespace: *namespace
  commonMetadata:
    labels:
      app.kubernetes.io/name: *appname
  interval: 30m
  timeout: 5m
  path: "./kubernetes/apps/example-ns-1/example-app-1/app"
  prune: true
  sourceRef:
    kind: GitRepository
    name: gitops-system
    namespace: gitops-system
  wait: false
  dependsOn:
    - name: example-app-2
      namespace: example-ns-2
  postBuild:
    substituteFrom:
      - kind: ConfigMap
        name: cluster-settings
      - kind: Secret
        name: example-app-2

# helmrelease.yaml, since app-template-4.1.1
---
# yaml-language-server: $schema=https://kubernetes-schemas.noirprime.com/helm.toolkit.fluxcd.io/helmrelease_v2.json
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: &name example-app
spec:
  interval: 30m
  chartRef:
    kind: OCIRepository
    name: app-template
    namespace: gitops-system
  maxHistory: 2
  install:
    crds: CreateReplace
    remediation:
      retries: -1
  upgrade:
    cleanupOnFail: true
    crds: CreateReplace
    remediation:
      retries: 3
  uninstall:
    keepHistory: false

  values:
    defaultPodOptions:
      hostUsers: false                        # new way
      # securityContext:                      # old way
      #   runAsUser: 2000
      #   runAsGroup: 2000
      #   runAsNonRoot: true
      #   fsGroup: 2000                       # optional
      #   fsGroupChangePolicy: OnRootMismatch # optional
    controllers:
      example-app:
        annotations:
          reloader.stakater.com/auto: "true"
        serviceAccount: # can be ignored if only one serviceaccount
          identifier: example-app
        initContainers:
          init-db:
            image:
              repository: ghcr.io/home-operations/postgres-init
              tag: "17"
            envFrom:
              - secretRef:
                  name: example-app-initdb
        containers:
          app:
            image:
              repository: path/to/repo
              tag: 1.0.0
            env:
              TZ: "${TIMEZONE}"
              HTTP_PROXY: "${HTTP_PROXY}"
              HTTPS_PROXY: "${HTTPS_PROXY}"
              NO_PROXY: "${NO_PROXY}"
              DB_USERNAME:
                valueFrom:
                  secretKeyRef:
                    name: &pguser example-app-pguser
                    key: user
              DB_PASSWORD:
                valueFrom:
                  secretKeyRef:
                    name: *pguser
                    key: password
              DB_DATABASE_NAME:
                valueFrom:
                  secretKeyRef:
                    name: *pguser
                    key: db
              DB_HOSTNAME:
                valueFrom:
                  secretKeyRef:
                    name: *pguser
                    key: host
              DB_PORT:
                valueFrom:
                  secretKeyRef:
                    name: *pguser
                    key: port
            envFrom: &envFrom
              - configMapRef:
                  name: *name
              - secretRef:
                  name: *name
            ports:
              - name: http
                containerPort: &port 8080
            resources:
              requests:
                cpu: 15m
              limits:
                memory: 512Mi
            securityContext:
              allowPrivilegeEscalation: false
              capabilities: { drop: ["ALL"] }
              readOnlyRootFilesystem: true

    service:
      app:
        controller: *name     # can be ignored if only one controller
        ports:
          http:
            primary: true     # can be ignored if only one port
            port: *port
          metrics:
            port: *metricsPort
        primary: true         # can be ignored if only one service, only one primary
    serviceMonitor:
      app:
        serviceName: *name    # can be ignored if only one service
        endpoints:
          - port: metrics
    route:
      app:
        hostnames:
          - sub.example.com
        parentRefs:
          - name: internal
            namespace: kube-system
            sectionName: https
        rules:                 # can be ignored if only one service
          - backendRefs:
              - identifier: app
                port: *port

    serviceAccount:
      example-app: {}
    persistence:
      app:
        existingClaim: *name
        globalMounts:
          - path: /app/data
            subPath: data     # can be ignored if only one path
      tmpfs:
        type: emptyDir
        globalMounts:
          - path: /tmp
            subPath: tmp      # can be ignored if only one path
      media:
        type: nfs
        server: nas.homelab.internal
        path: /mnt/Arcanum/shared/media
        advancedMounts:
          example-app:
            app:
              - path: /data
                subPath: data