├── .github ├── CODEOWNERS ├── linters │ ├── server-ct.yaml │ ├── worker-ct.yaml │ └── prometheus-prefect-exporter-ct.yaml ├── dependabot.yaml ├── workflows │ ├── helm-unittest.yaml │ ├── update-mise-tools.yaml │ ├── validate-updatecli-config.yaml │ ├── updatecli-minor-versions.yaml │ ├── updatecli-major-versions.yaml │ ├── server-lint-and-test.yaml │ ├── prometheus-prefect-exporter-lint-and-test.yaml │ ├── notify-on-failure.yaml │ ├── worker-lint-and-test.yaml │ ├── prometheus-exporter-helm-release.yaml │ └── helm-release.yaml ├── pull_request_template.md ├── release.yaml └── updatecli │ ├── manifest-major.yaml │ └── manifest-minor.yaml ├── charts ├── prefect-worker │ ├── templates │ │ ├── NOTES.txt │ │ ├── configmap.yaml │ │ ├── pdb.yaml │ │ ├── serviceaccount.yaml │ │ ├── rolebinding.yaml │ │ ├── role.yaml │ │ ├── hpa.yaml │ │ └── _helpers.tpl │ ├── tests │ │ └── required_values.yaml │ ├── .helmignore │ ├── Chart.yaml │ └── UPGRADING.md ├── prometheus-prefect-exporter │ ├── templates │ │ ├── _helpers.tpl │ │ ├── serviceaccount.yaml │ │ ├── pdb.yaml │ │ ├── prometheusrule.yaml │ │ ├── service.yaml │ │ ├── hpa.yaml │ │ ├── servicemonitor.yaml │ │ ├── NOTES.txt │ │ └── deployment.yaml │ ├── tests │ │ ├── test-connection.yaml │ │ └── exporter_test.yaml │ ├── Chart.yaml │ ├── README.md.gotmpl │ ├── README.md │ ├── values.yaml │ └── values.schema.json └── prefect-server │ ├── tests │ ├── test-connection.yaml │ ├── service_test.yaml │ ├── gateway_ingress_exclusivity_test.yaml │ ├── database_test.yaml │ └── pre_upgrade_hook_test.yaml │ ├── .helmignore │ ├── templates │ ├── pvc.yaml │ ├── secret.yaml │ ├── serviceaccount.yaml │ ├── background-services │ │ ├── serviceaccount.yaml │ │ └── deployment.yaml │ ├── hpa.yaml │ ├── httproute-tls-redirect.yaml │ ├── NOTES.txt │ ├── httproute.yaml │ ├── service.yaml │ ├── gateway.yaml │ ├── _validation.tpl │ ├── ingress.yaml │ ├── pre-upgrade-hook.yaml │ ├── deployment.yaml │ └── _helpers.tpl │ ├── Chart.yaml │ ├── examples │ └── gateway-values.yaml │ ├── UPGRADING.md │ └── README.md.gotmpl ├── .yamllint ├── artifacthub-repo.yml ├── scripts ├── helm_unittest.sh └── helm_charttest.sh ├── .pre-commit-config.yaml ├── .gitignore ├── .mise.toml ├── README.md └── LICENSE /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @PrefectHQ/platform 2 | -------------------------------------------------------------------------------- /charts/prefect-worker/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Check Prefect worker connections in the prefect UI 2 | -------------------------------------------------------------------------------- /charts/prefect-worker/tests/required_values.yaml: -------------------------------------------------------------------------------- 1 | worker: 2 | config: 3 | workPool: my-work-pool 4 | cloudApiConfig: 5 | accountId: my-account-id 6 | workspaceId: my-workspace-id -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | ignore: | 5 | charts/ 6 | 7 | rules: 8 | comments: 9 | min-spaces-from-content: 1 10 | comments-indentation: disable 11 | document-start: disable 12 | line-length: disable 13 | -------------------------------------------------------------------------------- /artifacthub-repo.yml: -------------------------------------------------------------------------------- 1 | repositoryID: 9eabedea-e9f6-4f35-ab50-4788aa4d1e67 2 | owners: 3 | - name: jamiezieziula 4 | email: jamie@prefect.io 5 | - name: jimid27 6 | email: jimi@prefect.io 7 | - name: parkedwards 8 | email: edward@prefect.io 9 | -------------------------------------------------------------------------------- /.github/linters/server-ct.yaml: -------------------------------------------------------------------------------- 1 | # See https://github.com/helm/chart-testing#configuration 2 | charts: 3 | - charts/prefect-server 4 | chart-repos: 5 | - bitnami=https://charts.bitnami.com/bitnami 6 | helm-extra-args: --timeout 90s 7 | release-label: prefect 8 | -------------------------------------------------------------------------------- /.github/linters/worker-ct.yaml: -------------------------------------------------------------------------------- 1 | # See https://github.com/helm/chart-testing#configuration 2 | charts: 3 | - charts/prefect-worker 4 | chart-repos: 5 | - bitnami=https://charts.bitnami.com/bitnami 6 | helm-extra-args: --timeout 60s 7 | namespace: prefect 8 | release-label: prefect 9 | -------------------------------------------------------------------------------- /.github/linters/prometheus-prefect-exporter-ct.yaml: -------------------------------------------------------------------------------- 1 | # See https://github.com/helm/chart-testing#configuration 2 | charts: 3 | - charts/prometheus-prefect-exporter 4 | chart-repos: 5 | - bitnami=https://charts.bitnami.com/bitnami 6 | helm-extra-args: --timeout 600s 7 | release-label: prefect 8 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: github-actions 5 | directory: / 6 | commit-message: 7 | prefix: chore 8 | groups: 9 | all: 10 | patterns: 11 | - "*" 12 | labels: 13 | - automated-dependency-updates 14 | schedule: 15 | interval: monthly 16 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Create the name of the service account to use 3 | */}} 4 | {{- define "prometheus-prefect-exporter.serviceAccountName" -}} 5 | {{- if .Values.serviceAccount.create }} 6 | {{- default (include "common.names.fullname" .) .Values.serviceAccount.name }} 7 | {{- else }} 8 | {{- default "default" .Values.serviceAccount.name }} 9 | {{- end }} 10 | {{- end }} 11 | -------------------------------------------------------------------------------- /charts/prefect-worker/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/prefect-server/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "server.fullname" . }}-test-connection" 5 | labels: 6 | {{- include "server.labels" . | nindent 4 }} 7 | annotations: 8 | "helm.sh/hook": test 9 | spec: 10 | containers: 11 | - name: wget 12 | image: busybox 13 | command: ['wget'] 14 | args: ['{{ include "server.fullname" . }}:{{ .Values.api.service.port }}'] 15 | restartPolicy: Never 16 | -------------------------------------------------------------------------------- /charts/prefect-server/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | # helm-unittest 25 | tests 26 | -------------------------------------------------------------------------------- /.github/workflows/helm-unittest.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Run Helm Unit Tests 3 | 4 | "on": 5 | pull_request: {} 6 | 7 | permissions: 8 | # required to read from the repo 9 | contents: read 10 | 11 | jobs: 12 | unittest: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v6 17 | 18 | - name: Run helm unittest 19 | uses: d3adb5/helm-unittest-action@v2 20 | with: 21 | helm-version: v3.17.1 22 | unittest-version: 1.0.0 23 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "prometheus-prefect-exporter.serviceAccountName" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: 8 | {{- include "common.labels.standard" . | nindent 4 }} 9 | {{- with .Values.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/templates/pdb.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.podDisruptionBudget -}} 2 | apiVersion: policy/v1 3 | kind: PodDisruptionBudget 4 | metadata: 5 | name: {{ template "common.names.fullname" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: 8 | {{- include "common.labels.standard" . | nindent 4 }} 9 | spec: 10 | selector: 11 | matchLabels: 12 | {{- include "common.labels.matchLabels" . | nindent 6 }} 13 | {{ toYaml .Values.podDisruptionBudget | indent 2 }} 14 | {{- end }} 15 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.sqlite.enabled .Values.sqlite.persistence.enabled }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: {{ template "common.names.fullname" . }}-sqlite 6 | namespace: {{.Release.Namespace}} 7 | spec: 8 | {{- with .Values.sqlite.persistence.storageClassName }} 9 | storageClassName: {{.}} 10 | {{- end }} 11 | accessModes: 12 | - ReadWriteOnce 13 | resources: 14 | requests: 15 | storage: {{.Values.sqlite.persistence.size}} 16 | {{- end }} 17 | -------------------------------------------------------------------------------- /.github/workflows/update-mise-tools.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Update mise tool versions 3 | 4 | "on": 5 | schedule: 6 | - cron: 0 15 1 * * # First of the month @ 3pm UTC 7 | workflow_dispatch: {} 8 | 9 | permissions: 10 | # required to write to the repo 11 | contents: write 12 | # required to open a pr with changes 13 | pull-requests: write 14 | 15 | jobs: 16 | update_mise_tools: 17 | if: github.repository == 'prefecthq/prefect-helm' 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: upgrade mise tools 21 | uses: prefecthq/actions-mise-upgrade@main 22 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.testConnection }} 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: "{{ include "common.names.fullname" . }}-test-connection" 6 | labels: 7 | {{- include "common.labels.standard" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | containers: 12 | - name: wget 13 | image: busybox 14 | command: ['wget'] 15 | args: ['{{ include "common.names.fullname" . }}:{{ .Values.service.targetPort | default .Values.service.port }}'] 16 | restartPolicy: Never 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/prefect-server/tests/service_test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | suite: Service API Configuration 3 | release: 4 | name: service-test 5 | namespace: prefect 6 | 7 | tests: 8 | - it: Service default port name is server-svc-port 9 | asserts: 10 | - template: service.yaml 11 | equal: 12 | path: spec.ports[0].name 13 | value: "server-svc-port" 14 | 15 | - it: Service port name is the customized one 16 | set: 17 | service: 18 | portName: my-custom-port-name 19 | asserts: 20 | - template: service.yaml 21 | equal: 22 | path: spec.ports[0].name 23 | value: "my-custom-port-name" 24 | -------------------------------------------------------------------------------- /scripts/helm_unittest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script uses https://github.com/helm-unittest/helm-unittest 4 | # to run unit tests for our Helm Chart templates. 5 | # 6 | # It uses the Docker image to make it easier to run on local machines without 7 | # having to manage the binary and its correct version. Note that if it ever 8 | # appears in https://mise.jdx.dev/registry.html, we can add an entry in .mise.toml. 9 | # 10 | # Dependencies: 11 | # - docker 12 | # 13 | # Usage: 14 | # ./scripts/helm_unittest.sh 15 | 16 | version=${VERSION:-3.18.4-1.0.0} 17 | 18 | docker run \ 19 | -it --rm \ 20 | -v $(pwd):/apps \ 21 | helmunittest/helm-unittest:${version} charts/* 22 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/templates/prometheusrule.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.prometheusRule.enabled }} 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: PrometheusRule 4 | metadata: 5 | name: {{ template "common.names.fullname" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: 8 | {{- include "common.labels.standard" . | nindent 4 }} 9 | {{- with .Values.prometheusRule.additionalLabels -}} 10 | {{- toYaml . | nindent 4 -}} 11 | {{- end }} 12 | spec: 13 | {{- with .Values.prometheusRule.rules }} 14 | groups: 15 | - name: {{ template "common.names.fullname" $ }} 16 | rules: {{ toYaml . | nindent 8 }} 17 | {{- end }} 18 | {{- end }} 19 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Summary 2 | 3 | 4 | 5 | ### Requirements 6 | 7 | - [ ] [Contributing guide](https://github.com/PrefectHQ/prefect-helm/?tab=readme-ov-file#contributing) has been read 8 | - [ ] Title follows the [conventional commits](https://www.conventionalcommits.org) format 9 | - [ ] Body includes `Closes `, if available 10 | - [ ] Added/modified configuration includes a descriptive comment for documentation generation 11 | - [ ] Unit tests are added/updated 12 | - [ ] Deprecation/removal checks are added in `templates/NOTES.txt` 13 | - [ ] Relevant labels are added 14 | - [ ] `Draft` status is used until ready for review 15 | -------------------------------------------------------------------------------- /.github/release.yaml: -------------------------------------------------------------------------------- 1 | # .github/release.yml 2 | 3 | changelog: 4 | exclude: 5 | labels: 6 | - maintenance 7 | categories: 8 | - title: Breaking Changes 9 | labels: 10 | - breaking 11 | - title: Dependency Updates 12 | labels: 13 | - dependencies 14 | - title: Documentation 15 | labels: 16 | - docs 17 | - title: Enhancements 18 | labels: 19 | - enhancement 20 | - title: Exciting New Features 🎉 21 | labels: 22 | - feature 23 | - title: Prometheus Exporter 24 | labels: 25 | - exporter 26 | - title: Fixes 27 | labels: 28 | - fix 29 | - title: Uncategorized 30 | labels: 31 | - "*" 32 | -------------------------------------------------------------------------------- /.github/workflows/validate-updatecli-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Validate Updatecli Config 3 | 4 | "on": 5 | pull_request: 6 | branches: 7 | - main 8 | paths: 9 | - .github/updatecli/** 10 | 11 | permissions: 12 | # required to read from the repo 13 | contents: read 14 | 15 | jobs: 16 | validate_updatecli_configs: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: checkout 20 | uses: actions/checkout@v6 21 | 22 | - name: install updatecli 23 | uses: updatecli/updatecli-action@v2 24 | 25 | - name: validate manifest-minor 26 | run: updatecli diff --config .github/updatecli/manifest-minor.yaml 27 | 28 | - name: validate manifest-major 29 | run: updatecli diff --config .github/updatecli/manifest-major.yaml 30 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "common.names.fullname" . }} 5 | namespace: {{ include "common.names.namespace" . | quote }} 6 | labels: 7 | {{- include "common.labels.standard" . | nindent 4 }} 8 | {{- if .Values.service.annotations }} 9 | annotations: 10 | {{- include "common.tplvalues.render" ( dict "value" .Values.service.annotations "context" $) | nindent 4 }} 11 | {{- end }} 12 | spec: 13 | type: {{ .Values.service.type }} 14 | ports: 15 | - port: {{ .Values.service.port }} 16 | targetPort: {{ .Values.service.targetPort | default .Values.service.port }} 17 | protocol: TCP 18 | name: http 19 | selector: 20 | {{- include "common.labels.matchLabels" . | nindent 4 }} 21 | -------------------------------------------------------------------------------- /.github/workflows/updatecli-minor-versions.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Updatecli Minor Dependency Updates 3 | 4 | "on": 5 | schedule: 6 | - cron: 0 15 * * 1 # Monday @ 3pm UTC 7 | workflow_dispatch: {} 8 | 9 | permissions: 10 | # required to write to the repo 11 | contents: write 12 | # required to open a pr with updatecli changes 13 | pull-requests: write 14 | 15 | jobs: 16 | updatecli_minor: 17 | if: github.repository == 'prefecthq/prefect-helm' 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: checkout 21 | uses: actions/checkout@v6 22 | 23 | - name: updatecli-minor-apply 24 | uses: prefecthq/actions-updatecli-apply@main 25 | with: 26 | manifest-path: .github/updatecli/manifest-minor.yaml 27 | run-helm-docs: true 28 | run-type: minor 29 | -------------------------------------------------------------------------------- /.github/workflows/updatecli-major-versions.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Updatecli Major Dependency Updates 3 | 4 | "on": 5 | schedule: 6 | - cron: 0 15 1 * * # First of the month @ 3pm UTC 7 | workflow_dispatch: {} 8 | 9 | permissions: 10 | # required to write to the repo 11 | contents: write 12 | # required to open a pr with updatecli changes 13 | pull-requests: write 14 | 15 | jobs: 16 | updatecli_major: 17 | if: github.repository == 'prefecthq/prefect-helm' 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: checkout 21 | uses: actions/checkout@v6 22 | 23 | - name: updatecli-major-apply 24 | uses: prefecthq/actions-updatecli-apply@main 25 | with: 26 | manifest-path: .github/updatecli/manifest-major.yaml 27 | run-helm-docs: true 28 | run-type: major 29 | -------------------------------------------------------------------------------- /charts/prefect-worker/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | appVersion: 3-latest 3 | dependencies: 4 | - name: common 5 | repository: https://charts.bitnami.com/bitnami 6 | tags: 7 | - bitnami-common 8 | version: 2.31.4 9 | description: Prefect Worker application bundle 10 | engine: gotpl 11 | home: https://github.com/PrefectHQ 12 | maintainers: 13 | - name: jamiezieziula 14 | email: jamie@prefect.io 15 | - name: jimid27 16 | email: jimi@prefect.io 17 | - name: parkedwards 18 | email: edward@prefect.io 19 | - name: mitchnielsen 20 | email: mitchell@prefect.io 21 | name: prefect-worker 22 | sources: 23 | - https://github.com/PrefectHQ/prefect-helm 24 | type: application 25 | # This version is never actually shipped. github actions will package add the appropriate version at build-time 26 | version: 0.0.0 27 | -------------------------------------------------------------------------------- /charts/prefect-worker/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.worker.config.baseJobTemplate.configuration }} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: {{ include "worker.baseJobTemplateName" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: worker 9 | {{- if .Values.commonLabels }} 10 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 11 | {{- end }} 12 | {{- if .Values.commonAnnotations }} 13 | annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 14 | {{- end }} 15 | data: 16 | baseJobTemplate.json: {{ .Values.worker.config.baseJobTemplate.configuration | toJson }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /scripts/helm_charttest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | # This script uses https://github.com/helm/chart-testing 6 | # to run tests for our Helm Charts. 7 | # 8 | # It uses the Docker image to make it easier to run on local machines without 9 | # having to manage the binary and its correct version. 10 | # 11 | # Dependencies: 12 | # - docker 13 | # 14 | # Usage: 15 | # ./scripts/helm_charttest.sh 16 | 17 | version=${VERSION:-v3.14.0} 18 | 19 | # Lint each chart. 20 | # Note: we'll skip validating maintainers, which doesn't play nicely 21 | # in the Docker container. This will still run in CI. 22 | for chart in worker server; do 23 | docker run \ 24 | -it --rm \ 25 | -v "$(pwd)":/code \ 26 | -w /code \ 27 | "quay.io/helmpack/chart-testing:${version}" \ 28 | /bin/bash -c "ct lint --config .github/linters/${chart}-ct.yaml --validate-maintainers=false" 29 | done 30 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | appVersion: "latest" 3 | description: A Helm chart to deploy Prometheus Prefect Exporter 4 | home: https://github.com/PrefectHQ 5 | dependencies: 6 | - name: common 7 | repository: https://charts.bitnami.com/bitnami 8 | tags: 9 | - bitnami-common 10 | version: 2.31.4 11 | keywords: 12 | - prometheus-prefect-exporter 13 | maintainers: 14 | - name: jamiezieziula 15 | email: jamie@prefect.io 16 | - name: jimid27 17 | email: jimi@prefect.io 18 | - name: parkedwards 19 | email: edward@prefect.io 20 | - name: mitchnielsen 21 | email: mitchell@prefect.io 22 | name: prometheus-prefect-exporter 23 | sources: 24 | - https://github.com/PrefectHQ/prefect-helm 25 | type: application 26 | # This version is never actually shipped. github actions will package add the appropriate version at build-time 27 | version: 0.0.0 28 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.secret.create (not .Values.sqlite.enabled) }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ include "server.postgres-string-secret-name" . | quote }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: server 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.commonLabels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if .Values.commonAnnotations }} 14 | annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 15 | {{- end }} 16 | type: Opaque 17 | data: 18 | connection-string: {{ include "server.postgres-connstr" . | b64enc | quote }} 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /charts/prefect-worker/templates/pdb.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.worker.podDisruptionBudget -}} 2 | apiVersion: policy/v1 3 | kind: PodDisruptionBudget 4 | metadata: 5 | name: {{ template "common.names.fullname" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: worker 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.commonLabels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if .Values.commonAnnotations }} 14 | annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 15 | {{- end }} 16 | spec: 17 | selector: 18 | matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} 19 | app.kubernetes.io/component: worker 20 | {{ toYaml .Values.worker.podDisruptionBudget | indent 2 }} 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "server.serviceAccountName" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: server 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.commonLabels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if or .Values.serviceAccount.annotations .Values.commonAnnotations }} 14 | annotations: 15 | {{- if .Values.commonAnnotations }} 16 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 17 | {{- end }} 18 | {{- if .Values.serviceAccount.annotations }} 19 | {{- include "common.tplvalues.render" (dict "value" .Values.serviceAccount.annotations "context" $) | nindent 4 }} 20 | {{- end }} 21 | {{- end }} 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /charts/prefect-worker/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "worker.serviceAccountName" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: worker 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.commonLabels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if or .Values.serviceAccount.annotations .Values.commonAnnotations }} 14 | annotations: 15 | {{- if .Values.commonAnnotations }} 16 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 17 | {{- end }} 18 | {{- if .Values.serviceAccount.annotations }} 19 | {{- include "common.tplvalues.render" (dict "value" .Values.serviceAccount.annotations "context" $) | nindent 4 }} 20 | {{- end }} 21 | {{- end }} 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v3.1.0 5 | hooks: 6 | - id: check-merge-conflict 7 | - id: detect-private-key 8 | - id: no-commit-to-branch 9 | - id: trailing-whitespace 10 | 11 | - repo: https://github.com/norwoodj/helm-docs 12 | rev: v1.11.0 13 | hooks: 14 | - id: helm-docs 15 | args: 16 | - --template-files=README.md.gotmpl 17 | 18 | - repo: https://github.com/gruntwork-io/pre-commit 19 | rev: v0.1.17 20 | hooks: 21 | - id: helmlint 22 | 23 | - repo: https://github.com/rhysd/actionlint 24 | rev: v1.7.1 25 | hooks: 26 | - id: actionlint 27 | args: 28 | - -shellcheck= 29 | 30 | - repo: https://github.com/koalaman/shellcheck-precommit 31 | rev: v0.7.2 32 | hooks: 33 | - id: shellcheck 34 | args: ["--severity=error"] 35 | 36 | - repo: https://github.com/adrienverge/yamllint.git 37 | rev: v1.28.0 38 | hooks: 39 | - id: yamllint 40 | args: 41 | - --strict 42 | -------------------------------------------------------------------------------- /charts/prefect-server/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | appVersion: 3-latest 3 | dependencies: 4 | - name: common 5 | repository: https://charts.bitnami.com/bitnami 6 | tags: 7 | - bitnami-common 8 | version: 2.31.4 9 | - name: postgresql 10 | condition: postgresql.enabled 11 | repository: https://charts.bitnami.com/bitnami 12 | version: 12.12.10 13 | - name: redis 14 | condition: redis.enabled 15 | repository: https://charts.bitnami.com/bitnami 16 | version: 22.0.4 17 | description: Prefect server application bundle 18 | engine: gotpl 19 | home: https://github.com/PrefectHQ 20 | maintainers: 21 | - name: jamiezieziula 22 | email: jamie@prefect.io 23 | - name: jimid27 24 | email: jimi@prefect.io 25 | - name: parkedwards 26 | email: edward@prefect.io 27 | - name: mitchnielsen 28 | email: mitchell@prefect.io 29 | name: prefect-server 30 | sources: 31 | - https://github.com/PrefectHQ/prefect-helm 32 | type: application 33 | # This version is never actually shipped. github actions will package add the appropriate version at build-time 34 | version: 0.0.0 35 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "common.names.fullname" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: 8 | {{- include "common.labels.standard" . | nindent 4 }} 9 | spec: 10 | scaleTargetRef: 11 | apiVersion: apps/v1 12 | kind: Deployment 13 | name: {{ include "common.names.fullname" . }} 14 | minReplicas: {{ .Values.autoscaling.minReplicas }} 15 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 16 | metrics: 17 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 18 | - type: Resource 19 | resource: 20 | name: cpu 21 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 22 | {{- end }} 23 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 24 | - type: Resource 25 | resource: 26 | name: memory 27 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 28 | {{- end }} 29 | {{- end }} 30 | -------------------------------------------------------------------------------- /charts/prefect-worker/templates/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rolebinding.create }} 2 | apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} 3 | kind: RoleBinding 4 | metadata: 5 | name: {{ template "common.names.fullname" . }} 6 | namespace: {{ default (include "common.names.namespace" .) .Values.role.namespace | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: worker 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.commonLabels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if .Values.commonAnnotations }} 14 | annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 15 | {{- end }} 16 | roleRef: 17 | apiGroup: rbac.authorization.k8s.io 18 | kind: Role 19 | name: {{ template "common.names.fullname" . }} 20 | subjects: 21 | - kind: ServiceAccount 22 | name: {{ template "worker.serviceAccountName" . }} 23 | namespace: {{ include "common.names.namespace" . | quote }} 24 | {{- end }} 25 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/templates/servicemonitor.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceMonitor.enabled }} 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: ServiceMonitor 4 | metadata: 5 | name: {{ include "common.names.fullname" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: 8 | {{- include "common.labels.standard" . | nindent 4 }} 9 | {{- with .Values.serviceMonitor.additionalLabels }} 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | spec: 13 | jobLabel: "{{ .Release.Name }}" 14 | selector: 15 | matchLabels: 16 | {{- include "common.labels.matchLabels" . | nindent 8 }} 17 | endpoints: 18 | - port: http 19 | interval: {{ .Values.serviceMonitor.interval | quote }} 20 | scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout | quote }} 21 | {{- if .Values.serviceMonitor.metricRelabelings }} 22 | metricRelabelings: 23 | {{- toYaml .Values.serviceMonitor.metricRelabelings | nindent 4 }} 24 | {{- end }} 25 | {{- if .Values.serviceMonitor.relabelings }} 26 | relabelings: 27 | {{- toYaml .Values.serviceMonitor.relabelings | nindent 4 }} 28 | {{- end }} 29 | {{- end -}} 30 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/background-services/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.backgroundServices.serviceAccount.create .Values.backgroundServices.runAsSeparateDeployment}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "backgroundServices.serviceAccountName" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: background-services 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.commonLabels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if or .Values.backgroundServices.serviceAccount.annotations .Values.commonAnnotations }} 14 | annotations: 15 | {{- if .Values.commonAnnotations }} 16 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 17 | {{- end }} 18 | {{- if .Values.backgroundServices.serviceAccount.annotations }} 19 | {{- include "common.tplvalues.render" (dict "value" .Values.backgroundServices.serviceAccount.annotations "context" $) | nindent 4 }} 20 | {{- end }} 21 | {{- end }} 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /charts/prefect-worker/templates/role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.role.create }} 2 | apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} 3 | kind: Role 4 | metadata: 5 | name: {{ include "common.names.fullname" . }} 6 | namespace: {{ default (include "common.names.namespace" .) .Values.role.namespace | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: worker 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.commonLabels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if .Values.commonAnnotations }} 14 | annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 15 | {{- end }} 16 | rules: 17 | - apiGroups: [""] 18 | resources: ["events", "pods", "pods/log", "pods/status"] 19 | verbs: ["get", "watch", "list"] 20 | - apiGroups: ["batch"] 21 | resources: ["jobs"] 22 | verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] 23 | {{- if .Values.role.extraPermissions }} 24 | {{- include "common.tplvalues.render" (dict "value" .Values.role.extraPermissions "context" $) | nindent 0 }} 25 | {{- end }} 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /.github/updatecli/manifest-major.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | sources: 3 | common: 4 | kind: helmchart 5 | spec: 6 | url: https://charts.bitnami.com/bitnami 7 | name: common 8 | versionFilter: 9 | kind: semver 10 | sourceid: common 11 | postgresql: 12 | kind: helmchart 13 | spec: 14 | url: https://charts.bitnami.com/bitnami 15 | name: postgresql 16 | versionFilter: 17 | kind: semver 18 | sourceid: postgresql 19 | conditions: {} 20 | targets: 21 | prometheus_prefect_exporter_common: 22 | name: bump chart dependencies 23 | kind: yaml 24 | spec: 25 | file: charts/prometheus-prefect-exporter/Chart.yaml 26 | key: dependencies[0].version 27 | sourceid: common 28 | server_common: 29 | name: bump chart dependencies 30 | kind: yaml 31 | spec: 32 | file: charts/prefect-server/Chart.yaml 33 | key: dependencies[0].version 34 | sourceid: common 35 | worker_common: 36 | name: bump chart dependencies 37 | kind: yaml 38 | spec: 39 | file: charts/prefect-worker/Chart.yaml 40 | key: dependencies[0].version 41 | sourceid: common 42 | server_postgresql: 43 | name: bump chart dependencies 44 | kind: yaml 45 | spec: 46 | file: charts/prefect-server/Chart.yaml 47 | key: dependencies[1].version 48 | sourceid: postgresql 49 | -------------------------------------------------------------------------------- /.github/updatecli/manifest-minor.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | sources: 3 | common: 4 | kind: helmchart 5 | spec: 6 | url: https://charts.bitnami.com/bitnami 7 | name: common 8 | versionFilter: 9 | kind: semver 10 | pattern: 2.x.x 11 | sourceid: common 12 | postgresql: 13 | kind: helmchart 14 | spec: 15 | url: https://charts.bitnami.com/bitnami 16 | name: postgresql 17 | versionFilter: 18 | kind: semver 19 | pattern: 12.x.x 20 | sourceid: postgresql 21 | conditions: {} 22 | targets: 23 | prometheus_prefect_exporter_common: 24 | name: bump chart dependencies 25 | kind: yaml 26 | spec: 27 | file: charts/prometheus-prefect-exporter/Chart.yaml 28 | key: dependencies[0].version 29 | sourceid: common 30 | server_common: 31 | name: bump chart dependencies 32 | kind: yaml 33 | spec: 34 | file: charts/prefect-server/Chart.yaml 35 | key: dependencies[0].version 36 | sourceid: common 37 | worker_common: 38 | name: bump chart dependencies 39 | kind: yaml 40 | spec: 41 | file: charts/prefect-worker/Chart.yaml 42 | key: dependencies[0].version 43 | sourceid: common 44 | server_postgresql: 45 | name: bump chart dependencies 46 | kind: yaml 47 | spec: 48 | file: charts/prefect-server/Chart.yaml 49 | key: dependencies[1].version 50 | sourceid: postgresql 51 | -------------------------------------------------------------------------------- /.github/workflows/server-lint-and-test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lint and Test Prefect Server Chart 3 | 4 | "on": 5 | pull_request_target: 6 | branches: 7 | - main 8 | 9 | permissions: 10 | # required to read from the repo 11 | contents: read 12 | 13 | jobs: 14 | lint_test: 15 | environment: ${{ 16 | (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) && 'Acceptance Tests (External)' || '' }} 17 | name: "lint-test (${{ matrix.kubernetes }})" 18 | runs-on: ubuntu-latest 19 | strategy: 20 | matrix: 21 | kubernetes: 22 | - "1.31.0" 23 | - "1.32.0" 24 | - "1.33.0" 25 | - "1.34.0" 26 | fail-fast: false 27 | 28 | steps: 29 | - name: Checkout Code 30 | uses: actions/checkout@v6 31 | with: 32 | repository: ${{ github.event.pull_request.head.repo.full_name }} 33 | ref: ${{ github.event.pull_request.head.sha }} 34 | 35 | - name: Set up Helm 36 | uses: azure/setup-helm@v4 37 | 38 | - name: Set up chart-testing 39 | uses: helm/chart-testing-action@v2.8.0 40 | 41 | - name: Run chart-testing (lint) 42 | run: ct lint --config .github/linters/server-ct.yaml 43 | 44 | - name: Create kind cluster 45 | uses: helm/kind-action@v1.13.0 46 | with: 47 | node_image: "kindest/node:v${{ matrix.kubernetes }}" 48 | 49 | - name: Run chart-testing (install) 50 | run: ct install --config .github/linters/server-ct.yaml --helm-extra-set-args "--set=postgresql.auth.password=TESTING" 51 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.server.autoscaling.enabled .Values.server.resources.requests (not .Values.sqlite.enabled) }} 2 | apiVersion: autoscaling/v2 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "common.names.fullname" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | prefect-version: {{ .Chart.AppVersion }} 9 | {{- if .Values.commonLabels }} 10 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 11 | {{- end }} 12 | {{- if .Values.commonAnnotations }} 13 | annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 14 | {{- end }} 15 | spec: 16 | scaleTargetRef: 17 | apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} 18 | kind: Deployment 19 | name: {{ include "common.names.fullname" . }} 20 | minReplicas: {{ .Values.server.autoscaling.minReplicas }} 21 | maxReplicas: {{ .Values.server.autoscaling.maxReplicas }} 22 | metrics: 23 | {{- if .Values.server.autoscaling.targetCPU }} 24 | - type: Resource 25 | resource: 26 | name: cpu 27 | target: 28 | type: Utilization 29 | averageUtilization: {{ .Values.server.autoscaling.targetCPU }} 30 | {{- end }} 31 | {{- if .Values.server.autoscaling.targetMemory }} 32 | - type: Resource 33 | resource: 34 | name: memory 35 | target: 36 | type: Utilization 37 | averageUtilization: {{ .Values.server.autoscaling.targetMemory }} 38 | {{- end }} 39 | {{- end }} 40 | -------------------------------------------------------------------------------- /charts/prefect-worker/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.worker.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ template "common.names.fullname" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: worker 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.commonLabels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if .Values.commonAnnotations }} 14 | annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 15 | {{- end }} 16 | spec: 17 | scaleTargetRef: 18 | apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} 19 | kind: Deployment 20 | name: {{ template "common.names.fullname" . }} 21 | minReplicas: {{ .Values.worker.autoscaling.minReplicas }} 22 | maxReplicas: {{ .Values.worker.autoscaling.maxReplicas }} 23 | metrics: 24 | {{- if .Values.worker.autoscaling.targetCPUUtilizationPercentage }} 25 | - type: Resource 26 | resource: 27 | name: cpu 28 | target: 29 | type: Utilization 30 | averageUtilization: {{ .Values.worker.autoscaling.targetCPUUtilizationPercentage }} 31 | {{- end }} 32 | {{- if .Values.worker.autoscaling.targetMemoryUtilizationPercentage }} 33 | - type: Resource 34 | resource: 35 | name: memory 36 | target: 37 | type: Utilization 38 | averageUtilization: {{ .Values.worker.autoscaling.targetMemoryUtilizationPercentage }} 39 | {{- end }} 40 | {{- end }} 41 | -------------------------------------------------------------------------------- /.github/workflows/prometheus-prefect-exporter-lint-and-test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lint and Test Prometheus Prefect Exporter Chart 3 | 4 | "on": 5 | pull_request_target: 6 | branches: 7 | - main 8 | 9 | permissions: 10 | # required to read from the repo 11 | contents: read 12 | 13 | jobs: 14 | lint_test: 15 | name: "lint-test (${{ matrix.kubernetes }})" 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | kubernetes: 20 | - "1.31.0" 21 | - "1.32.0" 22 | - "1.33.0" 23 | - "1.34.0" 24 | fail-fast: false 25 | 26 | steps: 27 | - name: Checkout Code 28 | uses: actions/checkout@v6 29 | with: 30 | repository: ${{ github.event.pull_request.head.repo.full_name }} 31 | ref: ${{ github.event.pull_request.head.sha }} 32 | 33 | - name: Set up Helm 34 | uses: azure/setup-helm@v4 35 | 36 | - name: Set up chart-testing 37 | uses: helm/chart-testing-action@v2.8.0 38 | 39 | - name: Run chart-testing (lint) 40 | run: ct lint --config .github/linters/prometheus-prefect-exporter-ct.yaml 41 | 42 | - name: Create kind cluster 43 | uses: helm/kind-action@v1.13.0 44 | with: 45 | node_image: "kindest/node:v${{ matrix.kubernetes }}" 46 | 47 | - name: Install Prefect Server 48 | run: | 49 | helm dependency build ./charts/prefect-server/ 50 | helm install prefect-server -n default ./charts/prefect-server/ --set=postgresql.auth.password=TESTING 51 | 52 | - name: Run chart-testing (install) 53 | run: | 54 | ct install --config .github/linters/prometheus-prefect-exporter-ct.yaml --helm-extra-set-args "--set=prefectApiUrl=http://prefect-server.default.svc.cluster.local:4200/api" 55 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "common.names.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "common.names.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "common.names.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "common.names.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") 20 | echo "Visit http://127.0.0.1:8080 to use your application" 21 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /.github/workflows/notify-on-failure.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Notify on Failure 3 | 4 | "on": 5 | workflow_run: 6 | workflows: 7 | - Release Prefect Server and Worker Helm Charts 8 | - Release Prometheus Prefect Exporter Helm Chart 9 | - Updatecli Major Dependency Updates 10 | - Updatecli Minor Dependency Updates 11 | - Update mise tool versions 12 | types: [completed] 13 | 14 | permissions: 15 | # required to introspect the workflow run 16 | actions: read 17 | # required to read from the repo 18 | contents: read 19 | 20 | jobs: 21 | notify: 22 | name: Notify on Failure 23 | runs-on: ubuntu-latest 24 | if: ${{ github.event.workflow_run.conclusion == 'failure' }} 25 | steps: 26 | - name: Format date 27 | run: | 28 | formatted_date=$(date -d "${{ github.event.workflow_run.run_started_at }}" "+%b %d at %I:%M %p") 29 | echo "FORMATTED_DATE=$formatted_date" >> $GITHUB_ENV 30 | 31 | - name: Send Slack notification 32 | uses: 8398a7/action-slack@v3 33 | with: 34 | status: custom 35 | # https://api.slack.com/reference/messaging/attachments 36 | custom_payload: | 37 | { 38 | attachments: [{ 39 | pretext: ':x: Workflow triggered by ${{ github.actor }} failed', 40 | title: '${{ github.event.workflow_run.display_title }} #${{github.event.workflow_run.run_number}}', 41 | title_link: '${{ github.event.workflow_run.html_url }}', 42 | footer: '${{ github.repository }} | ${{ env.FORMATTED_DATE }} UTC', 43 | footer_icon: 'https://slack-imgs.com/?c=1&o1=wi32.he32.si&url=https%3A%2F%2Fslack.github.com%2Fstatic%2Fimg%2Ffavicon-neutral.png', 44 | color: 'danger', 45 | }] 46 | } 47 | env: 48 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_GHA_JOB_STATUS }} 49 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/httproute-tls-redirect.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.gateway.enabled .Values.httproute.enabled .Values.httproute.tls.redirect }} 2 | apiVersion: gateway.networking.k8s.io/v1 3 | kind: HTTPRoute 4 | metadata: 5 | name: {{ printf "%s-tls-redirect" (include "httproute.name" .) }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: httproute 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.httproute.labels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.httproute.labels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if .Values.commonLabels }} 14 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 15 | {{- end }} 16 | {{- if or .Values.httproute.annotations .Values.commonAnnotations }} 17 | annotations: 18 | {{- if .Values.httproute.annotations }} 19 | {{- include "common.tplvalues.render" ( dict "value" .Values.httproute.annotations "context" $) | nindent 4 }} 20 | {{- end }} 21 | {{- if .Values.commonAnnotations }} 22 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 23 | {{- end }} 24 | {{- end }} 25 | spec: 26 | parentRefs: 27 | - name: {{ (.Values.httproute.parentRefs | first).name | default (include "gateway.name" $) | quote }} 28 | {{- if ((.Values.httproute.parentRefs | first).namespace) }} 29 | namespace: {{ (.Values.httproute.parentRefs | first).namespace | quote }} 30 | {{- end }} 31 | sectionName: http 32 | {{- $hostnames := include "gateway.hostnames" . | fromYamlArray }} 33 | {{- if $hostnames }} 34 | hostnames: 35 | {{- range $hostnames }} 36 | - {{ . | quote }} 37 | {{- end }} 38 | {{- end }} 39 | rules: 40 | - filters: 41 | - type: RequestRedirect 42 | requestRedirect: 43 | scheme: https 44 | port: {{ .Values.httproute.tls.redirectPort | default 443 }} 45 | statusCode: 301 46 | {{- end }} 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | .static_storage/ 56 | .media/ 57 | local_settings.py 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | # dask stuff 107 | dask-scheduler.o* 108 | dask-worker.o* 109 | scheduler.json 110 | 111 | # log files 112 | *.out 113 | 114 | # Helm stuff 115 | charts/*/charts 116 | requirements.lock 117 | Chart.lock 118 | 119 | # IDEs 120 | .vscode/ 121 | .idea/ 122 | 123 | # macs 124 | .DS_Store 125 | 126 | # for private values.yaml files 127 | *.private.y*ml 128 | -------------------------------------------------------------------------------- /.github/workflows/worker-lint-and-test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lint and Test Prefect Worker Chart 3 | 4 | "on": 5 | pull_request_target: 6 | branches: 7 | - main 8 | 9 | permissions: 10 | # required to read from the repo 11 | contents: read 12 | 13 | jobs: 14 | lint_test: 15 | environment: ${{ 16 | (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) && 'Acceptance Tests (External)' || '' }} 17 | name: "lint-test (${{ matrix.kubernetes }})" 18 | runs-on: ubuntu-latest 19 | strategy: 20 | matrix: 21 | kubernetes: 22 | - "1.31.0" 23 | - "1.32.0" 24 | - "1.33.0" 25 | - "1.34.0" 26 | fail-fast: false 27 | 28 | steps: 29 | - name: Checkout Code 30 | uses: actions/checkout@v6 31 | with: 32 | repository: ${{ github.event.pull_request.head.repo.full_name }} 33 | ref: ${{ github.event.pull_request.head.sha }} 34 | 35 | - name: Set up Helm 36 | uses: azure/setup-helm@v4 37 | 38 | - name: Set up chart-testing 39 | uses: helm/chart-testing-action@v2.8.0 40 | 41 | - name: Run chart-testing (lint) 42 | run: ct lint --config .github/linters/worker-ct.yaml 43 | 44 | - name: Create kind cluster 45 | uses: helm/kind-action@v1.13.0 46 | with: 47 | node_image: "kindest/node:v${{ matrix.kubernetes }}" 48 | 49 | - name: Create API Secret for Worker Chart 50 | run: | 51 | kubectl create ns prefect 52 | kubectl create secret generic prefect-api-key --from-literal=key=${{ secrets.PREFECT_CLOUD_API_KEY }} -n prefect 53 | 54 | - name: Run chart-testing (install) 55 | run: | 56 | ct install --config .github/linters/worker-ct.yaml --helm-extra-set-args "--set=worker.config.workPool=repo-prefect-helm-gha-workflow-tests --set=worker.cloudApiConfig.accountId=${{ secrets.PREFECT_CLOUD_ACCOUNT_ID }} --set=worker.cloudApiConfig.workspaceId=${{ secrets.PREFECT_CLOUD_WORKSPACE_ID }} --set=worker.cloudApiConfig.cloudUrl=${{ secrets.PREFECT_CLOUD_API_URL }}" 57 | -------------------------------------------------------------------------------- /charts/prefect-server/tests/gateway_ingress_exclusivity_test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | suite: Gateway and Ingress Mutual Exclusivity 3 | release: 4 | name: exclusivity-test 5 | namespace: prefect 6 | capabilities: 7 | apiVersions: 8 | - gateway.networking.k8s.io/v1/Gateway 9 | - gateway.networking.k8s.io/v1/HTTPRoute 10 | 11 | tests: 12 | - it: Should fail when both Gateway and Ingress are enabled 13 | set: 14 | gateway: 15 | enabled: true 16 | className: "istio" 17 | ingress: 18 | enabled: true 19 | asserts: 20 | - template: NOTES.txt 21 | failedTemplate: 22 | errorMessage: "Gateway API and Ingress are mutually exclusive. Only one can be enabled at a time. Please set either gateway.enabled=false or ingress.enabled=false." 23 | 24 | - it: Should fail when Gateway is enabled without className 25 | set: 26 | gateway: 27 | enabled: true 28 | className: "" 29 | asserts: 30 | - template: NOTES.txt 31 | failedTemplate: 32 | errorMessage: "gateway.className is required when gateway.enabled=true. Please specify a GatewayClass that exists in your cluster." 33 | 34 | - it: Should succeed when only Gateway is enabled with className 35 | set: 36 | gateway: 37 | enabled: true 38 | className: "istio" 39 | ingress: 40 | enabled: false 41 | asserts: 42 | - template: gateway.yaml 43 | hasDocuments: 44 | count: 1 45 | 46 | - it: Should succeed when only Ingress is enabled 47 | set: 48 | gateway: 49 | enabled: false 50 | ingress: 51 | enabled: true 52 | host: 53 | hostname: "prefect.example.com" 54 | asserts: 55 | - template: ingress.yaml 56 | hasDocuments: 57 | count: 1 58 | 59 | - it: Should succeed when both are disabled 60 | set: 61 | gateway: 62 | enabled: false 63 | ingress: 64 | enabled: false 65 | asserts: 66 | - template: gateway.yaml 67 | hasDocuments: 68 | count: 0 69 | - template: ingress.yaml 70 | hasDocuments: 71 | count: 0 72 | -------------------------------------------------------------------------------- /.mise.toml: -------------------------------------------------------------------------------- 1 | [tools] 2 | actionlint = "1.7.9" 3 | github-cli = "2.83.1" 4 | helm = "3.19" 5 | helm-ct = "3.14.0" 6 | helm-docs = '1.14.2' 7 | pre-commit = "4.5.0" 8 | shellcheck = "0.11.0" 9 | yamllint = "1.37.1" 10 | 11 | # Variables 12 | [env] 13 | WORKER_CHART_NAME = "prefect-worker" 14 | WORKER_CHART_PATH = "./charts/prefect-worker" 15 | WORKER_RELEASE_NAME = "prefect-worker" 16 | SERVER_CHART_NAME = "prefect-server" 17 | SERVER_CHART_PATH = "./charts/prefect-server" 18 | SERVER_RELEASE_NAME = "prefect-server" 19 | PROMETHEUS_PREFECT_EXPORTER_CHART_NAME = "prometheus-prefect-exporter" 20 | PROMETHEUS_PREFECT_EXPORTER_CHART_PATH = "./charts/prometheus-prefect-exporter" 21 | NAMESPACE = "prefect" 22 | VALUES_FILE = "./charts/prefect-server/values.yaml" 23 | 24 | [tasks.tools] 25 | description = "Install all tools and setup pre-commit" 26 | depends = ["mise", "pre-commit-install"] 27 | 28 | [tasks.mise] 29 | description = "Install mise tools" 30 | run = "mise install --yes" 31 | 32 | [tasks.pre-commit-install] 33 | description = "Install pre-commit hooks" 34 | run = "pre-commit install" 35 | outputs = [".git/hooks/pre-commit"] 36 | 37 | [tasks.tools-list] 38 | description = "List current mise tools" 39 | run = "mise list --current" 40 | 41 | [tasks.helm-repo] 42 | description = "Add required Helm repositories" 43 | run = "helm repo add bitnami https://charts.bitnami.com/bitnami" 44 | 45 | [tasks.buildprom] 46 | description = "Build Prometheus Prefect Exporter Helm dependencies" 47 | run = "helm dependency build $PROMETHEUS_PREFECT_EXPORTER_CHART_PATH" 48 | depends = ["helm-repo"] 49 | 50 | [tasks.buildserver] 51 | description = "Build Server Helm dependencies" 52 | run = "helm dependency build $SERVER_CHART_PATH" 53 | depends = ["helm-repo"] 54 | 55 | [tasks.buildworker] 56 | description = "Build Worker Helm dependencies" 57 | run = "helm dependency build $WORKER_CHART_PATH" 58 | depends = ["helm-repo"] 59 | 60 | [tasks.buildall] 61 | description = "Build all Helm dependencies" 62 | depends = ["buildworker", "buildserver", "buildprom"] 63 | 64 | [tasks.helmtest] 65 | description = "Run Helm unittest" 66 | run = "./scripts/helm_unittest.sh" 67 | 68 | [tasks.charttest] 69 | description = "Run chart-testing" 70 | run = "./scripts/helm_charttest.sh" 71 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | {{- include "prefect-server.validatePrefectVersion" . }} 2 | {{- include "prefect-server.validatePrefectServerApiSettings" . }} 3 | {{- include "prefect-server.validateMessaging" . }} 4 | {{- include "prefect-server.validateGatewayAPI" . }} 5 | {{- if .Values.gateway.enabled }} 6 | Gateway API is enabled. Access Prefect via your Gateway's configured hostname(s): 7 | {{- $hostnames := include "gateway.hostnames" . | fromYamlArray }} 8 | {{- if $hostnames }} 9 | {{- range $hostnames }} 10 | https://{{ . }}{{ $.Values.httproute.path }} 11 | {{- end }} 12 | {{- else }} 13 | Configure hostnames in httproute.hostnames 14 | {{- end }} 15 | 16 | To check Gateway status: 17 | $ kubectl get gateway {{ include "gateway.name" . }} -n {{ .Release.Namespace }} 18 | $ kubectl get httproute {{ include "httproute.name" . }} -n {{ .Release.Namespace }} 19 | {{- else if .Values.ingress.enabled }} 20 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .Values.ingress.host.hostname }}{{ .Values.ingress.host.path }} 21 | {{- else if contains "NodePort" .Values.service.type }} 22 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "common.names.fullname" . }}) 23 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 24 | echo http://$NODE_IP:$NODE_PORT 25 | {{- else if contains "LoadBalancer" .Values.service.type }} 26 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 27 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "common.names.fullname" . }}' 28 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "common.names.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 29 | echo http://$SERVICE_IP:{{ .Values.service.port }} 30 | {{- else if contains "ClusterIP" .Values.service.type }} 31 | Run the following command to port-forward the UI to your localhost: 32 | $ kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ template "common.names.fullname" . }} {{ .Values.service.targetPort }}:{{ .Values.service.port }} 33 | 34 | Visit {{ include "server.uiUrl" . }} to use Prefect! 35 | {{- end }} 36 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/httproute.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.gateway.enabled .Values.httproute.enabled }} 2 | apiVersion: gateway.networking.k8s.io/v1 3 | kind: HTTPRoute 4 | metadata: 5 | name: {{ include "httproute.name" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: httproute 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.httproute.labels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.httproute.labels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if .Values.commonLabels }} 14 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 15 | {{- end }} 16 | {{- if or .Values.httproute.annotations .Values.commonAnnotations }} 17 | annotations: 18 | {{- if .Values.httproute.annotations }} 19 | {{- include "common.tplvalues.render" ( dict "value" .Values.httproute.annotations "context" $) | nindent 4 }} 20 | {{- end }} 21 | {{- if .Values.commonAnnotations }} 22 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 23 | {{- end }} 24 | {{- end }} 25 | spec: 26 | parentRefs: 27 | {{- range .Values.httproute.parentRefs }} 28 | - name: {{ .name | default (include "gateway.name" $) | quote }} 29 | {{- if .namespace }} 30 | namespace: {{ .namespace | quote }} 31 | {{- end }} 32 | {{- if .sectionName }} 33 | sectionName: {{ .sectionName }} 34 | {{- end }} 35 | {{- if .port }} 36 | port: {{ .port }} 37 | {{- end }} 38 | {{- end }} 39 | {{- $hostnames := include "gateway.hostnames" . | fromYamlArray }} 40 | {{- if $hostnames }} 41 | hostnames: 42 | {{- range $hostnames }} 43 | - {{ . | quote }} 44 | {{- end }} 45 | {{- end }} 46 | rules: 47 | - matches: 48 | - path: 49 | type: PathPrefix 50 | value: {{ .Values.httproute.path | default "/" | quote }} 51 | backendRefs: 52 | - name: {{ include "common.names.fullname" . }} 53 | port: {{ .Values.service.port }} 54 | {{- if .Values.httproute.extraRules }} 55 | {{- include "common.tplvalues.render" ( dict "value" .Values.httproute.extraRules "context" $ ) | nindent 2 }} 56 | {{- end }} 57 | {{- end }} 58 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "common.names.fullname" . }} 5 | namespace: {{ include "common.names.namespace" . | quote }} 6 | labels: {{- include "common.labels.standard" . | nindent 4 }} 7 | app.kubernetes.io/component: server 8 | prefect-version: {{ .Chart.AppVersion }} 9 | {{- if .Values.commonLabels }} 10 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 11 | {{- end }} 12 | {{- if or .Values.service.annotations .Values.commonAnnotations }} 13 | annotations: 14 | {{- if .Values.service.annotations }} 15 | {{- include "common.tplvalues.render" ( dict "value" .Values.service.annotations "context" $) | nindent 4 }} 16 | {{- end }} 17 | {{- if .Values.commonAnnotations }} 18 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 19 | {{- end }} 20 | {{- end }} 21 | spec: 22 | type: {{ .Values.service.type }} 23 | {{- if and .Values.service.clusterIP (eq .Values.service.type "ClusterIP") }} 24 | clusterIP: {{ .Values.service.clusterIP }} 25 | {{- end }} 26 | {{- if eq .Values.service.type "NodePort" }} 27 | externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }} 28 | {{- end }} 29 | ports: 30 | - name: {{ .Values.service.portName }} 31 | port: {{ .Values.service.port }} 32 | protocol: TCP 33 | targetPort: {{ .Values.service.targetPort }} 34 | {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePort)) }} 35 | nodePort: {{ .Values.service.nodePort }} 36 | {{- else if eq .Values.service.type "ClusterIP" }} 37 | nodePort: null 38 | {{- end }} 39 | {{- range .Values.service.extraPorts }} 40 | - name: {{ .name }} 41 | protocol: TCP 42 | port: {{ .port }} 43 | targetPort: {{ .targetPort }} 44 | {{- if and (eq $.Values.service.type "NodePort") (not (empty .nodePort)) }} 45 | nodePort: {{ .nodePort }} 46 | {{- else if eq $.Values.service.type "ClusterIP" }} 47 | nodePort: null 48 | {{- end }} 49 | {{- end }} 50 | selector: {{- include "common.labels.matchLabels" . | nindent 4 }} 51 | app.kubernetes.io/component: server 52 | -------------------------------------------------------------------------------- /charts/prefect-worker/UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrade guidelines 2 | 3 | ## > 2025.3.7033449 4 | 5 | After version 2025.3.7033449, there have been several breaking changes to the `prefect-worker` chart: 6 | - The allowed values for the `apiConfig` key changed from `cloud`, `server`, or `selfManaged` to `cloud`, `selfHostedServer`, and `customerManagedCloud`. 7 | - The `serverApiConfig` key has been replaced with the `selfHostedServerApiConfig`. 8 | - `.Values.worker.serverApiConfig` => `.Values.worker.selfHostedServerApiConfig` 9 | - The `basicAuth` key has been nested under the `selfHostedServerApiConfig` key. 10 | - `.Values.worker.basicAuth` => `.Values.worker.selfHostedServerApiConfig.basicAuth` 11 | 12 | ### Adjusting Your Configuration 13 | 14 | #### Self Hosted Server Configuration 15 | 16 | **Before** 17 | 18 | ```yaml 19 | worker: 20 | basicAuth: 21 | ... 22 | apiConfig: server 23 | serverApiConfig: 24 | ... 25 | ``` 26 | 27 | **After** 28 | 29 | ```yaml 30 | worker: 31 | apiConfig: selfHostedServer 32 | selfHostedServerApiConfig: 33 | basicAuth: 34 | ... 35 | ``` 36 | 37 | #### Self Managed Cloud Configuration 38 | 39 | **Before** 40 | 41 | ```yaml 42 | worker: 43 | apiConfig: selfManaged 44 | ... 45 | ``` 46 | 47 | **After** 48 | 49 | ```yaml 50 | worker: 51 | apiConfig: customerManagedCloud 52 | ... 53 | ``` 54 | 55 | ### UI URL in NOTES.txt 56 | 57 | The UI URL related values (`Values.worker.serverApiConfig.uiUrl` and `.Values.worker.customerManagedCloudApiConfig.uiUrl`) have been removed. These values were previously only used in the NOTES.txt file to provide a link to the Prefect UI. 58 | 59 | --- 60 | 61 | ## > 2025.1.28020410 62 | 63 | After version `2025.1.28020410`, the `prefect-worker` chart renamed the `selfHostedCloudApiConfig` key to `customerManagedCloudApiConfig`. 64 | 65 | **Before** 66 | 67 | ```yaml 68 | worker: 69 | selfHostedCloudApiConfig: 70 | apiUrl: "" 71 | accountId: "" 72 | workspaceId: "" 73 | apiKeySecret: 74 | name: prefect-api-key 75 | key: key 76 | cloudApiUrl: "" 77 | uiUrl: "" 78 | ``` 79 | 80 | **After** 81 | 82 | ```yaml 83 | worker: 84 | customerManagedCloudApiConfig: 85 | apiUrl: "" 86 | accountId: "" 87 | workspaceId: "" 88 | apiKeySecret: 89 | name: prefect-api-key 90 | key: key 91 | cloudApiUrl: "" 92 | uiUrl: "" 93 | ``` 94 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/gateway.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.gateway.enabled }} 2 | apiVersion: gateway.networking.k8s.io/v1 3 | kind: Gateway 4 | metadata: 5 | name: {{ include "gateway.name" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: gateway 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.gateway.labels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.gateway.labels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if .Values.commonLabels }} 14 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 15 | {{- end }} 16 | {{- if or .Values.gateway.annotations .Values.commonAnnotations }} 17 | annotations: 18 | {{- if .Values.gateway.annotations }} 19 | {{- include "common.tplvalues.render" ( dict "value" .Values.gateway.annotations "context" $) | nindent 4 }} 20 | {{- end }} 21 | {{- if .Values.commonAnnotations }} 22 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 23 | {{- end }} 24 | {{- end }} 25 | spec: 26 | gatewayClassName: {{ .Values.gateway.className | quote }} 27 | {{- if .Values.gateway.infrastructure }} 28 | infrastructure: 29 | {{- include "common.tplvalues.render" ( dict "value" .Values.gateway.infrastructure "context" $ ) | nindent 4 }} 30 | {{- end }} 31 | listeners: 32 | {{- range .Values.gateway.listeners }} 33 | - name: {{ .name }} 34 | port: {{ .port }} 35 | protocol: {{ .protocol }} 36 | {{- if .hostname }} 37 | hostname: {{ .hostname | quote }} 38 | {{- end }} 39 | {{- if and (eq .protocol "HTTPS") .tls }} 40 | tls: 41 | mode: {{ .tls.mode | default "Terminate" }} 42 | {{- if .tls.certificateRefs }} 43 | certificateRefs: 44 | {{- range .tls.certificateRefs }} 45 | - kind: {{ .kind | default "Secret" }} 46 | {{- if .name }} 47 | name: {{ .name | quote }} 48 | {{- else }} 49 | name: {{ include "gateway.tlsSecretName" $ | quote }} 50 | {{- end }} 51 | {{- if .namespace }} 52 | namespace: {{ .namespace | quote }} 53 | {{- end }} 54 | {{- end }} 55 | {{- end }} 56 | {{- end }} 57 | {{- end }} 58 | {{- end }} 59 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/README.md.gotmpl: -------------------------------------------------------------------------------- 1 | {{ template "chart.header" . }} 2 | 3 | ## Overview 4 | 5 | This chart deploys a [Prometheus Exporter](https://github.com/PrefectHQ/prometheus-prefect-exporter) for Prefect Server, providing relevant metrics from your deployed Prefect Server instance. 6 | Shoutout to @ialejandro for the original work on this chart! 7 | 8 | ## Installing the Chart 9 | 10 | ### Prerequisites 11 | 12 | 1. Add the Prefect Helm repository to your Helm client: 13 | 14 | ```bash 15 | helm repo add prefect https://prefecthq.github.io/prefect-helm 16 | helm repo update 17 | ``` 18 | 19 | 2. Deploy a Prefect Server instance using the [Prefect Server Helm chart](https://github.com/PrefectHQ/prefect-helm/tree/main/charts/prefect-server) 20 | 21 | ### Install the Prefect Exporter chart 22 | 23 | 1. Configure the Prefect exporter values as needed 24 | Create a `values.yaml` file to customize the Prometheus Prefect Exporter configuration. 25 | 26 | 2. Install the chart 27 | ```bash 28 | helm install prometheus-prefect-exporter prefect/prometheus-prefect-exporter --namespace= -f values.yaml 29 | ``` 30 | 31 | 3. Verify the deployment 32 | 33 | Check the status of your Prometheus Prefect Exporter deployment: 34 | 35 | ```bash 36 | kubectl get pods -n prefect 37 | 38 | NAME READY STATUS RESTARTS AGE 39 | prometheus-prefect-exporter-76vxqnq 1/1 Running 0 25m 40 | ``` 41 | 42 | You should see the Prometheus Prefect Exporter pod running 43 | 44 | ## Additional Exporter Configurations 45 | 46 | ### Basic Auth 47 | 48 | Prefect documentation on [basic auth](https://docs.prefect.io/v3/develop/settings-and-profiles#security-settings) 49 | 50 | Self-hosted Prefect servers can be equipped with a Basic Authentication string for an administrator/password combination. Assuming you are running a self-hosted server with basic auth enabled, you can authenticate your exporter with the same credentials. 51 | 52 | The format of the auth string is `admin:` (no brackets). 53 | 54 | ```yaml 55 | basicAuth: 56 | enabled: true 57 | authString: "admin:pass" 58 | ``` 59 | 60 | Alternatively, you can provide an existing Kubernetes Secret containing the auth string credentials. The secret must contain a key `auth-string` with the value of the auth string. 61 | 62 | ```sh 63 | kubectl create secret generic prefect-basic-auth --from-literal=auth-string='admin:my-password' 64 | ``` 65 | 66 | ```yaml 67 | basicAuth: 68 | enabled: true 69 | existingSecret: prefect-basic-auth 70 | ``` 71 | 72 | 73 | {{ template "chart.maintainersSection" . }} 74 | 75 | {{ template "chart.requirementsSection" . }} 76 | 77 | {{ template "chart.valuesSection" . }} 78 | 79 | {{ template "helm-docs.versionFooter" . }} 80 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/_validation.tpl: -------------------------------------------------------------------------------- 1 | {{- define "prefect-server.validatePrefectVersion" -}} 2 | {{- if and .Values.backgroundServices.runAsSeparateDeployment (eq .Values.global.prefect.image.repository "prefecthq/prefect") -}} 3 | {{- $prefectTag := .Values.global.prefect.image.prefectTag -}} 4 | {{- if not (regexMatch "^[0-9]+" $prefectTag) -}} 5 | {{- fail "When running background services separately, Prefect tag must start with a version number" -}} 6 | {{- end -}} 7 | 8 | {{- $version := regexFind "^[0-9]+\\.[0-9]+\\.[0-9]+" $prefectTag -}} 9 | {{- if not $version -}} 10 | {{- fail "When running background services separately, Prefect tag must be in format X.Y.Z" -}} 11 | {{- end -}} 12 | 13 | {{- $parts := splitList "." $version -}} 14 | {{- $major := index $parts 0 | atoi -}} 15 | {{- $minor := index $parts 1 | atoi -}} 16 | {{- $patch := index $parts 2 | atoi -}} 17 | 18 | {{- if or (lt $major 3) (and (eq $major 3) (lt $minor 1)) (and (eq $major 3) (eq $minor 1) (lt $patch 13)) -}} 19 | {{- fail "When running background services separately, Prefect version must be 3.1.13 or higher" -}} 20 | {{- end -}} 21 | {{- end -}} 22 | {{- end -}} 23 | 24 | {{- define "prefect-server.validatePrefectServerApiSettings" -}} 25 | {{- if .Values.global.prefect.prefectApiUrl -}} 26 | {{- fail "`global.prefect.prefectApiUrl` has been removed. Please use `server.uiConfig.prefectUiApiUrl` instead." -}} 27 | {{- end -}} 28 | {{- if .Values.global.prefect.prefectApiHost -}} 29 | {{- fail "`global.prefect.prefectApiHost` has been removed. Please use `server.uiConfig.prefectUiApiUrl` instead." -}} 30 | {{- end -}} 31 | {{- if .Values.server.uiConfig.prefectUiUrl -}} 32 | {{- fail "`server.uiConfig.prefectUiUrl` has been removed. This value was used solely for the purposes of printing out the UI URL during the installation process. It will now infer the UI URL from the `prefectUiApiUrl` value." -}} 33 | {{- end -}} 34 | {{- end -}} 35 | 36 | {{- define "prefect-server.validateMessaging" -}} 37 | {{- if and (.Values.backgroundServices.runAsSeparateDeployment) (and (not .Values.redis.enabled) (.Values.backgroundServices.messaging.redis.host | empty)) -}} 38 | {{- fail "You must set redis.enabled=true or provide a redis configuration when backgroundServices.runAsSeparateDeployment=true" -}} 39 | {{- end -}} 40 | {{- end -}} 41 | 42 | {{- define "prefect-server.validateGatewayAPI" -}} 43 | {{- if and .Values.gateway.enabled .Values.ingress.enabled -}} 44 | {{- fail "Gateway API and Ingress are mutually exclusive. Only one can be enabled at a time. Please set either gateway.enabled=false or ingress.enabled=false." -}} 45 | {{- end -}} 46 | {{- if and .Values.gateway.enabled (not .Values.gateway.className) -}} 47 | {{- fail "gateway.className is required when gateway.enabled=true. Please specify a GatewayClass that exists in your cluster." -}} 48 | {{- end -}} 49 | {{- if and .Values.gateway.enabled (not (include "gateway.apiAvailable" .)) -}} 50 | {{- fail "Gateway API (gateway.networking.k8s.io/v1) is not available in this cluster. Please install Gateway API CRDs or disable gateway.enabled." -}} 51 | {{- end -}} 52 | {{- end -}} 53 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled }} 2 | apiVersion: {{ include "common.capabilities.ingress.apiVersion" . }} 3 | kind: Ingress 4 | metadata: 5 | name: {{ template "common.names.fullname" . }} 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: server 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.commonLabels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if or .Values.ingress.annotations .Values.commonAnnotations }} 14 | annotations: 15 | {{- if .Values.ingress.annotations }} 16 | {{- include "common.tplvalues.render" ( dict "value" .Values.ingress.annotations "context" $) | nindent 4 }} 17 | {{- end }} 18 | {{- if .Values.commonAnnotations }} 19 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 20 | {{- end }} 21 | {{- end }} 22 | spec: 23 | {{- if .Values.ingress.className }} 24 | ingressClassName: {{ .Values.ingress.className | quote }} 25 | {{- end }} 26 | rules: 27 | {{- if .Values.ingress.host.hostname }} 28 | - host: {{ .Values.ingress.host.hostname | quote }} 29 | http: 30 | paths: 31 | {{- if .Values.ingress.extraPaths }} 32 | {{- toYaml .Values.ingress.extraPaths | nindent 10 }} 33 | {{- end }} 34 | - path: {{ .Values.ingress.host.path }} 35 | pathType: {{ .Values.ingress.host.pathType }} 36 | backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" .) "servicePort" .Values.ingress.servicePort "context" $) | nindent 14 }} 37 | {{- end }} 38 | {{- range .Values.ingress.extraHosts }} 39 | - host: {{ .name | quote }} 40 | http: 41 | paths: 42 | - path: {{ default "/" .path }} 43 | pathType: {{ default "ImplementationSpecific" .pathType }} 44 | backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" $) "servicePort" $.Values.ingress.servicePort "context" $) | nindent 14 }} 45 | {{- end }} 46 | {{- if .Values.ingress.extraRules }} 47 | {{- include "common.tplvalues.render" (dict "value" .Values.ingress.extraRules "context" $) | nindent 4 }} 48 | {{- end }} 49 | {{- if or (and .Values.ingress.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations )) .Values.ingress.selfSigned)) .Values.ingress.extraTls }} 50 | tls: 51 | {{- if or (and .Values.ingress.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations )) .Values.ingress.selfSigned)) }} 52 | - hosts: 53 | - {{ .Values.ingress.host.hostname | quote }} 54 | secretName: {{ printf "%s-tls" .Values.ingress.host.hostname }} 55 | {{- end }} 56 | {{- if .Values.ingress.extraTls }} 57 | {{- include "common.tplvalues.render" (dict "value" .Values.ingress.extraTls "context" $) | nindent 4 }} 58 | {{- end }} 59 | {{- end }} 60 | {{- end }} 61 | -------------------------------------------------------------------------------- /charts/prefect-server/examples/gateway-values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Example values for deploying prefect-server with Gateway API 3 | # This example demonstrates: 4 | # - Gateway API with HTTPS and TLS 5 | # - Automatic HTTP to HTTPS redirect 6 | # - Custom hostnames and paths 7 | # - TLS certificate configuration 8 | 9 | # Disable Ingress (Gateway and Ingress are mutually exclusive) 10 | ingress: 11 | enabled: false 12 | 13 | # Enable and configure Gateway API 14 | gateway: 15 | enabled: true 16 | 17 | # GatewayClass name - must exist in your cluster 18 | # Common values: "istio", "envoy", "nginx", etc. 19 | className: "istio" 20 | 21 | # Optional: Custom Gateway name (defaults to release fullname) 22 | # name: "my-custom-gateway" 23 | 24 | # Optional: Add custom labels to the Gateway resource 25 | labels: 26 | environment: production 27 | team: platform 28 | 29 | # Optional: Add custom annotations to the Gateway resource 30 | annotations: 31 | external-dns.alpha.kubernetes.io/hostname: "prefect.example.com" 32 | 33 | # Gateway listeners configuration 34 | listeners: 35 | # HTTP listener on port 80 36 | - name: http 37 | port: 80 38 | protocol: HTTP 39 | hostname: "" 40 | 41 | # HTTPS listener on port 443 42 | - name: https 43 | port: 443 44 | protocol: HTTPS 45 | hostname: "" 46 | tls: 47 | mode: Terminate 48 | certificateRefs: 49 | - kind: Secret 50 | # TLS certificate Secret name 51 | # The secret should contain tls.crt and tls.key 52 | name: "prefect-tls-cert" 53 | # Optional: specify namespace if secret is in a different namespace 54 | # namespace: "cert-manager" 55 | 56 | # HTTPRoute configuration 57 | httproute: 58 | # HTTPRoute is enabled by default when gateway.enabled=true 59 | enabled: true 60 | 61 | # Optional: Custom HTTPRoute name (defaults to release fullname) 62 | # name: "my-custom-httproute" 63 | 64 | # Hostnames that this HTTPRoute should match 65 | hostnames: 66 | - "prefect.example.com" 67 | # Optional: Add additional hostnames 68 | # - "prefect-alt.example.com" 69 | 70 | # Parent Gateway references 71 | # Defaults shown below - usually you don't need to override these 72 | parentRefs: 73 | - name: "" # Defaults to gateway.name 74 | namespace: "" # Defaults to release namespace 75 | sectionName: https # Which listener to attach to 76 | port: null # Optional: specify port if needed 77 | 78 | # Optional: Add custom labels to the HTTPRoute resource 79 | labels: 80 | app: prefect 81 | 82 | # Optional: Add custom annotations to the HTTPRoute resource 83 | annotations: 84 | custom-annotation: value 85 | 86 | # TLS redirect configuration 87 | tls: 88 | # Enable automatic HTTP to HTTPS redirect 89 | redirect: true 90 | # HTTPS port for redirect (defaults to 443) 91 | redirectPort: 443 92 | 93 | # Server configuration 94 | server: 95 | # Configure the Prefect UI API URL 96 | # This should match your Gateway hostname 97 | uiConfig: 98 | prefectUiApiUrl: "https://prefect.example.com/api" 99 | 100 | # Service configuration 101 | service: 102 | type: ClusterIP 103 | port: 4200 104 | 105 | # Database configuration 106 | postgresql: 107 | enabled: true 108 | auth: 109 | username: prefect 110 | password: prefect-password 111 | database: prefect 112 | 113 | # Redis configuration (required for background services) 114 | redis: 115 | enabled: true 116 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/pre-upgrade-hook.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.backgroundServices.runAsSeparateDeployment (not .Values.sqlite.enabled) .Values.migrations.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "common.names.fullname" . }}-db-migrations 6 | namespace: {{ .Release.Namespace }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | prefect-version: {{ .Chart.AppVersion }} 9 | {{- if .Values.commonLabels }} 10 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 11 | {{- end }} 12 | app.kubernetes.io/component: pre-upgrade-hook 13 | annotations: 14 | "helm.sh/hook": post-install,pre-upgrade 15 | "helm.sh/hook-weight": "-5" 16 | "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded 17 | spec: 18 | {{- if .Values.migrations.timeoutSeconds }} 19 | activeDeadlineSeconds: {{ .Values.migrations.timeoutSeconds }} 20 | {{- end }} 21 | backoffLimit: {{ .Values.migrations.backoffLimit }} 22 | template: 23 | metadata: 24 | labels: {{- include "common.labels.standard" . | nindent 8 }} 25 | app.kubernetes.io/component: pre-upgrade-hook 26 | prefect-version: {{ .Chart.AppVersion }} 27 | {{- if .Values.migrations.podLabels }} 28 | {{- include "common.tplvalues.render" (dict "value" .Values.migrations.podLabels "context" $) | nindent 8 }} 29 | {{- end }} 30 | spec: 31 | serviceAccountName: {{ include "server.serviceAccountName" . }} 32 | restartPolicy: {{ .Values.migrations.restartPolicy }} 33 | containers: 34 | - name: pre-upgrade-migration 35 | image: "{{ .Values.global.prefect.image.repository }}:{{ .Values.global.prefect.image.prefectTag }}" 36 | imagePullPolicy: {{ .Values.global.prefect.image.pullPolicy }} 37 | {{- if .Values.migrations.entrypoint }} 38 | command: {{- toYaml .Values.migrations.entrypoint | nindent 10 }} 39 | {{- end }} 40 | args: 41 | - | 42 | set -eo pipefail 43 | echo "Starting database migration..." 44 | {{- tpl .Values.migrations.command . | nindent 10 }} 45 | env: 46 | - name: PREFECT_API_DATABASE_CONNECTION_URL 47 | valueFrom: 48 | secretKeyRef: 49 | name: {{ include "server.postgres-string-secret-name" . }} 50 | key: connection-string 51 | {{- if .Values.global.prefect.env }} 52 | {{- include "common.tplvalues.render" (dict "value" .Values.global.prefect.env "context" $) | nindent 8 }} 53 | {{- end }} 54 | {{- if .Values.server.env }} 55 | {{- include "common.tplvalues.render" (dict "value" .Values.server.env "context" $) | nindent 8 }} 56 | {{- end }} 57 | {{- if .Values.migrations.env }} 58 | {{- include "common.tplvalues.render" (dict "value" .Values.migrations.env "context" $) | nindent 8 }} 59 | {{- end }} 60 | resources: {{- toYaml .Values.migrations.resources | nindent 10 }} 61 | securityContext: {{- toYaml .Values.migrations.securityContext | nindent 10 }} 62 | {{- if .Values.migrations.extraVolumeMounts }} 63 | volumeMounts: {{- toYaml .Values.migrations.extraVolumeMounts | nindent 10 }} 64 | {{- end }} 65 | {{- if .Values.migrations.extraVolumes }} 66 | volumes: {{- toYaml .Values.migrations.extraVolumes | nindent 8 }} 67 | {{- end }} 68 | {{- if .Values.migrations.affinity }} 69 | affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.migrations.affinity "context" $) | nindent 8 }} 70 | {{- end }} 71 | {{- if .Values.migrations.nodeSelector }} 72 | nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.migrations.nodeSelector "context" $) | nindent 8 }} 73 | {{- end }} 74 | {{- if .Values.migrations.tolerations }} 75 | tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.migrations.tolerations "context" .) | nindent 8 }} 76 | {{- end }} 77 | {{- if .Values.global.prefect.image.pullSecrets }} 78 | imagePullSecrets: 79 | {{- range .Values.global.prefect.image.pullSecrets }} 80 | - name: {{ . }} 81 | {{- end }} 82 | {{- end }} 83 | {{- end }} 84 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "common.names.fullname" . }} 5 | namespace: {{ include "common.names.namespace" . | quote }} 6 | labels: 7 | {{- include "common.labels.standard" . | nindent 4 }} 8 | spec: 9 | revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} 10 | {{- if not .Values.autoscaling.enabled }} 11 | replicas: {{ .Values.replicaCount }} 12 | {{- end }} 13 | selector: 14 | matchLabels: 15 | {{- include "common.labels.matchLabels" . | nindent 6 }} 16 | template: 17 | metadata: 18 | {{- with .Values.podAnnotations }} 19 | annotations: 20 | {{- toYaml . | nindent 8 }} 21 | {{- end }} 22 | labels: 23 | {{- include "common.labels.matchLabels" . | nindent 8 }} 24 | spec: 25 | {{- with .Values.imagePullSecrets }} 26 | imagePullSecrets: 27 | {{- toYaml . | nindent 8 }} 28 | {{- end }} 29 | {{- if .Values.serviceAccount.useServiceAccount }} 30 | serviceAccountName: {{ .Values.serviceAccount.useServiceAccount }} 31 | {{ else }} 32 | serviceAccountName: {{ include "prometheus-prefect-exporter.serviceAccountName" . }} 33 | {{- end }} 34 | securityContext: 35 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 36 | containers: 37 | - name: {{ .Chart.Name }} 38 | securityContext: 39 | {{- toYaml .Values.securityContext | nindent 12 }} 40 | image: {{ include "common.images.image" (dict "imageRoot" .Values.image)}} 41 | imagePullPolicy: {{ .Values.image.pullPolicy }} 42 | args: 43 | {{- if .Values.containerArgs }} 44 | {{- range .Values.containerArgs }} 45 | - {{ . | quote }} 46 | {{- end }} 47 | {{- end }} 48 | ports: 49 | - name: http 50 | containerPort: {{ .Values.service.targetPort | default .Values.service.port }} 51 | protocol: TCP 52 | {{- if .Values.livenessProbe }} 53 | livenessProbe: 54 | httpGet: 55 | path: / 56 | port: http 57 | {{- end }} 58 | {{- if .Values.readinessProbe }} 59 | readinessProbe: 60 | httpGet: 61 | path: / 62 | port: http 63 | {{- end }} 64 | env: 65 | - name: PREFECT_API_URL 66 | value: {{ .Values.prefectApiUrl }} 67 | {{- if .Values.csrfAuth }} 68 | - name: PREFECT_CSRF_ENABLED 69 | value: "True" 70 | {{- end }} 71 | {{- if .Values.pagination.enabled }} 72 | - name: PAGINATION_LIMIT 73 | value: {{ .Values.pagination.limit | quote }} 74 | - name: PAGINATION_ENABLED 75 | value: "True" 76 | {{- end }} 77 | {{- if not .Values.pagination.enabled }} 78 | - name: PAGINATION_ENABLED 79 | value: "False" 80 | {{- end }} 81 | {{- if .Values.env }} 82 | {{- range $key, $value := .Values.env }} 83 | - name: {{ $key | upper }} 84 | value: {{ $value | quote }} 85 | {{- end }} 86 | {{- end }} 87 | {{- if .Values.basicAuth.enabled }} 88 | - name: PREFECT_API_AUTH_STRING 89 | {{- if .Values.basicAuth.existingSecret }} 90 | valueFrom: 91 | secretKeyRef: 92 | name: {{ .Values.basicAuth.existingSecret }} 93 | key: auth-string 94 | {{- else }} 95 | value: {{ .Values.basicAuth.authString | quote }} 96 | {{- end }} 97 | {{- end }} 98 | {{- if .Values.extraEnvVars }} 99 | {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 10 }} 100 | {{- end }} 101 | resources: 102 | {{- toYaml .Values.resources | nindent 12 }} 103 | {{- with .Values.nodeSelector }} 104 | nodeSelector: 105 | {{- toYaml . | nindent 8 }} 106 | {{- end }} 107 | {{- with .Values.affinity }} 108 | affinity: 109 | {{- toYaml . | nindent 8 }} 110 | {{- end }} 111 | {{- with .Values.tolerations }} 112 | tolerations: 113 | {{- toYaml . | nindent 8 }} 114 | {{- end }} 115 | -------------------------------------------------------------------------------- /charts/prefect-worker/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Create the name of the service account to use 3 | */}} 4 | {{- define "worker.serviceAccountName" -}} 5 | {{- if .Values.serviceAccount.create -}} 6 | {{ default (include "common.names.fullname" .) .Values.serviceAccount.name }} 7 | {{- else -}} 8 | {{ default "default" .Values.serviceAccount.name }} 9 | {{- end -}} 10 | {{- end -}} 11 | 12 | {{/* 13 | Require Prefect Cloud Account ID 14 | */}} 15 | {{- define "cloud.requiredConfig.accountId" -}} 16 | {{- if eq .Values.worker.apiConfig "cloud" }} 17 | {{- required "A Prefect Cloud Account ID is required (worker.cloudApiConfig.accountId)" .Values.worker.cloudApiConfig.accountId -}} 18 | {{- end -}} 19 | {{- end -}} 20 | 21 | {{/* 22 | Require Prefect Cloud Workspace ID 23 | */}} 24 | {{- define "cloud.requiredConfig.workspaceId" -}} 25 | {{- if eq .Values.worker.apiConfig "cloud" }} 26 | {{- required "A Prefect Cloud Workspace ID is required (worker.cloudApiConfig.workspaceId)" .Values.worker.cloudApiConfig.workspaceId -}} 27 | {{- end -}} 28 | {{- end -}} 29 | 30 | {{/* 31 | Require Self-managed Cloud Account ID 32 | */}} 33 | {{- define "selfManaged.requiredConfig.accountId" -}} 34 | {{- if eq .Values.worker.apiConfig "customerManagedCloud" }} 35 | {{- required "A Prefect Cloud Account ID is required (worker.customerManagedCloudApiConfig.accountId)" .Values.worker.customerManagedCloudApiConfig.accountId -}} 36 | {{- end -}} 37 | {{- end -}} 38 | 39 | {{/* 40 | Require Self-managed Cloud Workspace ID 41 | */}} 42 | {{- define "selfManaged.requiredConfig.workspaceId" -}} 43 | {{- if eq .Values.worker.apiConfig "customerManagedCloud" }} 44 | {{- required "A Prefect Cloud Workspace ID is required (worker.customerManagedCloudApiConfig.workspaceId)" .Values.worker.customerManagedCloudApiConfig.workspaceId -}} 45 | {{- end -}} 46 | {{- end -}} 47 | 48 | {{/* 49 | Require Self-managed Cloud API URL 50 | */}} 51 | {{- define "selfManaged.requiredConfig.apiUrl" -}} 52 | {{- if eq .Values.worker.apiConfig "customerManagedCloud" }} 53 | {{- required "The Self-managed Cloud API URL is required (worker.customerManagedCloudApiConfig.apiUrl)" .Values.worker.customerManagedCloudApiConfig.apiUrl -}} 54 | {{- end -}} 55 | {{- end -}} 56 | 57 | {{/* 58 | Require Prefect Server API URL 59 | */}} 60 | {{- define "server.requiredConfig.apiUrl" -}} 61 | {{- if eq .Values.worker.apiConfig "selfHostedServer" }} 62 | {{- required "The Prefect Server API URL is required (worker.selfHostedServerApiConfig.apiUrl)" .Values.worker.selfHostedServerApiConfig.apiUrl -}} 63 | {{- end -}} 64 | {{- end -}} 65 | 66 | {{/* 67 | worker.apiUrl: 68 | Define the API URL for the worker based on the API config 69 | */}} 70 | {{- define "worker.apiUrl" -}} 71 | {{- if eq .Values.worker.apiConfig "cloud" }} 72 | {{- printf "%s/accounts/%s/workspaces/%s" .Values.worker.cloudApiConfig.cloudUrl (include "cloud.requiredConfig.accountId" .) (include "cloud.requiredConfig.workspaceId" .) | quote }} 73 | {{- else if eq .Values.worker.apiConfig "customerManagedCloud" }} 74 | {{- printf "%s/accounts/%s/workspaces/%s" (include "selfManaged.requiredConfig.apiUrl" .) (include "selfManaged.requiredConfig.accountId" .) (include "selfManaged.requiredConfig.workspaceId" .) | quote }} 75 | {{- else if eq .Values.worker.apiConfig "selfHostedServer" }} 76 | {{- include "server.requiredConfig.apiUrl" . | quote }} 77 | {{- end }} 78 | {{- end }} 79 | 80 | 81 | {{/* 82 | worker.clusterUUID: 83 | Define cluster UID either from user-defined UID or by doing a lookup at helm install time 84 | */}} 85 | {{- define "worker.clusterUUID" -}} 86 | {{- $defaultDict := dict "metadata" (dict "uid" "") -}} 87 | {{- if .Values.worker.clusterUid }} 88 | {{- .Values.worker.clusterUid | quote }} 89 | {{- else }} 90 | {{- (lookup "v1" "Namespace" "" "kube-system" | default $defaultDict).metadata.uid | quote }} 91 | {{- end }} 92 | {{- end }} 93 | 94 | {{/* 95 | Determine the name of the ConfigMap for the baseJobTemplate 96 | */}} 97 | {{- define "worker.baseJobTemplateName" -}} 98 | {{- if .Values.worker.config.baseJobTemplate.configuration -}} 99 | {{ default "prefect-worker-base-job-template" .Values.worker.config.baseJobTemplate.name . }} 100 | {{- else if .Values.worker.config.baseJobTemplate.existingConfigMapName -}} 101 | {{ .Values.worker.config.baseJobTemplate.existingConfigMapName }} 102 | {{- else -}} 103 | {{- end -}} 104 | {{- end -}} 105 | -------------------------------------------------------------------------------- /.github/workflows/prometheus-exporter-helm-release.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release Prometheus Prefect Exporter Helm Chart 3 | 4 | "on": 5 | workflow_dispatch: {} 6 | 7 | permissions: 8 | # GitHub considers creating releases and uploading assets as writing contents. 9 | contents: write 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | outputs: 15 | releaseVersion: ${{ steps.output_version.outputs.releaseVersion }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v6 19 | with: 20 | fetch-depth: 0 21 | 22 | # We set the chart release version here - the version schema 23 | # is a SemVer adherent date-based versioning scheme that looks like: 24 | # 2024.2.9125019 25 | # which equates to a release on 2/9/24 at 12:50:19 26 | - name: Get the version tags 27 | id: get_version 28 | run: | 29 | # Enable pipefail so git command failures do not result in null versions downstream 30 | set -x 31 | 32 | echo "RELEASE_VERSION=$(date +'%Y.%-m.%-d%H%M%S')" >> $GITHUB_ENV 33 | 34 | echo "PROMETHEUS_PREFECT_EXPORTER_VERSION=$(\ 35 | git ls-remote --tags --refs --sort="v:refname" \ 36 | https://github.com/PrefectHQ/prometheus-prefect-exporter | tail -n1 | sed 's/.*\///' \ 37 | )" >> $GITHUB_ENV 38 | 39 | - name: Output version as GitHub Output 40 | id: output_version 41 | run: | 42 | echo "releaseVersion=$RELEASE_VERSION" >> $GITHUB_OUTPUT 43 | 44 | - name: Copy Artifact Hub metadata 45 | run: | 46 | mkdir -p /tmp/chart 47 | cp artifacthub-repo.yml /tmp/chart 48 | 49 | - name: Configure Git 50 | run: | 51 | git config user.name "$GITHUB_ACTOR" 52 | git config user.email "$GITHUB_ACTOR@users.noreply.github.com" 53 | 54 | - name: Set up Helm 55 | uses: azure/setup-helm@v4 56 | 57 | - name: Prepare GPG key for signing 58 | run: | 59 | gpg_dir=/tmp/.gpg 60 | mkdir "$gpg_dir" 61 | keyring="$gpg_dir/secring.gpg" 62 | base64 -d <<< "$GPG_KEYRING_BASE64" > "$keyring" 63 | passphrase_file="$gpg_dir/passphrase" 64 | echo "$GPG_PASSPHRASE" > "$passphrase_file" 65 | echo "SIGN_PASSPHRASE_FILE=$passphrase_file" >> $GITHUB_ENV 66 | echo "SIGN_KEYRING=$keyring" >> $GITHUB_ENV 67 | env: 68 | GPG_KEYRING_BASE64: ${{ secrets.GPG_KEYRING_BASE64 }} 69 | GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} 70 | 71 | - name: Package Prometheus Exporter helm chart 72 | run: | 73 | mkdir -p /tmp/chart 74 | cd charts 75 | # Update the prefect version tag in values.yaml 76 | sed -i "s/tag:.*$/tag: $PROMETHEUS_PREFECT_EXPORTER_VERSION/g" prometheus-prefect-exporter/values.yaml 77 | helm package prometheus-prefect-exporter \ 78 | --destination /tmp/chart \ 79 | --dependency-update \ 80 | --version $RELEASE_VERSION \ 81 | --app-version $PROMETHEUS_PREFECT_EXPORTER_VERSION \ 82 | --sign --key 'jamie@prefect.io' \ 83 | --keyring $SIGN_KEYRING \ 84 | --passphrase-file $SIGN_PASSPHRASE_FILE 85 | 86 | - name: Update chart index 87 | run: | 88 | git stash # Stash changes to the values.yaml so checkout doesn't complain 89 | git checkout gh-pages 90 | helm repo index /tmp/chart --url https://prefecthq.github.io/prefect-helm/charts --merge ./index.yaml 91 | 92 | - name: Commit and push 93 | run: | 94 | cp /tmp/chart/artifacthub-repo.yml . 95 | cp /tmp/chart/index.yaml . 96 | cp /tmp/chart/prometheus-prefect-exporter-$RELEASE_VERSION.* ./charts 97 | git add ./artifacthub-repo.yml ./index.yaml ./charts/prometheus-prefect-exporter-$RELEASE_VERSION.* 98 | git commit -m "Release $RELEASE_VERSION" 99 | git push origin gh-pages 100 | 101 | - name: Create Github Release + Tag 102 | run: | 103 | gh release create $RELEASE_VERSION \ 104 | --generate-notes \ 105 | --notes "Packaged with Prometheus Prefect Exporter version \ 106 | [$PROMETHEUS_PREFECT_EXPORTER_VERSION](https://github.com/PrefectHQ/prometheus-prefect-exporter/releases/tag/$PROMETHEUS_PREFECT_EXPORTER_VERSION)" 107 | env: 108 | GH_TOKEN: ${{ github.token }} 109 | -------------------------------------------------------------------------------- /.github/workflows/helm-release.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release Prefect Server and Worker Helm Charts 3 | 4 | "on": 5 | workflow_dispatch: 6 | 7 | permissions: 8 | # GitHub considers creating releases and uploading assets as writing contents. 9 | contents: write 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | outputs: 15 | releaseVersion: ${{ steps.output_version.outputs.releaseVersion }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v6 19 | with: 20 | fetch-depth: 0 21 | 22 | # We set the chart release version here - the version schema 23 | # is a SemVer adherent date-based versioning scheme that looks like: 24 | # 2024.2.9125019 25 | # which equates to a release on 2/9/24 at 12:50:19 26 | - name: Get the version tags 27 | id: get_version 28 | run: | 29 | # Enable pipefail so git command failures do not result in null versions downstream 30 | set -x 31 | 32 | echo "RELEASE_VERSION=$(date +'%Y.%-m.%-d%H%M%S')" >> $GITHUB_ENV 33 | echo "PREFECT_VERSION=$(\ 34 | git ls-remote --tags --refs --sort="v:refname" \ 35 | https://github.com/PrefectHQ/prefect.git '3.*.*' \ 36 | | grep -E -v 'rc|dev' \ 37 | | tail -n1 \ 38 | | sed 's/.*\///' \ 39 | )" >> $GITHUB_ENV 40 | 41 | - name: Output version as GitHub Output 42 | id: output_version 43 | run: | 44 | echo "releaseVersion=$RELEASE_VERSION" >> $GITHUB_OUTPUT 45 | 46 | - name: Copy Artifact Hub metadata 47 | run: | 48 | mkdir -p /tmp/chart 49 | cp artifacthub-repo.yml /tmp/chart 50 | 51 | - name: Configure Git 52 | run: | 53 | git config user.name "$GITHUB_ACTOR" 54 | git config user.email "$GITHUB_ACTOR@users.noreply.github.com" 55 | 56 | - name: Set up Helm 57 | uses: azure/setup-helm@v4 58 | 59 | - name: Prepare GPG key for signing 60 | run: | 61 | gpg_dir=/tmp/.gpg 62 | mkdir "$gpg_dir" 63 | keyring="$gpg_dir/secring.gpg" 64 | base64 -d <<< "$GPG_KEYRING_BASE64" > "$keyring" 65 | passphrase_file="$gpg_dir/passphrase" 66 | echo "$GPG_PASSPHRASE" > "$passphrase_file" 67 | echo "SIGN_PASSPHRASE_FILE=$passphrase_file" >> $GITHUB_ENV 68 | echo "SIGN_KEYRING=$keyring" >> $GITHUB_ENV 69 | env: 70 | GPG_KEYRING_BASE64: ${{ secrets.GPG_KEYRING_BASE64 }} 71 | GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} 72 | 73 | - name: Add dependency chart repos 74 | run: | 75 | helm repo add bitnami https://charts.bitnami.com/bitnami 76 | 77 | - name: Package Worker helm chart 78 | run: | 79 | mkdir -p /tmp/chart 80 | cd charts 81 | # Update the prefect version tag in values.yaml 82 | sed -i "s/prefectTag:.*$/prefectTag: $PREFECT_VERSION-python3.11-kubernetes/g" prefect-worker/values.yaml 83 | helm package prefect-worker \ 84 | --destination /tmp/chart \ 85 | --dependency-update \ 86 | --version $RELEASE_VERSION \ 87 | --app-version $PREFECT_VERSION \ 88 | --sign --key 'jamie@prefect.io' \ 89 | --keyring $SIGN_KEYRING \ 90 | --passphrase-file $SIGN_PASSPHRASE_FILE 91 | 92 | - name: Package Server helm chart 93 | run: | 94 | mkdir -p /tmp/chart 95 | cd charts 96 | # Update the prefect version tag in values.yaml 97 | sed -i "s/prefectTag:.*$/prefectTag: $PREFECT_VERSION-python3.11/g" prefect-server/values.yaml 98 | helm package prefect-server \ 99 | --destination /tmp/chart \ 100 | --dependency-update \ 101 | --version $RELEASE_VERSION \ 102 | --app-version $PREFECT_VERSION \ 103 | --sign --key 'jamie@prefect.io' \ 104 | --keyring $SIGN_KEYRING \ 105 | --passphrase-file $SIGN_PASSPHRASE_FILE 106 | 107 | - name: Update chart index 108 | run: | 109 | git stash # Stash changes to the values.yaml so checkout doesn't complain 110 | git checkout gh-pages 111 | helm repo index /tmp/chart --url https://prefecthq.github.io/prefect-helm/charts --merge ./index.yaml 112 | 113 | - name: Commit and push 114 | run: | 115 | cp /tmp/chart/artifacthub-repo.yml . 116 | cp /tmp/chart/index.yaml . 117 | cp /tmp/chart/prefect-server-$RELEASE_VERSION.* ./charts 118 | cp /tmp/chart/prefect-worker-$RELEASE_VERSION.* ./charts 119 | git add ./artifacthub-repo.yml ./index.yaml ./charts/prefect-server-$RELEASE_VERSION.* ./charts/prefect-worker-$RELEASE_VERSION.* 120 | git commit -m "Release $RELEASE_VERSION" 121 | git push origin gh-pages 122 | 123 | - name: Create Github Release + Tag 124 | run: | 125 | gh release create $RELEASE_VERSION \ 126 | --generate-notes \ 127 | --notes "Packaged with Prefect version \ 128 | [$PREFECT_VERSION](https://github.com/PrefectHQ/prefect/releases/tag/$PREFECT_VERSION)" 129 | env: 130 | GH_TOKEN: ${{ github.token }} 131 | -------------------------------------------------------------------------------- /charts/prefect-server/tests/database_test.yaml: -------------------------------------------------------------------------------- 1 | suite: Database configuration 2 | release: 3 | name: database-test 4 | namespace: prefect 5 | 6 | # Anchors to reuse in the tests 7 | envSecretPath: &envSecretPath .spec.template.spec.containers[?(@.name == "prefect-server")].env[?(@.name == "PREFECT_API_DATABASE_CONNECTION_URL")].valueFrom.secretKeyRef.name 8 | defaultSecretName: &defaultSecretName prefect-server-postgresql-connection 9 | 10 | tests: 11 | # SQLite embedded database tests 12 | - it: Should correctly configure SQLite connection string 13 | set: 14 | postgresql: 15 | enabled: false 16 | sqlite: 17 | enabled: true 18 | asserts: 19 | - template: deployment.yaml 20 | contains: 21 | path: .spec.template.spec.containers[0].env 22 | content: 23 | name: PREFECT_API_DATABASE_CONNECTION_URL 24 | value: sqlite+aiosqlite:////data/prefect.db 25 | 26 | - it: Should correctly configure SQLite storage settings 27 | set: 28 | postgresql: 29 | enabled: false 30 | sqlite: 31 | enabled: true 32 | asserts: 33 | - template: deployment.yaml 34 | contains: 35 | path: .spec.template.spec.volumes 36 | content: 37 | name: sqlite-storage 38 | persistentVolumeClaim: 39 | claimName: prefect-server-sqlite 40 | - template: deployment.yaml 41 | contains: 42 | path: .spec.template.spec.containers[0].volumeMounts 43 | content: 44 | mountPath: /data 45 | name: sqlite-storage 46 | - template: pvc.yaml 47 | containsDocument: 48 | kind: PersistentVolumeClaim 49 | apiVersion: v1 50 | name: prefect-server-sqlite 51 | namespace: prefect 52 | 53 | - it: Should not allow an HPA 54 | set: 55 | postgresql: 56 | enabled: false 57 | sqlite: 58 | enabled: true 59 | server: 60 | autoscaling: 61 | enabled: true 62 | asserts: 63 | - template: hpa.yaml 64 | not: true 65 | containsDocument: 66 | apiVersion: autoscaling/v2 67 | kind: HorizontalPodAutoscaler 68 | name: prefect-server 69 | namespace: prefect 70 | 71 | - it: Should not allow more than 1 replica 72 | set: 73 | postgresql: 74 | enabled: false 75 | sqlite: 76 | enabled: true 77 | server: 78 | replicaCount: 5 79 | asserts: 80 | - template: deployment.yaml 81 | equal: 82 | path: .spec.replicas 83 | value: 1 84 | 85 | # Bundled PostgreSQL chart tests 86 | 87 | - it: Should produce the expected secret name and content with the defaults 88 | asserts: 89 | - template: secret.yaml 90 | equal: 91 | path: .metadata.name 92 | value: *defaultSecretName 93 | - template: secret.yaml 94 | equal: 95 | path: .data.connection-string 96 | decodeBase64: true 97 | value: postgresql+asyncpg://prefect:prefect-rocks@database-test-postgresql.prefect:5432/server 98 | - template: deployment.yaml 99 | equal: 100 | path: *envSecretPath 101 | value: *defaultSecretName 102 | 103 | - it: Should inject custom connection auth info 104 | set: 105 | postgresql: 106 | primary: 107 | service: 108 | ports: 109 | postgresql: 1234 110 | auth: 111 | username: myuser 112 | password: mypass 113 | database: mydb 114 | asserts: 115 | - template: secret.yaml 116 | equal: 117 | path: .data.connection-string 118 | decodeBase64: true 119 | value: postgresql+asyncpg://myuser:mypass@database-test-postgresql.prefect:1234/mydb 120 | 121 | - it: Should configure an external secret name correctly 122 | set: 123 | postgresql: 124 | auth: 125 | existingSecret: my-pg-secret 126 | asserts: 127 | - template: secret.yaml 128 | equal: 129 | path: .metadata.name 130 | value: my-pg-secret 131 | - template: deployment.yaml 132 | equal: 133 | path: *envSecretPath 134 | value: my-pg-secret 135 | 136 | 137 | # External PostgreSQL instance tests 138 | 139 | - it: Should inject custom connection auth info 140 | set: 141 | postgresql: 142 | enabled: false 143 | secret: 144 | username: foo 145 | password: bar 146 | host: mypghost.com 147 | port: 1234 148 | database: mydb 149 | asserts: 150 | - template: secret.yaml 151 | equal: 152 | path: .data.connection-string 153 | decodeBase64: true 154 | value: postgresql+asyncpg://foo:bar@mypghost.com:1234/mydb 155 | 156 | - it: Should fail if connection info is incomplete 157 | set: 158 | postgresql: 159 | enabled: false 160 | secret: 161 | username: foo 162 | password: bar 163 | # Not configured: 164 | # host: 165 | # port: 166 | # database: 167 | asserts: 168 | - failedTemplate: 169 | errorPattern: is required 170 | 171 | - it: Should configure an existing secret name correctly 172 | set: 173 | postgresql: 174 | enabled: false 175 | secret: 176 | create: false 177 | name: my-pg-secret 178 | asserts: 179 | - template: deployment.yaml 180 | equal: 181 | path: *envSecretPath 182 | value: my-pg-secret 183 | -------------------------------------------------------------------------------- /charts/prefect-server/UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrade guidelines 2 | 3 | ## Gateway API Support 4 | 5 | This release introduces support for [Kubernetes Gateway API](https://gateway-api.sigs.k8s.io/) as an alternative to the traditional Ingress API for exposing the Prefect server. Gateway API is the successor to Ingress and provides more advanced routing capabilities. 6 | 7 | ### What's New 8 | 9 | - **Gateway API Support**: New `gateway` and `httproute` configuration sections enable Gateway API resources 10 | - **Mutual Exclusivity**: Gateway API and Ingress are mutually exclusive - only one can be enabled at a time 11 | - **Backward Compatible**: Gateway API is disabled by default; existing Ingress configurations continue to work 12 | - **TLS Support**: Full TLS configuration including automatic HTTP to HTTPS redirect 13 | - **Advanced Routing**: Support for custom hostnames, labels, annotations, and infrastructure configuration 14 | 15 | ### Should You Migrate? 16 | 17 | **Gateway API is optional.** Your existing Ingress configuration will continue to work without any changes. Consider migrating if: 18 | 19 | - You want to use advanced Gateway API features (e.g., traffic splitting, header matching) 20 | - Your cluster already uses Gateway API for other applications 21 | - You prefer the more expressive Gateway API resource model 22 | 23 | ### Migration from Ingress to Gateway API 24 | 25 | If you want to migrate from Ingress to Gateway API: 26 | 27 | 1. **Prerequisites**: 28 | - Ensure Gateway API CRDs are installed (v1.0.0 or later) 29 | - Have a GatewayClass available (e.g., from Istio, Envoy Gateway, etc.) 30 | 31 | 2. **Update your values.yaml**: 32 | 33 | ```yaml 34 | gateway: 35 | enabled: true 36 | className: "your-gateway-class" # Replace with your GatewayClass name 37 | 38 | ingress: 39 | enabled: false 40 | 41 | httproute: 42 | hostnames: 43 | - "your-existing-hostname.example.com" 44 | tls: 45 | redirect: true # Optional: enable HTTP to HTTPS redirect 46 | ``` 47 | 48 | 3. **Test the migration**: 49 | - Deploy the updated chart to a test environment 50 | - Verify traffic flows correctly through the Gateway 51 | - Check Gateway and HTTPRoute status: `kubectl get gateway,httproute -n ` 52 | 53 | 4. **Rollback if needed**: 54 | - Simply re-enable Ingress and disable Gateway in your values 55 | 56 | For detailed configuration options, see the [Gateway API Configuration section in the README](./README.md#gateway-api-configuration). 57 | 58 | ### Important Notes 59 | 60 | - Gateway API and Ingress cannot be enabled simultaneously 61 | - The `gateway.className` field is required when Gateway API is enabled 62 | - Gateway API requires the CRDs to be available in your cluster 63 | 64 | --- 65 | 66 | ## > 2025.8.21160848 67 | 68 | After version 2025.8.21160848, the chart automatically handles database migrations during upgrades using a pre-upgrade hook when in multi-server mode. 69 | 70 | See the README.md file for more details. 71 | 72 | ## > 2025.7.31204438 73 | 74 | After version 2025.7.31204438, we have migrated the `postgresql` image from the existing `bitnami` repo image to the `bitnamilegacy` repo image. 75 | This change should not have any breaking change implications unless there is a need to whitelist that new docker registry. 76 | The change is required per https://github.com/bitnami/charts/issues/35164. 77 | 78 | ## > 2025.3.7033449 79 | 80 | After version 2025.3.7033449, there have been several breaking changes to the `prefect-server` chart: 81 | - The `prefectApiUrl` and `prefectApiHost` values have been removed in favor of the single `prefectUiApiUrl` value. 82 | - `.Values.server.uiConfig.prefectUiUrl` has been removed. 83 | - `.Values.server.uiConfig.prefectUiEnabled` has been removed. 84 | 85 | ### Adjusting your configuration 86 | 87 | #### API URLs 88 | 89 | - `.Values.global.prefect.prefectApiUrl` => `.Values.server.uiConfig.prefectUiApiUrl` 90 | - `.Values.global.prefect.prefectApiHost` => `.Values.server.uiConfig.prefectUiApiUrl` 91 | 92 | Note: If you were using the default value for `prefectApiUrl` (i.e. `http://localhost:4200/api`) you do not need to make any changes, as the default value for `prefectUiApiUrl` is the same. 93 | 94 | #### UI URL 95 | 96 | `.Values.server.uiConfig.prefectUiUrl` has been removed altogether. This value was used solely for the purposes of printing out the UI URL during the installation process. It will now infer the UI URL from the `prefectUiApiUrl` value. 97 | 98 | #### Disabling the UI 99 | 100 | If you would like to disable the UI, you can pass this configuration via the `env` key. 101 | 102 | ```yaml 103 | server: 104 | env: 105 | - name: PREFECT_UI_ENABLED 106 | value: 'false' 107 | ``` 108 | 109 | --- 110 | 111 | ## > 2025.1.23213604 112 | 113 | After version `2025.1.23213604`, the `prefect-server` chart [introduces the option to run background services as a separate deployment](https://github.com/PrefectHQ/prefect-helm/pull/425). Due to the numerous shared values between the `server` and `background-services` deployments, the `values.yaml` file has been consolidated in the following ways: 114 | 115 | ### Introduction of `global.prefect` key in `values.yaml` 116 | 117 | `.Values.global.prefect` will contain shared configurations, many of which used to live under `.Values.server`, specifically: 118 | 119 | - `.Values.server.image` => `.Values.global.prefect.image` 120 | - `.Values.server.prefectApiUrl` => `.Values.global.prefect.prefectApiUrl` 121 | - `.Values.server.prefectApiHost` => `.Values.global.prefect.prefectApiHost` 122 | 123 | **Before** 124 | 125 | ```yaml 126 | server: 127 | image: 128 | repository: prefecthq/prefect 129 | prefectTag: 3-latest 130 | pullPolicy: IfNotPresent 131 | pullSecrets: [] 132 | prefectApiUrl: http://localhost:4200/api 133 | prefectApiHost: 0.0.0.0 134 | ``` 135 | 136 | **After** 137 | 138 | ```yaml 139 | global: 140 | prefect: 141 | image: 142 | repository: prefecthq/prefect 143 | prefectTag: 3-latest 144 | pullPolicy: IfNotPresent 145 | pullSecrets: [] 146 | prefectApiUrl: http://localhost:4200/api 147 | prefectApiHost: 0.0.0.0 148 | ``` 149 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/README.md: -------------------------------------------------------------------------------- 1 | # prometheus-prefect-exporter 2 | 3 | ## Overview 4 | 5 | This chart deploys a [Prometheus Exporter](https://github.com/PrefectHQ/prometheus-prefect-exporter) for Prefect Server, providing relevant metrics from your deployed Prefect Server instance. 6 | Shoutout to @ialejandro for the original work on this chart! 7 | 8 | ## Installing the Chart 9 | 10 | ### Prerequisites 11 | 12 | 1. Add the Prefect Helm repository to your Helm client: 13 | 14 | ```bash 15 | helm repo add prefect https://prefecthq.github.io/prefect-helm 16 | helm repo update 17 | ``` 18 | 19 | 2. Deploy a Prefect Server instance using the [Prefect Server Helm chart](https://github.com/PrefectHQ/prefect-helm/tree/main/charts/prefect-server) 20 | 21 | ### Install the Prefect Exporter chart 22 | 23 | 1. Configure the Prefect exporter values as needed 24 | Create a `values.yaml` file to customize the Prometheus Prefect Exporter configuration. 25 | 26 | 2. Install the chart 27 | ```bash 28 | helm install prometheus-prefect-exporter prefect/prometheus-prefect-exporter --namespace= -f values.yaml 29 | ``` 30 | 31 | 3. Verify the deployment 32 | 33 | Check the status of your Prometheus Prefect Exporter deployment: 34 | 35 | ```bash 36 | kubectl get pods -n prefect 37 | 38 | NAME READY STATUS RESTARTS AGE 39 | prometheus-prefect-exporter-76vxqnq 1/1 Running 0 25m 40 | ``` 41 | 42 | You should see the Prometheus Prefect Exporter pod running 43 | 44 | ## Additional Exporter Configurations 45 | 46 | ### Basic Auth 47 | 48 | Prefect documentation on [basic auth](https://docs.prefect.io/v3/develop/settings-and-profiles#security-settings) 49 | 50 | Self-hosted Prefect servers can be equipped with a Basic Authentication string for an administrator/password combination. Assuming you are running a self-hosted server with basic auth enabled, you can authenticate your exporter with the same credentials. 51 | 52 | The format of the auth string is `admin:` (no brackets). 53 | 54 | ```yaml 55 | basicAuth: 56 | enabled: true 57 | authString: "admin:pass" 58 | ``` 59 | 60 | Alternatively, you can provide an existing Kubernetes Secret containing the auth string credentials. The secret must contain a key `auth-string` with the value of the auth string. 61 | 62 | ```sh 63 | kubectl create secret generic prefect-basic-auth --from-literal=auth-string='admin:my-password' 64 | ``` 65 | 66 | ```yaml 67 | basicAuth: 68 | enabled: true 69 | existingSecret: prefect-basic-auth 70 | ``` 71 | 72 | ## Maintainers 73 | 74 | | Name | Email | Url | 75 | | ---- | ------ | --- | 76 | | jamiezieziula | | | 77 | | jimid27 | | | 78 | | parkedwards | | | 79 | | mitchnielsen | | | 80 | 81 | ## Requirements 82 | 83 | | Repository | Name | Version | 84 | |------------|------|---------| 85 | | https://charts.bitnami.com/bitnami | common | 2.31.4 | 86 | 87 | ## Values 88 | 89 | | Key | Type | Default | Description | 90 | |-----|------|---------|-------------| 91 | | affinity | object | `{}` | Affinity for pod assignment | 92 | | autoscaling | object | `{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80}` | Autoscaling with CPU or memory utilization percentage | 93 | | basicAuth.authString | string | `"admin:pass"` | basic auth credentials in the format admin: (no brackets) | 94 | | basicAuth.enabled | bool | `false` | enable basic auth for the exporter, for an administrator/password combination. must be enabled on the server as well | 95 | | basicAuth.existingSecret | string | `""` | name of existing secret containing basic auth credentials. takes precedence over authString. must contain a key `auth-string` with the value of the auth string | 96 | | csrfAuth | bool | `false` | Enable CSRF authentication (Only set to true if Prefect Server has CSRF enabled) | 97 | | env | object | `{}` | Environment variables to configure application | 98 | | extraEnvVars | list | `[]` | array with extra environment variables to add to exporter deployment pods | 99 | | fullnameOverride | string | `""` | String to fully override common.names.fullname template | 100 | | image | object | `{"pullPolicy":"IfNotPresent","repository":"prefecthq/prometheus-prefect-exporter","tag":"1.1.0"}` | Image registry | 101 | | imagePullSecrets | list | `[]` | Global Docker registry secret names as an array | 102 | | ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"chart-example.local","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}],"tls":[]}` | Ingress configuration to expose app | 103 | | livenessProbe | bool | `false` | Enable livenessProbe | 104 | | nameOverride | string | `""` | String to partially override common.names.fullname template (will maintain the release name) | 105 | | nodeSelector | object | `{}` | Node labels for pod assignment | 106 | | pagination | object | `{"enabled":true,"limit":200}` | Pagination settings. If enabled, the exporter will paginate the API requests to Prefect Server which uses more resources. Remember to increase the resources for the exporter if enabled. | 107 | | podAnnotations | object | `{}` | Pod annotations | 108 | | podDisruptionBudget | object | `{}` | Limits the number of Pods of a replicated application that are down simultaneously from voluntary disruptions | 109 | | podSecurityContext | object | `{}` | To specify security settings for a Pod | 110 | | prefectApiUrl | string | `"http://prefect-server.prefect.svc.cluster.local:4200/api"` | Prefect API URL to connect to for metrics | 111 | | prometheusRule.additionalLabels | object | `{}` | | 112 | | prometheusRule.enabled | bool | `false` | | 113 | | prometheusRule.rules | list | `[]` | | 114 | | readinessProbe | bool | `false` | Enable readinessProbe | 115 | | replicaCount | int | `1` | Number of replicas | 116 | | resources | object | `{}` | The resources limits and requested | 117 | | revisionHistoryLimit | int | `10` | the number of old ReplicaSets to retain to allow rollback | 118 | | securityContext | object | `{}` | Defines privilege and access control settings for a Pod or Container | 119 | | service | object | `{"annotations":{},"port":80,"targetPort":8000,"type":"ClusterIP"}` | Kubernetes servide to expose Pod | 120 | | service.annotations | object | `{}` | additional custom annotations for exporter service | 121 | | service.port | int | `80` | Kubernetes Service port | 122 | | service.targetPort | int | `8000` | Pod expose port | 123 | | service.type | string | `"ClusterIP"` | Kubernetes Service type. Allowed values: NodePort, LoadBalancer or ClusterIP | 124 | | serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Enable creation of ServiceAccount | 125 | | serviceMonitor | object | `{"additionalLabels":{},"enabled":false,"interval":"30s","metricRelabelings":[],"relabelings":[],"scrapeTimeout":"10s"}` | Enable ServiceMonitor to get metrics ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitor | 126 | | serviceMonitor.enabled | bool | `false` | Enable or disable | 127 | | tolerations | list | `[]` | Tolerations for pod assignment | 128 | 129 | ---------------------------------------------- 130 | Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2) 131 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/background-services/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.backgroundServices.runAsSeparateDeployment }} 2 | apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} 3 | kind: Deployment 4 | metadata: 5 | name: {{ template "common.names.fullname" . }}-background-services 6 | namespace: {{ include "common.names.namespace" . | quote }} 7 | labels: {{- include "common.labels.standard" . | nindent 4 }} 8 | app.kubernetes.io/component: background-services 9 | prefect-version: {{ .Chart.AppVersion }} 10 | {{- if .Values.commonLabels }} 11 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 12 | {{- end }} 13 | {{- if .Values.commonAnnotations }} 14 | annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 15 | {{- end }} 16 | spec: 17 | revisionHistoryLimit: {{ .Values.backgroundServices.revisionHistoryLimit }} 18 | replicas: {{ .Values.backgroundServices.replicaCount }} 19 | selector: 20 | matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} 21 | app.kubernetes.io/component: background-services 22 | template: 23 | metadata: 24 | {{- if .Values.backgroundServices.podAnnotations }} 25 | annotations: {{- include "common.tplvalues.render" (dict "value" .Values.backgroundServices.podAnnotations "context" $) | nindent 8 }} 26 | {{- end }} 27 | labels: {{- include "common.labels.standard" . | nindent 8 }} 28 | app.kubernetes.io/component: background-services 29 | prefect-version: {{ .Chart.AppVersion }} 30 | {{- if .Values.backgroundServices.podLabels }} 31 | {{- include "common.tplvalues.render" (dict "value" .Values.backgroundServices.podLabels "context" $) | nindent 8 }} 32 | {{- end }} 33 | spec: 34 | {{- if .Values.global.prefect.image.pullSecrets }} 35 | imagePullSecrets: 36 | {{- range .Values.global.prefect.image.pullSecrets }} 37 | - name: {{ . }} 38 | {{- end }} 39 | {{- end }} 40 | serviceAccountName: {{ if .Values.backgroundServices.serviceAccount.create }}{{ template "backgroundServices.serviceAccountName" . }}{{ else if .Values.backgroundServices.serviceAccount.name }}{{ .Values.backgroundServices.serviceAccount.name }}{{ else }}{{ template "server.serviceAccountName" . }}{{ end }} 41 | {{- if .Values.backgroundServices.affinity }} 42 | affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.backgroundServices.affinity "context" $) | nindent 8 }} 43 | {{- end }} 44 | {{- if .Values.backgroundServices.nodeSelector }} 45 | nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.backgroundServices.nodeSelector "context" $) | nindent 8 }} 46 | {{- end }} 47 | {{- if .Values.backgroundServices.tolerations }} 48 | tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.backgroundServices.tolerations "context" .) | nindent 8 }} 49 | {{- end }} 50 | {{- if .Values.backgroundServices.podSecurityContext }} 51 | securityContext: {{- .Values.backgroundServices.podSecurityContext | toYaml | nindent 8 }} 52 | {{- end }} 53 | {{- if .Values.backgroundServices.priorityClassName }} 54 | priorityClassName: {{ .Values.backgroundServices.priorityClassName }} 55 | {{- end }} 56 | containers: 57 | - name: prefect-background-services 58 | image: "{{ .Values.global.prefect.image.repository }}:{{ .Values.global.prefect.image.prefectTag }}" 59 | imagePullPolicy: {{ .Values.global.prefect.image.pullPolicy }} 60 | command: 61 | {{- if .Values.backgroundServices.command }} 62 | {{- .Values.backgroundServices.command | toYaml | nindent 12 }} 63 | {{- else }} 64 | - /usr/bin/tini 65 | - -g 66 | - -- 67 | - /opt/prefect/entrypoint.sh 68 | {{- end }} 69 | args: 70 | {{- if .Values.backgroundServices.args }} 71 | {{- .Values.backgroundServices.args | toYaml | nindent 12 }} 72 | {{- else }} 73 | - prefect 74 | - server 75 | - services 76 | - start 77 | {{- end }} 78 | workingDir: /home/prefect 79 | env: 80 | - name: HOME 81 | value: /home/prefect 82 | - name: PREFECT_DEBUG_MODE 83 | value: {{ .Values.backgroundServices.debug | quote }} 84 | - name: PREFECT_LOGGING_SERVER_LEVEL 85 | value: {{ .Values.backgroundServices.loggingLevel | quote }} 86 | - name: PREFECT_UI_ENABLED 87 | value: 'false' 88 | - name: PREFECT_API_DATABASE_CONNECTION_URL 89 | {{- if .Values.sqlite.enabled }} 90 | value: "sqlite+aiosqlite:////data/prefect.db" 91 | {{- else }} 92 | valueFrom: 93 | secretKeyRef: 94 | name: {{ include "server.postgres-string-secret-name" . }} 95 | key: connection-string 96 | {{- end -}} 97 | {{- if .Values.backgroundServices.runAsSeparateDeployment }} 98 | {{- include "backgroundServices.envVars" . | nindent 12 }} 99 | {{- end }} 100 | {{- if .Values.global.prefect.env }} 101 | {{- include "common.tplvalues.render" (dict "value" .Values.global.prefect.env "context" $) | nindent 12 }} 102 | {{- end }} 103 | {{- if .Values.backgroundServices.env }} 104 | {{- include "common.tplvalues.render" (dict "value" .Values.backgroundServices.env "context" $) | nindent 12 }} 105 | {{- end }} 106 | {{- if or (.Values.backgroundServices.extraEnvVarsCM) (.Values.backgroundServices.extraEnvVarsSecret) }} 107 | envFrom: 108 | {{- if .Values.backgroundServices.extraEnvVarsCM }} 109 | - configMapRef: 110 | name: {{ include "common.tplvalues.render" (dict "value" .Values.backgroundServices.extraEnvVarsCM "context" $) }} 111 | {{- end }} 112 | {{- if .Values.backgroundServices.extraEnvVarsSecret }} 113 | - secretRef: 114 | name: {{ include "common.tplvalues.render" (dict "value" .Values.backgroundServices.extraEnvVarsSecret "context" $) }} 115 | {{- end }} 116 | {{- end }} 117 | {{- if .Values.backgroundServices.resources }} 118 | resources: {{- toYaml .Values.backgroundServices.resources | nindent 12 }} 119 | {{- end }} 120 | {{- with .Values.backgroundServices.containerSecurityContext }} 121 | securityContext: {{- toYaml . | nindent 12 }} 122 | {{- end }} 123 | volumeMounts: 124 | - mountPath: /home/prefect 125 | name: scratch 126 | subPathExpr: home 127 | - mountPath: /tmp 128 | name: scratch 129 | subPathExpr: tmp 130 | {{- if .Values.sqlite.enabled }} 131 | - mountPath: /data 132 | name: sqlite-storage 133 | {{- end }} 134 | {{- if .Values.backgroundServices.extraVolumeMounts }} 135 | {{- include "common.tplvalues.render" (dict "value" .Values.backgroundServices.extraVolumeMounts "context" $) | nindent 12 }} 136 | {{- end }} 137 | {{- if .Values.backgroundServices.extraContainers }} 138 | {{- include "common.tplvalues.render" (dict "value" .Values.backgroundServices.extraContainers "context" $) | nindent 8 }} 139 | {{- end }} 140 | volumes: 141 | - name: scratch 142 | emptyDir: {} 143 | {{- if .Values.sqlite.enabled }} 144 | - name: sqlite-storage 145 | persistentVolumeClaim: 146 | claimName: {{ template "common.names.fullname" . }}-sqlite 147 | {{- end }} 148 | {{- if .Values.backgroundServices.extraVolumes }} 149 | {{- include "common.tplvalues.render" (dict "value" .Values.backgroundServices.extraVolumes "context" $) | nindent 8 }} 150 | {{- end }} 151 | {{- end }} -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/values.yaml: -------------------------------------------------------------------------------- 1 | # -- the number of old ReplicaSets to retain to allow rollback 2 | revisionHistoryLimit: 10 3 | 4 | # -- Number of replicas 5 | replicaCount: 1 6 | 7 | # -- Image registry 8 | image: 9 | repository: prefecthq/prometheus-prefect-exporter 10 | pullPolicy: IfNotPresent 11 | # Overrides the image tag whose default is the chart appVersion. 12 | tag: 1.1.0 13 | 14 | # -- String to partially override common.names.fullname template (will maintain the release name) 15 | nameOverride: "" 16 | 17 | # -- String to fully override common.names.fullname template 18 | fullnameOverride: "" 19 | 20 | # -- Global Docker registry secret names as an array 21 | imagePullSecrets: [] 22 | 23 | # -- Enable creation of ServiceAccount 24 | serviceAccount: 25 | # Specifies whether a service account should be created 26 | create: true 27 | # Annotations to add to the service account 28 | annotations: {} 29 | # The name of the service account to use. 30 | # If not set and create is true, a name is generated using the fullname template 31 | name: "" 32 | 33 | # -- Prefect API URL to connect to for metrics 34 | prefectApiUrl: http://prefect-server.prefect.svc.cluster.local:4200/api 35 | 36 | # -- Enable CSRF authentication (Only set to true if Prefect Server has CSRF enabled) 37 | csrfAuth: false 38 | 39 | # ref: https://docs.prefect.io/v3/develop/settings-and-profiles#security-settings 40 | basicAuth: 41 | # -- enable basic auth for the exporter, for an administrator/password combination. must be enabled on the server as well 42 | enabled: false 43 | # -- basic auth credentials in the format admin: (no brackets) 44 | authString: "admin:pass" 45 | # -- name of existing secret containing basic auth credentials. takes precedence over authString. must contain a key `auth-string` with the value of the auth string 46 | existingSecret: "" 47 | 48 | # -- Pagination settings. If enabled, the exporter will paginate the API requests to Prefect Server which uses more resources. Remember to increase the resources for the exporter if enabled. 49 | pagination: 50 | enabled: true 51 | limit: 200 52 | # -- Environment variables to configure application 53 | env: {} 54 | # Plain vars 55 | # foo: bar 56 | # my_env: my_value 57 | 58 | # -- array with extra environment variables to add to exporter deployment pods 59 | extraEnvVars: [] 60 | 61 | # -- Limits the number of Pods of a replicated application that are down simultaneously from voluntary disruptions 62 | podDisruptionBudget: {} 63 | # maxUnavailable: 0 64 | 65 | # -- Pod annotations 66 | podAnnotations: {} 67 | 68 | # -- To specify security settings for a Pod 69 | podSecurityContext: {} 70 | # fsGroup: 2000 71 | 72 | # -- Defines privilege and access control settings for a Pod or Container 73 | securityContext: {} 74 | # capabilities: 75 | # drop: 76 | # - ALL 77 | # readOnlyRootFilesystem: true 78 | # runAsNonRoot: true 79 | # runAsUser: 1000 80 | 81 | # -- Kubernetes servide to expose Pod 82 | service: 83 | # -- Kubernetes Service type. Allowed values: NodePort, LoadBalancer or ClusterIP 84 | type: ClusterIP 85 | # -- Kubernetes Service port 86 | port: 80 87 | # -- Pod expose port 88 | targetPort: 8000 89 | # -- additional custom annotations for exporter service 90 | annotations: {} 91 | 92 | # -- Enable ServiceMonitor to get metrics 93 | # ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitor 94 | serviceMonitor: 95 | # -- Enable or disable 96 | enabled: false 97 | additionalLabels: {} 98 | interval: 30s 99 | scrapeTimeout: 10s 100 | metricRelabelings: [] 101 | relabelings: [] 102 | 103 | ## -- Custom PrometheusRules to be defined 104 | # ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions 105 | prometheusRule: 106 | enabled: false 107 | additionalLabels: {} 108 | rules: [] 109 | # - alert: PrefectServerDown 110 | # expr: sum by (pod, namespace) (kube_pod_info{namespace="prefect", pod=~"prefect-server.*"}) == 0 111 | # for: 0m 112 | # labels: 113 | # severity: critical 114 | # annotations: 115 | # summary: Prefect server is down 116 | # description: There are no Prefect server pods in the "prefect" namespace 117 | 118 | # - alert: PrefectDeploymentsAllPaused 119 | # expr: (count by (namespace) (prefect_info_deployment) == bool count by (namespace) (prefect_info_deployment{is_schedule_active="False"})) == 1 120 | # for: 0m 121 | # labels: 122 | # severity: warning 123 | # annotations: 124 | # summary: All deployments are paused 125 | # description: "All deployments are paused\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 126 | 127 | # - alert: PrefectWorkPoolNotAllow 128 | # expr: prefect_work_pools_total == 0 129 | # for: 0m 130 | # labels: 131 | # severity: critical 132 | # annotations: 133 | # summary: Worker pool not allowed 134 | # description: "Worker pool not allowed\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 135 | 136 | # - alert: PrefectWorkPoolsAllPaused 137 | # expr: (count by (namespace) (prefect_work_pools_total) == bool count by (namespace) (prefect_info_work_pools{is_paused="True"})) == 1 138 | # for: 0m 139 | # labels: 140 | # severity: warning 141 | # annotations: 142 | # summary: All work pools are paused 143 | # description: "All work pools are paused\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 144 | 145 | # - alert: PrefectWorkQueueNotAllow 146 | # expr: prefect_work_queues_total == 0 147 | # for: 0m 148 | # labels: 149 | # severity: critical 150 | # annotations: 151 | # summary: Worker queue not allowed 152 | # description: "Worker queue not allowed\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 153 | 154 | # - alert: PrefectWorkQueuesAllPaused 155 | # expr: (count by (namespace) (prefect_work_queues_total) == bool count by (namespace) (prefect_info_work_queues{is_paused="True"})) == 1 156 | # for: 0m 157 | # labels: 158 | # severity: warning 159 | # annotations: 160 | # summary: All work queues are paused 161 | # description: "All work queues are paused\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 162 | 163 | # - alert: PrefectFlowRunCrashedOrFailed 164 | # expr: group by (flow_name, flow_run_name, namespace) (count_over_time(prefect_info_flow_runs{state_name=~"Failed|Crashed"}[1m])) 165 | # for: 0m 166 | # labels: 167 | # severity: critical 168 | # annotations: 169 | # summary: Flow Run {{ $labels.flow_name }} {{ $labels.state_name }} (Flow {{ $labels.flow_name }}) 170 | # description: "Flow Run failed or crashed\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 171 | 172 | 173 | # -- Enable livenessProbe 174 | livenessProbe: false 175 | # -- Enable readinessProbe 176 | readinessProbe: false 177 | # -- Ingress configuration to expose app 178 | ingress: 179 | enabled: false 180 | className: "" 181 | annotations: {} 182 | # kubernetes.io/ingress.class: nginx 183 | # kubernetes.io/tls-acme: "true" 184 | hosts: 185 | - host: chart-example.local 186 | paths: 187 | - path: / 188 | pathType: ImplementationSpecific 189 | tls: [] 190 | # - secretName: chart-example-tls 191 | # hosts: 192 | # - chart-example.local 193 | 194 | # -- The resources limits and requested 195 | resources: {} 196 | # We usually recommend not to specify default resources and to leave this as a conscious 197 | # choice for the user. This also increases chances charts run on environments with little 198 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 199 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 200 | # limits: 201 | # cpu: 100m 202 | # memory: 128Mi 203 | # requests: 204 | # cpu: 100m 205 | # memory: 128Mi 206 | 207 | # -- Autoscaling with CPU or memory utilization percentage 208 | autoscaling: 209 | enabled: false 210 | minReplicas: 1 211 | maxReplicas: 100 212 | targetCPUUtilizationPercentage: 80 213 | # targetMemoryUtilizationPercentage: 80 214 | 215 | # -- Node labels for pod assignment 216 | nodeSelector: {} 217 | 218 | # -- Tolerations for pod assignment 219 | tolerations: [] 220 | 221 | # -- Affinity for pod assignment 222 | affinity: {} 223 | -------------------------------------------------------------------------------- /charts/prefect-server/tests/pre_upgrade_hook_test.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/helm-unittest-schema.json 2 | suite: Pre-upgrade hook tests 3 | release: 4 | name: pre-upgrade-hook-test 5 | namespace: prefect 6 | 7 | set: 8 | global: 9 | prefect: 10 | image: 11 | prefectTag: 3.1.13-python3.11-kubernetes 12 | backgroundServices: 13 | runAsSeparateDeployment: true 14 | redis: 15 | enabled: true 16 | 17 | tests: 18 | - it: Should create pre-upgrade hook job for PostgreSQL deployments 19 | set: 20 | postgresql: 21 | enabled: true 22 | auth: 23 | password: testpass 24 | sqlite: 25 | enabled: false 26 | asserts: 27 | - template: pre-upgrade-hook.yaml 28 | containsDocument: 29 | apiVersion: batch/v1 30 | kind: Job 31 | metadata: 32 | name: pre-upgrade-hook-test-pre-upgrade 33 | annotations: 34 | helm.sh/hook: pre-upgrade 35 | helm.sh/hook-weight: "-5" 36 | helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded 37 | spec: 38 | template: 39 | spec: 40 | restartPolicy: Never 41 | containers: 42 | - name: pre-upgrade-migration 43 | command: 44 | - /bin/sh 45 | - -c 46 | - | 47 | set -eo pipefail 48 | echo "Starting database migration..." 49 | prefect server database upgrade -y 50 | env: 51 | - name: PREFECT_API_DATABASE_CONNECTION_URL 52 | valueFrom: 53 | secretKeyRef: 54 | name: pre-upgrade-hook-test-postgresql-connection 55 | key: connection-string 56 | 57 | - it: Should not create pre-upgrade hook job for SQLite deployments 58 | set: 59 | postgresql: 60 | enabled: false 61 | sqlite: 62 | enabled: true 63 | asserts: 64 | - template: pre-upgrade-hook.yaml 65 | not: true 66 | containsDocument: 67 | apiVersion: batch/v1 68 | kind: Job 69 | 70 | - it: Should not create pre-upgrade hook job when migrations are disabled 71 | set: 72 | migrations: 73 | enabled: false 74 | asserts: 75 | - template: pre-upgrade-hook.yaml 76 | not: true 77 | containsDocument: 78 | apiVersion: batch/v1 79 | kind: Job 80 | 81 | - it: Should use correct service account for pre-upgrade hook 82 | asserts: 83 | - template: pre-upgrade-hook.yaml 84 | equal: 85 | path: .spec.template.spec.serviceAccountName 86 | value: prefect-server 87 | 88 | - it: Should include global environment variables in pre-upgrade hook 89 | set: 90 | global: 91 | prefect: 92 | env: 93 | - name: TEST_VAR 94 | value: test_value 95 | asserts: 96 | - template: pre-upgrade-hook.yaml 97 | contains: 98 | path: .spec.template.spec.containers[0].env 99 | content: 100 | name: TEST_VAR 101 | value: test_value 102 | 103 | - it: Should include server environment variables in pre-upgrade hook 104 | set: 105 | server: 106 | env: 107 | - name: SERVER_VAR 108 | value: server_value 109 | asserts: 110 | - template: pre-upgrade-hook.yaml 111 | contains: 112 | path: .spec.template.spec.containers[0].env 113 | content: 114 | name: SERVER_VAR 115 | value: server_value 116 | 117 | - it: Should set correct resource limits for pre-upgrade hook 118 | asserts: 119 | - template: pre-upgrade-hook.yaml 120 | equal: 121 | path: .spec.template.spec.containers[0].resources 122 | value: 123 | requests: 124 | cpu: 100m 125 | memory: 128Mi 126 | limits: 127 | cpu: 500m 128 | memory: 256Mi 129 | 130 | - it: Should set correct security context for pre-upgrade hook 131 | asserts: 132 | - template: pre-upgrade-hook.yaml 133 | equal: 134 | path: .spec.template.spec.containers[0].securityContext 135 | value: 136 | runAsUser: 1001 137 | runAsNonRoot: true 138 | readOnlyRootFilesystem: true 139 | allowPrivilegeEscalation: false 140 | capabilities: {} 141 | 142 | - it: Should not create pre-upgrade hook job when migrations are completely disabled 143 | set: 144 | migrations: 145 | enabled: false 146 | asserts: 147 | - template: pre-upgrade-hook.yaml 148 | not: true 149 | containsDocument: 150 | apiVersion: batch/v1 151 | kind: Job 152 | 153 | - it: Should not create pre-upgrade hook job when backgroundServices.runAsSeparateDeployment is false 154 | set: 155 | backgroundServices: 156 | runAsSeparateDeployment: false 157 | asserts: 158 | - template: pre-upgrade-hook.yaml 159 | not: true 160 | containsDocument: 161 | apiVersion: batch/v1 162 | kind: Job 163 | 164 | - it: Should use custom migration configuration when provided 165 | set: 166 | migrations: 167 | command: "custom-migration-command" 168 | entrypoint: ["/bin/bash", "-c"] 169 | timeoutSeconds: 600 170 | backoffLimit: 5 171 | resources: 172 | requests: 173 | cpu: 200m 174 | memory: 256Mi 175 | limits: 176 | cpu: 1000m 177 | memory: 512Mi 178 | securityContext: 179 | runAsUser: 2000 180 | runAsNonRoot: true 181 | readOnlyRootFilesystem: false 182 | env: 183 | - name: CUSTOM_MIGRATION_VAR 184 | value: custom_value 185 | asserts: 186 | - template: pre-upgrade-hook.yaml 187 | equal: 188 | path: .spec.activeDeadlineSeconds 189 | value: 600 190 | - template: pre-upgrade-hook.yaml 191 | equal: 192 | path: .spec.backoffLimit 193 | value: 5 194 | - template: pre-upgrade-hook.yaml 195 | equal: 196 | path: .spec.template.spec.containers[0].command 197 | value: 198 | - /bin/bash 199 | - -c 200 | - template: pre-upgrade-hook.yaml 201 | contains: 202 | path: .spec.template.spec.containers[0].args 203 | content: | 204 | set -eo pipefail 205 | echo "Starting database migration..." 206 | custom-migration-command 207 | - template: pre-upgrade-hook.yaml 208 | contains: 209 | path: .spec.template.spec.containers[0].env 210 | content: 211 | name: CUSTOM_MIGRATION_VAR 212 | value: custom_value 213 | - template: pre-upgrade-hook.yaml 214 | equal: 215 | path: .spec.template.spec.containers[0].resources.requests.cpu 216 | value: 200m 217 | - template: pre-upgrade-hook.yaml 218 | equal: 219 | path: .spec.template.spec.containers[0].securityContext.runAsUser 220 | value: 2000 221 | 222 | - it: Should use correct imagePullSecrets format in pre-upgrade hook 223 | set: 224 | global: 225 | prefect: 226 | image: 227 | pullSecrets: 228 | - my-secret-1 229 | - my-secret-2 230 | asserts: 231 | - template: pre-upgrade-hook.yaml 232 | equal: 233 | path: .spec.template.spec.imagePullSecrets[0].name 234 | value: my-secret-1 235 | - template: pre-upgrade-hook.yaml 236 | equal: 237 | path: .spec.template.spec.imagePullSecrets[1].name 238 | value: my-secret-2 239 | 240 | - it: Should set affinity 241 | set: 242 | migrations: 243 | affinity: 244 | nodeAffinity: 245 | requiredDuringSchedulingIgnoredDuringExecution: 246 | nodeSelectorTerms: 247 | - matchExpressions: 248 | - key: kubernetes.io/e2e-az-name 249 | operator: In 250 | values: 251 | - e2e-az1 252 | - e2e-az2 253 | asserts: 254 | - template: pre-upgrade-hook.yaml 255 | equal: 256 | path: .spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key 257 | value: kubernetes.io/e2e-az-name 258 | 259 | - it: Should set node selector 260 | set: 261 | migrations: 262 | nodeSelector: 263 | disktype: ssd 264 | asserts: 265 | - template: pre-upgrade-hook.yaml 266 | equal: 267 | path: .spec.template.spec.nodeSelector.disktype 268 | value: ssd 269 | 270 | - it: Should set tolerations 271 | set: 272 | migrations: 273 | tolerations: 274 | - key: "key1" 275 | operator: "Equal" 276 | value: "value1" 277 | effect: "NoSchedule" 278 | asserts: 279 | - template: pre-upgrade-hook.yaml 280 | equal: 281 | path: .spec.template.spec.tolerations[0].key 282 | value: key1 283 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/tests/exporter_test.yaml: -------------------------------------------------------------------------------- 1 | suite: Prometheus Prefect Exporter configuration 2 | release: 3 | name: test 4 | namespace: default 5 | 6 | tests: 7 | - it: Should not set basic auth by default 8 | asserts: 9 | - template: deployment.yaml 10 | notContains: 11 | path: .spec.template.spec.containers[0].env 12 | content: 13 | name: PREFECT_API_AUTH_STRING 14 | 15 | - it: Should set basic auth from authString 16 | set: 17 | basicAuth: 18 | enabled: true 19 | authString: "admin:mypassword" 20 | asserts: 21 | - template: deployment.yaml 22 | equal: 23 | path: .spec.template.spec.containers[0].env[?(@.name == "PREFECT_API_AUTH_STRING")].value 24 | value: "admin:mypassword" 25 | 26 | - it: Should set basic auth from existing secret 27 | set: 28 | basicAuth: 29 | enabled: true 30 | existingSecret: "my-auth-secret" 31 | asserts: 32 | - template: deployment.yaml 33 | contains: 34 | path: .spec.template.spec.containers[0].env 35 | content: 36 | name: PREFECT_API_AUTH_STRING 37 | valueFrom: 38 | secretKeyRef: 39 | name: my-auth-secret 40 | key: auth-string 41 | 42 | - it: Should set the correct image and tag 43 | asserts: 44 | - template: deployment.yaml 45 | equal: 46 | path: .spec.template.spec.containers[0].image 47 | value: prefecthq/prometheus-prefect-exporter:1.1.0 48 | 49 | - it: Should set custom image and tag 50 | set: 51 | image: 52 | repository: custom/exporter 53 | tag: v1.0.0 54 | asserts: 55 | - template: deployment.yaml 56 | equal: 57 | path: .spec.template.spec.containers[0].image 58 | value: custom/exporter:v1.0.0 59 | 60 | - it: Should set the correct pull policy 61 | asserts: 62 | - template: deployment.yaml 63 | equal: 64 | path: .spec.template.spec.containers[0].imagePullPolicy 65 | value: IfNotPresent 66 | 67 | - it: Should set custom pull policy 68 | set: 69 | image: 70 | pullPolicy: Always 71 | asserts: 72 | - template: deployment.yaml 73 | equal: 74 | path: .spec.template.spec.containers[0].imagePullPolicy 75 | value: Always 76 | 77 | - it: Should set image pull secrets 78 | set: 79 | imagePullSecrets: 80 | - name: my-secret 81 | asserts: 82 | - template: deployment.yaml 83 | equal: 84 | path: .spec.template.spec.imagePullSecrets[0].name 85 | value: my-secret 86 | 87 | - it: Should set the correct revision history limit 88 | asserts: 89 | - template: deployment.yaml 90 | equal: 91 | path: .spec.revisionHistoryLimit 92 | value: 10 93 | 94 | - it: Should set a custom revision history limit 95 | set: 96 | revisionHistoryLimit: 5 97 | asserts: 98 | - template: deployment.yaml 99 | equal: 100 | path: .spec.revisionHistoryLimit 101 | value: 5 102 | 103 | - it: Should set the correct replica count 104 | asserts: 105 | - template: deployment.yaml 106 | equal: 107 | path: .spec.replicas 108 | value: 1 109 | 110 | - it: Should set a custom replica count 111 | set: 112 | replicaCount: 3 113 | asserts: 114 | - template: deployment.yaml 115 | equal: 116 | path: .spec.replicas 117 | value: 3 118 | 119 | - it: Should set the correct Prefect API URL 120 | set: 121 | prefectApiUrl: "http://prefect-server:4200/api" 122 | asserts: 123 | - template: deployment.yaml 124 | equal: 125 | path: .spec.template.spec.containers[0].env[?(@.name == "PREFECT_API_URL")].value 126 | value: "http://prefect-server:4200/api" 127 | 128 | - it: Should enable CSRF authentication 129 | set: 130 | csrfAuth: true 131 | asserts: 132 | - template: deployment.yaml 133 | equal: 134 | path: .spec.template.spec.containers[0].env[?(@.name == "PREFECT_CSRF_ENABLED")].value 135 | value: "True" 136 | 137 | - it: Should set custom environment variables 138 | set: 139 | env: 140 | CUSTOM_ENV: custom_value 141 | asserts: 142 | - template: deployment.yaml 143 | equal: 144 | path: .spec.template.spec.containers[0].env[?(@.name == "CUSTOM_ENV")].value 145 | value: custom_value 146 | 147 | - it: Should set advanced custom environment variables 148 | set: 149 | extraEnvVars: 150 | - name: CUSTOM_ENV 151 | valueFrom: 152 | secretKeyRef: 153 | name: my-secret 154 | key: my-secret-key 155 | asserts: 156 | - template: deployment.yaml 157 | equal: 158 | path: .spec.template.spec.containers[0].env[?(@.name == "CUSTOM_ENV")].valueFrom.secretKeyRef.name 159 | value: my-secret 160 | - template: deployment.yaml 161 | equal: 162 | path: .spec.template.spec.containers[0].env[?(@.name == "CUSTOM_ENV")].valueFrom.secretKeyRef.key 163 | value: my-secret-key 164 | 165 | - it: Should set the correct pod security context 166 | set: 167 | podSecurityContext: 168 | fsGroup: 2000 169 | asserts: 170 | - template: deployment.yaml 171 | equal: 172 | path: .spec.template.spec.securityContext.fsGroup 173 | value: 2000 174 | 175 | - it: Should set the correct container security context 176 | set: 177 | securityContext: 178 | runAsNonRoot: true 179 | runAsUser: 1000 180 | asserts: 181 | - template: deployment.yaml 182 | equal: 183 | path: .spec.template.spec.containers[0].securityContext.runAsNonRoot 184 | value: true 185 | - template: deployment.yaml 186 | equal: 187 | path: .spec.template.spec.containers[0].securityContext.runAsUser 188 | value: 1000 189 | 190 | - it: Should set pod annotations 191 | set: 192 | podAnnotations: 193 | custom-annotation: custom-value 194 | asserts: 195 | - template: deployment.yaml 196 | equal: 197 | path: .spec.template.metadata.annotations.custom-annotation 198 | value: custom-value 199 | 200 | - it: Should set the correct service configuration 201 | asserts: 202 | - template: service.yaml 203 | equal: 204 | path: .spec.type 205 | value: ClusterIP 206 | - template: service.yaml 207 | equal: 208 | path: .spec.ports[0].port 209 | value: 80 210 | - template: service.yaml 211 | equal: 212 | path: .spec.ports[0].targetPort 213 | value: 8000 214 | 215 | - it: Should set custom service configuration 216 | set: 217 | service: 218 | type: LoadBalancer 219 | port: 8080 220 | targetPort: 30080 221 | annotations: 222 | my-annotation: hello-world 223 | asserts: 224 | - template: service.yaml 225 | equal: 226 | path: .spec.type 227 | value: LoadBalancer 228 | - template: service.yaml 229 | equal: 230 | path: .spec.ports[0].port 231 | value: 8080 232 | - template: service.yaml 233 | equal: 234 | path: .spec.ports[0].targetPort 235 | value: 30080 236 | - template: service.yaml 237 | equal: 238 | path: .metadata.annotations.my-annotation 239 | value: hello-world 240 | 241 | - it: Should set the correct container arguments 242 | set: 243 | containerArgs: 244 | - --log-level=debug 245 | asserts: 246 | - template: deployment.yaml 247 | equal: 248 | path: .spec.template.spec.containers[0].args[0] 249 | value: "--log-level=debug" 250 | 251 | - it: Should enable liveness probe 252 | set: 253 | livenessProbe: true 254 | asserts: 255 | - template: deployment.yaml 256 | isNotEmpty: 257 | path: .spec.template.spec.containers[0].livenessProbe 258 | 259 | - it: Should enable readiness probe 260 | set: 261 | readinessProbe: true 262 | asserts: 263 | - template: deployment.yaml 264 | isNotEmpty: 265 | path: .spec.template.spec.containers[0].readinessProbe 266 | 267 | - it: Should set the correct service account name 268 | set: 269 | serviceAccount: 270 | create: true 271 | name: custom-sa 272 | asserts: 273 | - template: deployment.yaml 274 | equal: 275 | path: .spec.template.spec.serviceAccountName 276 | value: custom-sa 277 | 278 | - it: Should set the correct prometheus rules 279 | set: 280 | prometheusRule: 281 | enabled: true 282 | additionalLabels: 283 | custom-label: custom-value 284 | rules: 285 | - alert: PrefectServerDown 286 | expr: sum by (pod, namespace) (kube_pod_info{namespace="prefect", pod=~"prefect-server.*"}) == 0 287 | for: 0m 288 | labels: 289 | severity: critical 290 | annotations: 291 | summary: Prefect server is down 292 | description: There are no Prefect server pods in the "prefect" namespace 293 | 294 | asserts: 295 | - template: prometheusrule.yaml 296 | equal: 297 | path: .metadata.labels.custom-label 298 | value: custom-value 299 | - template: prometheusrule.yaml 300 | equal: 301 | path: .spec.groups[0].rules[0].alert 302 | value: PrefectServerDown -------------------------------------------------------------------------------- /charts/prefect-server/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "common.names.fullname" . }} 5 | namespace: {{ include "common.names.namespace" . | quote }} 6 | labels: {{- include "common.labels.standard" . | nindent 4 }} 7 | app.kubernetes.io/component: server 8 | prefect-version: {{ .Chart.AppVersion }} 9 | {{- if .Values.commonLabels }} 10 | {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} 11 | {{- end }} 12 | {{- if .Values.commonAnnotations }} 13 | annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} 14 | {{- end }} 15 | spec: 16 | revisionHistoryLimit: {{ .Values.server.revisionHistoryLimit }} 17 | {{- if not .Values.server.autoscaling.enabled }} 18 | replicas: {{ .Values.sqlite.enabled | ternary 1 .Values.server.replicaCount }} 19 | {{- end }} 20 | selector: 21 | matchLabels: {{- include "common.labels.matchLabels" . | nindent 6 }} 22 | app.kubernetes.io/component: server 23 | strategy: {{ toYaml .Values.server.updateStrategy | nindent 4 }} 24 | template: 25 | metadata: 26 | {{- if .Values.server.podAnnotations }} 27 | annotations: {{- include "common.tplvalues.render" (dict "value" .Values.server.podAnnotations "context" $) | nindent 8 }} 28 | {{- end }} 29 | labels: {{- include "common.labels.standard" . | nindent 8 }} 30 | app.kubernetes.io/component: server 31 | prefect-version: {{ .Chart.AppVersion }} 32 | {{- if .Values.server.podLabels }} 33 | {{- include "common.tplvalues.render" (dict "value" .Values.server.podLabels "context" $) | nindent 8 }} 34 | {{- end }} 35 | spec: 36 | {{- if .Values.global.prefect.image.pullSecrets }} 37 | imagePullSecrets: 38 | {{- range .Values.global.prefect.image.pullSecrets }} 39 | - name: {{ . }} 40 | {{- end }} 41 | {{- end }} 42 | serviceAccountName: {{ template "server.serviceAccountName" . }} 43 | {{- if .Values.server.affinity }} 44 | affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.server.affinity "context" $) | nindent 8 }} 45 | {{- end }} 46 | {{- if .Values.server.nodeSelector }} 47 | nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.server.nodeSelector "context" $) | nindent 8 }} 48 | {{- end }} 49 | {{- if .Values.server.tolerations }} 50 | tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.server.tolerations "context" .) | nindent 8 }} 51 | {{- end }} 52 | {{- if .Values.server.podSecurityContext }} 53 | securityContext: {{- .Values.server.podSecurityContext | toYaml | nindent 8 }} 54 | {{- end }} 55 | {{- if .Values.server.priorityClassName }} 56 | priorityClassName: {{ .Values.server.priorityClassName }} 57 | {{- end }} 58 | containers: 59 | - name: prefect-server 60 | image: "{{ .Values.global.prefect.image.repository }}:{{ .Values.global.prefect.image.prefectTag }}" 61 | imagePullPolicy: {{ .Values.global.prefect.image.pullPolicy }} 62 | command: 63 | {{- if .Values.server.command }} 64 | {{- .Values.server.command | toYaml | nindent 12 }} 65 | {{- else }} 66 | - /usr/bin/tini 67 | - -g 68 | - -- 69 | - /opt/prefect/entrypoint.sh 70 | {{- end }} 71 | args: 72 | {{- if .Values.server.args }} 73 | {{- .Values.server.args | toYaml | nindent 12 }} 74 | {{- else }} 75 | - prefect 76 | - server 77 | - start 78 | {{- if .Values.backgroundServices.runAsSeparateDeployment }} 79 | - --no-services 80 | {{- end }} 81 | - --port 82 | - {{ .Values.service.targetPort | quote }} 83 | {{- range .Values.server.extraArgs }} 84 | - {{ . | toString }} 85 | {{- end }} 86 | {{- end }} 87 | workingDir: /home/prefect 88 | ports: 89 | - containerPort: {{ int .Values.service.targetPort }} 90 | env: 91 | - name: HOME 92 | value: /home/prefect 93 | - name: PREFECT_DEBUG_MODE 94 | value: {{ .Values.server.debug | quote }} 95 | - name: PREFECT_LOGGING_SERVER_LEVEL 96 | value: {{ .Values.server.loggingLevel | quote }} 97 | - name: PREFECT_SERVER_API_BASE_PATH 98 | value: {{ .Values.server.apiBasePath | quote }} 99 | - name: PREFECT_SERVER_API_HOST 100 | value: 0.0.0.0 101 | - name: PREFECT_SERVER_API_PORT 102 | value: {{ .Values.service.targetPort | quote }} 103 | - name: PREFECT_UI_API_URL 104 | value: {{ .Values.server.uiConfig.prefectUiApiUrl | quote }} 105 | - name: PREFECT_UI_STATIC_DIRECTORY 106 | value: {{ .Values.server.uiConfig.prefectUiStaticDirectory | quote }} 107 | - name: PREFECT_API_DATABASE_CONNECTION_URL 108 | {{- if .Values.sqlite.enabled }} 109 | value: "sqlite+aiosqlite:////data/prefect.db" 110 | {{- else }} 111 | valueFrom: 112 | secretKeyRef: 113 | name: {{ include "server.postgres-string-secret-name" . }} 114 | key: connection-string 115 | {{- end }} 116 | {{- if .Values.server.basicAuth.enabled }} 117 | - name: PREFECT_SERVER_API_AUTH_STRING 118 | {{- if .Values.server.basicAuth.existingSecret }} 119 | valueFrom: 120 | secretKeyRef: 121 | name: {{ .Values.server.basicAuth.existingSecret }} 122 | key: auth-string 123 | {{- else }} 124 | value: {{ .Values.server.basicAuth.authString | quote }} 125 | {{- end }} 126 | {{- end }} 127 | {{- if .Values.global.prefect.env }} 128 | {{- include "common.tplvalues.render" (dict "value" .Values.global.prefect.env "context" $) | nindent 12 }} 129 | {{- end }} 130 | {{- if .Values.server.env }} 131 | {{- include "common.tplvalues.render" (dict "value" .Values.server.env "context" $) | nindent 12 }} 132 | {{- end }} 133 | {{- if .Values.backgroundServices.runAsSeparateDeployment }} 134 | {{- include "backgroundServices.envVars" . | nindent 12 }} 135 | {{- end }} 136 | {{- if or (.Values.server.extraEnvVarsCM) (.Values.server.extraEnvVarsSecret) }} 137 | envFrom: 138 | {{- if .Values.server.extraEnvVarsCM }} 139 | - configMapRef: 140 | name: {{ include "common.tplvalues.render" (dict "value" .Values.server.extraEnvVarsCM "context" $) }} 141 | {{- end }} 142 | {{- if .Values.server.extraEnvVarsSecret }} 143 | - secretRef: 144 | name: {{ include "common.tplvalues.render" (dict "value" .Values.server.extraEnvVarsSecret "context" $) }} 145 | {{- end }} 146 | {{- end -}} 147 | {{- if .Values.server.resources }} 148 | resources: {{- toYaml .Values.server.resources | nindent 12 }} 149 | {{- end }} 150 | {{- with .Values.server.containerSecurityContext }} 151 | securityContext: {{- toYaml . | nindent 12 }} 152 | {{- end }} 153 | {{- if .Values.server.livenessProbe.enabled }} 154 | livenessProbe: 155 | httpGet: 156 | path: {{ .Values.server.apiBasePath }}/health 157 | port: {{ .Values.service.targetPort }} 158 | {{- toYaml .Values.server.livenessProbe.config | nindent 12 }} 159 | {{- end }} 160 | {{- if .Values.server.readinessProbe.enabled }} 161 | readinessProbe: 162 | httpGet: 163 | path: {{ .Values.server.apiBasePath }}/ready 164 | port: {{ .Values.service.targetPort }} 165 | {{- toYaml .Values.server.readinessProbe.config | nindent 12 }} 166 | {{- end }} 167 | volumeMounts: 168 | - mountPath: /home/prefect 169 | name: scratch 170 | subPathExpr: home 171 | - mountPath: /tmp 172 | name: scratch 173 | subPathExpr: tmp 174 | - mountPath: {{ .Values.server.uiConfig.prefectUiStaticDirectory }} 175 | name: scratch 176 | subPathExpr: ui-build 177 | {{- if .Values.sqlite.enabled }} 178 | - mountPath: /data 179 | name: sqlite-storage 180 | {{- end }} 181 | {{- if .Values.server.extraVolumeMounts }} 182 | {{- include "common.tplvalues.render" (dict "value" .Values.server.extraVolumeMounts "context" $) | nindent 12 }} 183 | {{- end }} 184 | {{- if .Values.server.extraContainers }} 185 | {{- include "common.tplvalues.render" (dict "value" .Values.server.extraContainers "context" $) | nindent 8 }} 186 | {{- end }} 187 | volumes: 188 | - name: scratch 189 | emptyDir: {} 190 | {{- if .Values.sqlite.enabled }} 191 | - name: sqlite-storage 192 | persistentVolumeClaim: 193 | claimName: {{ template "common.names.fullname" . }}-sqlite 194 | {{- end }} 195 | {{- if .Values.server.extraVolumes }} 196 | {{- include "common.tplvalues.render" (dict "value" .Values.server.extraVolumes "context" $) | nindent 8 }} 197 | {{- end }} 198 | -------------------------------------------------------------------------------- /charts/prefect-server/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Create the name of the service account to associate with the server deployment 3 | */}} 4 | {{- define "server.serviceAccountName" -}} 5 | {{- if .Values.serviceAccount.create -}} 6 | {{ default (include "common.names.fullname" .) .Values.serviceAccount.name }} 7 | {{- else -}} 8 | {{ default "default" .Values.serviceAccount.name }} 9 | {{- end -}} 10 | {{- end -}} 11 | 12 | {{/* 13 | Create the name of the service account to associate with the background-services deployment 14 | */}} 15 | {{- define "backgroundServices.serviceAccountName" -}} 16 | {{- if and .Values.backgroundServices.serviceAccount.create .Values.backgroundServices.runAsSeparateDeployment -}} 17 | {{ .Values.backgroundServices.serviceAccount.name | default (printf "%s-background-services" (include "common.names.fullname" .)) }} 18 | {{- else -}} 19 | {{ default "default" .Values.backgroundServices.serviceAccount.name }} 20 | {{- end -}} 21 | {{- end -}} 22 | 23 | {{- /* 24 | Reusable block for background services environment variables. 25 | */ -}} 26 | {{- define "backgroundServices.envVars" -}} 27 | {{- /* 28 | Make redis subchart context available as a variable in this block 29 | */ -}} 30 | {{- $redis := dict 31 | "Release" .Release 32 | "Capabilities" .Capabilities 33 | "Values" .Values.redis 34 | "Chart" (dict "Name" "redis") 35 | -}} 36 | - name: PREFECT_API_DATABASE_MIGRATE_ON_START 37 | value: "false" 38 | - name: PREFECT_MESSAGING_BROKER 39 | value: {{ .Values.backgroundServices.messaging.broker }} 40 | - name: PREFECT_MESSAGING_CACHE 41 | value: {{ .Values.backgroundServices.messaging.cache }} 42 | {{- if eq .Values.backgroundServices.messaging.broker "prefect_redis.messaging" }} 43 | - name: PREFECT_SERVER_EVENTS_CAUSAL_ORDERING 44 | value: prefect_redis.ordering 45 | - name: PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE 46 | value: prefect_redis.lease_storage 47 | - name: PREFECT_REDIS_MESSAGING_HOST 48 | {{- if and (.Values.redis.enabled) (.Values.backgroundServices.messaging.redis.host | empty) }} 49 | value: {{ printf "%s-headless" (include "common.names.fullname" $redis) }}.{{ .Release.Namespace }}.svc.cluster.local 50 | {{- else }} 51 | value: {{ .Values.backgroundServices.messaging.redis.host | quote }} 52 | {{- end }} 53 | - name: PREFECT_REDIS_MESSAGING_PORT 54 | value: {{ .Values.backgroundServices.messaging.redis.port | quote }} 55 | {{- if (.Values.backgroundServices.messaging.redis.ssl) }} 56 | - name: PREFECT_REDIS_MESSAGING_SSL 57 | value: {{ .Values.backgroundServices.messaging.redis.ssl | quote }} 58 | {{- end }} 59 | - name: PREFECT_REDIS_MESSAGING_DB 60 | value: {{ .Values.backgroundServices.messaging.redis.db | quote }} 61 | {{- if not (.Values.backgroundServices.messaging.redis.username | empty) }} 62 | - name: PREFECT_REDIS_MESSAGING_USERNAME 63 | value: {{ .Values.backgroundServices.messaging.redis.username | quote }} 64 | {{- end -}} 65 | {{- /* 66 | There are three scenarios for passwords: 67 | 1. If the subchart is enabled, reference the secret from the subchart. 68 | Setting backgroundServices.messaging.redis.password has no effect here. 69 | 2. If the subchart is not enabled, use the secret defined in the values file. TODO: secret reference 70 | 3. No password is set, so the environment variable is not defined. 71 | */ -}} 72 | {{- if and (.Values.redis.enabled) (.Values.backgroundServices.messaging.redis.password | empty) }} 73 | - name: PREFECT_REDIS_MESSAGING_PASSWORD 74 | valueFrom: 75 | secretKeyRef: 76 | name: {{ include "common.names.fullname" $redis }} 77 | key: redis-password 78 | {{- else if not (.Values.backgroundServices.messaging.redis.password | empty) }} 79 | - name: PREFECT_REDIS_MESSAGING_PASSWORD 80 | value: {{ .Values.backgroundServices.messaging.redis.password | quote }} 81 | {{- end }} 82 | {{- end }} 83 | {{- end -}} 84 | 85 | {{/* ----- Connection string templates ------ */}} 86 | 87 | {{/* 88 | server.postgres-hostname: 89 | Generate the hostname of the postgresql service 90 | If a subchart is used, evaluate using its fullname function 91 | and append the namespace at the end. 92 | Otherwise, the configured external hostname will be returned 93 | */}} 94 | {{- define "server.postgres-hostname" -}} 95 | {{- if .Values.postgresql.enabled -}} 96 | {{- $subchart_overrides := .Values.postgresql -}} 97 | {{- $name := include "postgresql.v1.primary.fullname" (dict "Values" $subchart_overrides "Chart" (dict "Name" "postgresql") "Release" .Release) -}} 98 | {{- printf "%s.%s" $name .Release.Namespace -}} 99 | {{- else -}} 100 | {{- .Values.secret.host | required ".Values.secret.host is required." -}} 101 | {{- end -}} 102 | {{- end -}} 103 | 104 | {{/* 105 | server.postgres-port: 106 | Generate the port of the postgresql service 107 | If a subchart is used, evaluate using its port function 108 | Otherwise, the configured port will be returned 109 | */}} 110 | {{- define "server.postgres-port" -}} 111 | {{- if .Values.postgresql.enabled -}} 112 | {{- $subchart_overrides := .Values.postgresql -}} 113 | {{- include "postgresql.v1.service.port" (dict "Values" $subchart_overrides) -}} 114 | {{- else -}} 115 | {{- .Values.secret.port | required ".Values.secret.port is required." -}} 116 | {{- end -}} 117 | {{- end -}} 118 | 119 | {{/* 120 | server.postgres-username: 121 | Generate the username for postgresql 122 | If a subchart is used, evaluate using its username function 123 | Otherwise, the configured username will be returned 124 | */}} 125 | {{- define "server.postgres-username" -}} 126 | {{- if .Values.postgresql.enabled -}} 127 | {{- $subchart_overrides := .Values.postgresql -}} 128 | {{- include "postgresql.v1.username" (dict "Values" $subchart_overrides) -}} 129 | {{- else -}} 130 | {{- .Values.secret.username | required ".Values.secret.username is required." -}} 131 | {{- end -}} 132 | {{- end -}} 133 | 134 | {{/* 135 | server.postgres-password: 136 | Generate the password for postgresql 137 | If a subchart is used, evaluate using its password value 138 | Otherwise, the configured password will be returned 139 | */}} 140 | {{- define "server.postgres-password" -}} 141 | {{- if .Values.postgresql.enabled -}} 142 | {{- .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required." -}} 143 | {{- else -}} 144 | {{- .Values.secret.password | required ".Values.secret.password is required." -}} 145 | {{- end -}} 146 | {{- end -}} 147 | 148 | {{/* 149 | server.postgres-database: 150 | Generate the database for postgresql 151 | If a subchart is used, evaluate using its database value 152 | Otherwise, the configured database will be returned 153 | */}} 154 | {{- define "server.postgres-database" -}} 155 | {{- if .Values.postgresql.enabled -}} 156 | {{- .Values.postgresql.auth.database | required ".Values.postgresql.auth.database is required." -}} 157 | {{- else -}} 158 | {{- .Values.secret.database | required ".Values.secret.database is required." -}} 159 | {{- end -}} 160 | {{- end -}} 161 | 162 | {{/* 163 | server.postgres-connstr: 164 | Generates the connection string for the postgresql service 165 | */}} 166 | {{- define "server.postgres-connstr" -}} 167 | {{- $user := include "server.postgres-username" . -}} 168 | {{- $pass := include "server.postgres-password" . -}} 169 | {{- $host := include "server.postgres-hostname" . -}} 170 | {{- $port := include "server.postgres-port" . -}} 171 | {{- $db := include "server.postgres-database" . -}} 172 | {{- printf "postgresql+asyncpg://%s:%s@%s:%s/%s" $user $pass $host $port $db -}} 173 | {{- end -}} 174 | 175 | {{/* 176 | server.postgres-string-secret-name: 177 | Get the name of the secret to be used for the postgresql 178 | user password. Generates {release-name}-postgresql-connection if 179 | an existing secret is not set. 180 | */}} 181 | {{- define "server.postgres-string-secret-name" -}} 182 | {{- if .Values.postgresql.auth.existingSecret -}} 183 | {{- .Values.postgresql.auth.existingSecret -}} 184 | {{- else if .Values.secret.name -}} 185 | {{- .Values.secret.name -}} 186 | {{- else -}} 187 | {{- $name := include "common.names.fullname" . -}} 188 | {{- printf "%s-%s" $name "postgresql-connection" -}} 189 | {{- end -}} 190 | {{- end -}} 191 | 192 | {{/* ----- End connection string templates ----- */}} 193 | 194 | {{- define "server.uiUrl" -}} 195 | {{- printf "%s" (replace "/api" "" .Values.server.uiConfig.prefectUiApiUrl) -}} 196 | {{- end -}} 197 | 198 | {{/* ----- Gateway API Helper Templates ----- */}} 199 | 200 | {{/* 201 | gateway.name: 202 | Returns the name of the Gateway resource 203 | */}} 204 | {{- define "gateway.name" -}} 205 | {{- if .Values.gateway.name -}} 206 | {{- .Values.gateway.name -}} 207 | {{- else -}} 208 | {{- include "common.names.fullname" . -}} 209 | {{- end -}} 210 | {{- end -}} 211 | 212 | {{/* 213 | httproute.name: 214 | Returns the name of the HTTPRoute resource 215 | */}} 216 | {{- define "httproute.name" -}} 217 | {{- if .Values.httproute.name -}} 218 | {{- .Values.httproute.name -}} 219 | {{- else -}} 220 | {{- include "common.names.fullname" . -}} 221 | {{- end -}} 222 | {{- end -}} 223 | 224 | {{/* 225 | gateway.hostnames: 226 | Returns the list of hostnames for Gateway/HTTPRoute from httproute.hostnames 227 | */}} 228 | {{- define "gateway.hostnames" -}} 229 | {{- if .Values.httproute.hostnames -}} 230 | {{- toYaml .Values.httproute.hostnames -}} 231 | {{- end -}} 232 | {{- end -}} 233 | 234 | {{/* 235 | gateway.tlsSecretName: 236 | Returns the TLS secret name based on the first gateway hostname or release name 237 | */}} 238 | {{- define "gateway.tlsSecretName" -}} 239 | {{- $hostnames := include "gateway.hostnames" . | fromYamlArray -}} 240 | {{- if $hostnames -}} 241 | {{- printf "%s-tls" (index $hostnames 0) -}} 242 | {{- else -}} 243 | {{- printf "%s-tls" (include "common.names.fullname" .) -}} 244 | {{- end -}} 245 | {{- end -}} 246 | 247 | {{/* 248 | gateway.apiAvailable: 249 | Check if Gateway API is available in the cluster 250 | Returns "true" if available, empty otherwise 251 | */}} 252 | {{- define "gateway.apiAvailable" -}} 253 | {{- if .Capabilities.APIVersions.Has "gateway.networking.k8s.io/v1/Gateway" -}} 254 | true 255 | {{- end -}} 256 | {{- end -}} 257 | 258 | {{/* ----- End Gateway API Helper Templates ----- */}} 259 | -------------------------------------------------------------------------------- /charts/prometheus-prefect-exporter/values.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema#", 3 | "type": "object", 4 | "additionalProperties": true, 5 | "properties": { 6 | "revisionHistoryLimit": { 7 | "type": "integer", 8 | "title": "Revision History Limit", 9 | "description": "the number of old ReplicaSets to retain to allow rollback" 10 | }, 11 | "replicaCount": { 12 | "type": "integer", 13 | "title": "Replica Count", 14 | "description": "Number of replicas to deploy" 15 | }, 16 | "image": { 17 | "type": "object", 18 | "title": "Image", 19 | "description": "Image to deploy", 20 | "properties": { 21 | "repository": { 22 | "type": "string", 23 | "title": "Repository", 24 | "description": "Image repository" 25 | }, 26 | "tag": { 27 | "type": "string", 28 | "title": "Tag", 29 | "description": "Image tag" 30 | }, 31 | "pullPolicy": { 32 | "type": "string", 33 | "title": "Pull Policy", 34 | "description": "Image pull policy" 35 | } 36 | } 37 | }, 38 | "nameOverride": { 39 | "type": "string", 40 | "title": "Name Override", 41 | "description": "Override the name of the chart" 42 | }, 43 | "fullnameOverride": { 44 | "type": "string", 45 | "title": "Fullname Override", 46 | "description": "Override the fullname of the chart" 47 | }, 48 | "imagePullSecrets": { 49 | "type": "array", 50 | "title": "Image Pull Secrets", 51 | "description": "Image pull secrets" 52 | }, 53 | "serviceAccount": { 54 | "type": "object", 55 | "title": "Service Account", 56 | "description": "Service account", 57 | "properties": { 58 | "create": { 59 | "type": "boolean", 60 | "title": "Create", 61 | "description": "Create service account" 62 | }, 63 | "annotations": { 64 | "type": "object", 65 | "title": "Annotations", 66 | "description": "Service account annotations" 67 | }, 68 | "name": { 69 | "type": "string", 70 | "title": "Name", 71 | "description": "Service account name" 72 | } 73 | } 74 | }, 75 | "prefectApiUrl": { 76 | "type": "string", 77 | "title": "Prefect API URL", 78 | "description": "Prefect API URL" 79 | }, 80 | "csrfAuth": { 81 | "type": "boolean", 82 | "title": "CSRF Auth", 83 | "description": "Enable CSRF auth" 84 | }, 85 | "basicAuth": { 86 | "type": "object", 87 | "title": "Basic Auth", 88 | "description": "basic auth configuration", 89 | "properties": { 90 | "enabled": { 91 | "type": "boolean", 92 | "title": "Enabled", 93 | "description": "enable basic auth for the exporter, for an administrator/password combination. must be enabled on the server as well" 94 | }, 95 | "authString": { 96 | "type": "string", 97 | "title": "Auth String", 98 | "description": "basic auth credentials in the format admin: (no brackets)" 99 | }, 100 | "existingSecret": { 101 | "type": "string", 102 | "title": "Existing Secret", 103 | "description": "name of existing secret containing basic auth credentials. takes precedence over authString. must contain a key `auth-string` with the value of the auth string" 104 | } 105 | } 106 | }, 107 | "pagination": { 108 | "type": "object", 109 | "title": "Pagination", 110 | "description": "Pagination settings", 111 | "properties": { 112 | "enabled": { 113 | "type": "boolean", 114 | "title": "Enabled", 115 | "description": "Enable pagination" 116 | }, 117 | "limit": { 118 | "type": "integer", 119 | "title": "Limit", 120 | "description": "Pagination limit" 121 | } 122 | } 123 | }, 124 | "env": { 125 | "type": "object", 126 | "title": "Environment Variables", 127 | "description": "Environment variables" 128 | }, 129 | "extraEnvVars": { 130 | "type": "array", 131 | "title": "Extra Env Vars", 132 | "description": "Extra environment variables to add to exporter deployment pods" 133 | }, 134 | "podDisruptionBudget": { 135 | "type": "object", 136 | "title": "Pod Disruption Budget", 137 | "description": "Pod disruption budget" 138 | }, 139 | "podAnnotations": { 140 | "type": "object", 141 | "title": "Pod Annotations", 142 | "description": "Pod annotations" 143 | }, 144 | "podSecurityContext": { 145 | "type": "object", 146 | "title": "Pod Security Context", 147 | "description": "Pod security context" 148 | }, 149 | "securityContext": { 150 | "type": "object", 151 | "title": "Security Context", 152 | "description": "Security context" 153 | }, 154 | "service": { 155 | "type": "object", 156 | "additionalProperties": true, 157 | "title": "Service", 158 | "description": "Service", 159 | "properties": { 160 | "type": { 161 | "type": "string", 162 | "title": "Type", 163 | "description": "Service type" 164 | }, 165 | "port": { 166 | "type": "integer", 167 | "title": "Port", 168 | "description": "Service port" 169 | }, 170 | "targetPort": { 171 | "type": "integer", 172 | "title": "Target Port", 173 | "description": "Service target port" 174 | }, 175 | "annotations": { 176 | "type": "object", 177 | "title": "Annotations", 178 | "description": "annotations to add to the exporter service" 179 | } 180 | } 181 | }, 182 | "serviceMonitor": { 183 | "type": "object", 184 | "title": "Service Monitor", 185 | "description": "Service monitor", 186 | "properties": { 187 | "enabled": { 188 | "type": "boolean", 189 | "title": "Enabled", 190 | "description": "Enable service monitor" 191 | }, 192 | "additionalLabels": { 193 | "type": "object", 194 | "title": "Additional Labels", 195 | "description": "Prometheus rule additional labels" 196 | }, 197 | "interval": { 198 | "type": "string", 199 | "title": "Interval", 200 | "description": "Service monitor interval" 201 | }, 202 | "scrapeTimeout": { 203 | "type": "string", 204 | "title": "Timeout", 205 | "description": "Service monitor timeout" 206 | }, 207 | "metricRelabelings": { 208 | "type": "array", 209 | "title": "Metric Relabelings", 210 | "description": "Service monitor metric relabelings" 211 | }, 212 | "relabelings": { 213 | "type": "array", 214 | "title": "Relabelings", 215 | "description": "Service monitor relabelings" 216 | } 217 | } 218 | }, 219 | "prometheusRule": { 220 | "type": "object", 221 | "title": "Prometheus Rule", 222 | "description": "Prometheus rule", 223 | "properties": { 224 | "enabled": { 225 | "type": "boolean", 226 | "title": "Enabled", 227 | "description": "Enable prometheus rule" 228 | }, 229 | "additionalLabels": { 230 | "type": "object", 231 | "title": "Additional Labels", 232 | "description": "Prometheus rule additional labels" 233 | }, 234 | "rules": { 235 | "type": "array", 236 | "title": "Rules", 237 | "description": "Prometheus rule rules" 238 | } 239 | } 240 | }, 241 | "livenessProbe": { 242 | "type": "boolean", 243 | "title": "Liveness Probe", 244 | "description": "Enable liveness probe" 245 | }, 246 | "readinessProbe": { 247 | "type": "boolean", 248 | "title": "Readiness Probe", 249 | "description": "Enable readiness probe" 250 | }, 251 | "ingress": { 252 | "type": "object", 253 | "title": "Ingress", 254 | "description": "Ingress", 255 | "properties": { 256 | "enabled": { 257 | "type": "boolean", 258 | "title": "Enabled", 259 | "description": "Enable ingress" 260 | }, 261 | "className": { 262 | "type": "string", 263 | "title": "Class Name", 264 | "description": "Ingress class name" 265 | }, 266 | "annotations": { 267 | "type": "object", 268 | "title": "Annotations", 269 | "description": "Ingress annotations" 270 | }, 271 | "hosts": { 272 | "type": "array", 273 | "title": "Hosts", 274 | "description": "Ingress hosts" 275 | }, 276 | "tls": { 277 | "type": "array", 278 | "title": "TLS", 279 | "description": "Ingress TLS" 280 | } 281 | } 282 | }, 283 | "resources": { 284 | "type": "object", 285 | "title": "Resources", 286 | "description": "Resources" 287 | }, 288 | "autoscaling": { 289 | "type": "object", 290 | "title": "Autoscaling", 291 | "description": "Autoscaling", 292 | "properties": { 293 | "enabled": { 294 | "type": "boolean", 295 | "title": "Enabled", 296 | "description": "Enable autoscaling" 297 | }, 298 | "minReplicas": { 299 | "type": "integer", 300 | "title": "Min Replicas", 301 | "description": "Autoscaling min replicas" 302 | }, 303 | "maxReplicas": { 304 | "type": "integer", 305 | "title": "Max Replicas", 306 | "description": "Autoscaling max replicas" 307 | }, 308 | "targetCPUUtilizationPercentage": { 309 | "type": "integer", 310 | "title": "Target CPU Utilization Percentage", 311 | "description": "Autoscaling target CPU utilization percentage" 312 | } 313 | } 314 | }, 315 | "nodeSelector": { 316 | "type": "object", 317 | "title": "Node Selector", 318 | "description": "Node selector" 319 | }, 320 | "tolerations": { 321 | "type": "array", 322 | "title": "Tolerations", 323 | "description": "Tolerations" 324 | }, 325 | "affinity": { 326 | "type": "object", 327 | "title": "Affinity", 328 | "description": "Affinity" 329 | }, 330 | "common": { 331 | "type": "object", 332 | "title": "Common", 333 | "description": "common configuration. Not set by user but required as common vars are passed to all manifests." 334 | }, 335 | "global": { 336 | "type": "object", 337 | "title": "Global", 338 | "description": "global configuration. Not set by user but required when prefect is referenced as a downstream Chart" 339 | } 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /charts/prefect-server/README.md.gotmpl: -------------------------------------------------------------------------------- 1 | {{ template "chart.header" . }} 2 | {{ template "chart.description" . }} 3 | 4 | {{ template "chart.homepageLine" . }} 5 | 6 | ## Installing the Chart 7 | 8 | To install the chart with the release name `prefect-server`: 9 | 10 | ```console 11 | helm repo add prefect https://prefecthq.github.io/prefect-helm 12 | helm install prefect-server prefect/prefect-server 13 | ``` 14 | 15 | ## Prefect Configuration 16 | 17 | ### Container Port // Port Forwarding 18 | 19 | Without making any modifications to the `values.yaml` file, you can access the Prefect UI by port forwarding either the Server `pod` or `service` with the following command and visiting [http:localhost:4200](http:localhost:4200): 20 | ```console 21 | kubectl port-forward svc/prefect-server 4200:4200 22 | ``` 23 | 24 | Note: If you choose to make modifications to either the `server.prefectApiUrl` or `service.port`, make sure to update the other value with the updated port! 25 | 26 | ### Basic Auth 27 | 28 | Prefect documentation on [basic auth](https://docs.prefect.io/v3/develop/settings-and-profiles#security-settings) 29 | 30 | Self-hosted Prefect servers can be equipped with a Basic Authentication string for an administrator/password combination. 31 | 32 | The format of the auth string is `admin:` (no brackets). 33 | 34 | ```yaml 35 | server: 36 | basicAuth: 37 | enabled: true 38 | authString: "admin:pass" 39 | ``` 40 | 41 | Alternatively, you can provide an existing Kubernetes Secret containing the auth string credentials. The secret must contain a key `auth-string` with the value of the auth string. 42 | 43 | ```sh 44 | kubectl create secret generic prefect-basic-auth --from-literal=auth-string='admin:my-password' 45 | ``` 46 | 47 | ```yaml 48 | server: 49 | basicAuth: 50 | enabled: true 51 | existingSecret: prefect-basic-auth 52 | ``` 53 | 54 | ## Background Services Configuration 55 | 56 | The Prefect server includes background services related to scheduling and 57 | cleanup. By default, these run in the same deployment as the web server, but 58 | they can be separated for better resource management and scalability. 59 | 60 | Support for this separation was added to provide a path to scaling your deployment as your usage grows. 61 | If you are orchestrating a lot of work, you may need more web services to handle requests than background 62 | services to field the increased API requests. 63 | 64 | By default, the web services and background services share a connection pool to the 65 | database, but their connection needs are very different and even antagonistic 66 | with each other at times. Splitting the background services out also allows you 67 | to tune the database connections for each deployment (pool size, timeout, etc.), 68 | which can help with the database load. 69 | 70 | The separate deployment for background services is currently limited to one replica 71 | because it has not been optimized for running multiple copies. Additionally, many background 72 | services run on a loop between 5 and 60 seconds, so if they go down, Kubernetes should bring 73 | them back up after a health check without much disruption. 74 | 75 | Splitting the background services is optional, and is likely not necessary if 76 | you are not having any issues with your setup. 77 | 78 | To run background services in a separate deployment: 79 | 80 | > [!WARNING] 81 | > **Version Requirement**: When using `backgroundServices.runAsSeparateDeployment: true`, you must use Prefect 3.4.16 or later. Earlier versions have a bug where the `--no-services` flag doesn't fully disable background services, causing Redis connection errors in the server pod. 82 | 83 | ```yaml 84 | backgroundServices: 85 | runAsSeparateDeployment: true 86 | 87 | # Use the bundled Redis chart 88 | # See the next section for more details on other deployment options 89 | redis: 90 | enabled: true 91 | ``` 92 | 93 | This configuration is recommended when: 94 | - You're experiencing database connection pool contention 95 | - You need different scaling policies for the web server and background services 96 | - You want to monitor and manage resource usage separately 97 | 98 | You can read more about this architecture in the [How to scale self-hosted Prefect](https://docs.prefect.io/v3/advanced/self-hosted) guide. 99 | 100 | ## Redis Configuration 101 | 102 | This section applies when enabling the use of Background Services. 103 | 104 | For a simple deployment, you can use the bundled Redis chart by setting the following: 105 | 106 | ```yaml 107 | redis: 108 | enabled: true 109 | ``` 110 | 111 | This will automatically configure the Prefect server and background services to use the bundled Redis instance with the correct connection string information. 112 | 113 | If you want to use the bundled Redis chart but need to customize the configuration, you can do so by providing additional values under the `redis` section. For example: 114 | 115 | ```yaml 116 | redis: 117 | enabled: true 118 | 119 | auth: 120 | # set a custom password for the Redis instance 121 | password: "dontpanic!" 122 | ``` 123 | 124 | You can find additional configuration values in the [Bitnami Redis chart values.yaml file](https://github.com/bitnami/charts/blob/main/bitnami/redis/values.yaml). 125 | 126 | **NOTE** Using the embedded Bitnami Redis chart his is **not intended for production use**, and is only 127 | included to provide a functional proof of concept installation. 128 | 129 | ### Using an External Redis Instance 130 | 131 | If you want to use an existing or external Redis instance, do not set `redis.enabled`. Provide the connection details in the `backgroundServices.messaging.redis` section: 132 | 133 | ```yaml 134 | backgroundServices: 135 | runAsSeparateDeployment: true 136 | messaging: 137 | redis: 138 | host: external.redis.host.example.com 139 | username: marvin 140 | password: paranoid! 141 | ``` 142 | 143 | ## PostgreSQL Configuration 144 | 145 | ### Handling Connection Secrets 146 | 147 | #### Using the bundled PostgreSQL chart 148 | 149 | By default, Bitnami's PostgreSQL Helm Chart will be deployed. This is **not intended for production use**, and is only 150 | included to provide a functional proof of concept installation. 151 | 152 | In this scenario, you'll need to provide _either one_ of the following fields: 153 | 154 | 1. `postgresql.auth.password`: a password you want to set for the prefect user (default: `prefect-rocks`) 155 | 156 | 2. `postgresql.auth.existingSecret`: name of an existing secret in your cluster with the following field: 157 | 158 | - `connection-string`: fully-quallified connection string in the format of `postgresql+asyncpg://{username}:{password}@{hostname}/{database}` 159 | - username = `postgresql.auth.username` 160 | - hostname = `-postgresql.:` 161 | - database = `postgresql.auth.database` 162 | 163 | Two secrets are created when not providing an existing secret name: 164 | 1. `prefect-server-postgresql-connection`: used by the prefect-server deployment to connect to the postgresql database. 165 | 166 | 2. `-postgresql-0`: defines the `postgresql.auth.username`'s password on the postgresql server to allow successful authentication from the prefect server. 167 | 168 | #### Using an external instance of PostgreSQL 169 | 170 | If you want to disable the bundled PostgreSQL chart and use an external instance, provide the following configuration: 171 | 172 | ```yaml 173 | postgresql: 174 | enabled: false 175 | 176 | secret: 177 | # Option 1: provide the name of an existing secret following the instructions above. 178 | create: false 179 | name: 180 | 181 | # Option 2: provide the connection string details directly 182 | create: true 183 | username: myuser 184 | password: mypass 185 | host: myhost.com 186 | port: 1234 187 | database: mydb 188 | ``` 189 | 190 | ### Connecting with SSL configured 191 | 192 | 1. Mount the relevant certificate to `/home/prefect/.postgresql` so that it can be found by `asyncpg`. This is the default location postgresql expects per their [documentation](https://www.postgresql.org/docs/current/libpq-ssl.html). 193 | ```yaml 194 | server: 195 | extraVolumes: 196 | - name: db-ssl-secret 197 | secret: 198 | secretName: db-ssl-secret 199 | defaultMode: 384 200 | extraVolumeMounts: 201 | - name: db-ssl-secret 202 | mountPath: "/home/prefect/.postgresql" 203 | readOnly: true 204 | postgresql: 205 | enabled: false 206 | auth: 207 | existingSecret: external-db-connection-string 208 | ``` 209 | 210 | 2. Create a secret to hold the ca certificate for the database with the key `root.crt` 211 | ```yaml 212 | apiVersion: v1 213 | kind: Secret 214 | metadata: 215 | name: db-ssl-secret 216 | data: 217 | root.crt: BASE64ENCODECERTIFICATE= 218 | type: Opaque 219 | ``` 220 | 221 | 3. Set the connection string in the existing secret following this format - `?ssl=verify-ca` is crucial: 222 | ``` 223 | postgresql+asyncpg://{username}:{password}@{hostname}/{database}?ssl=verify-ca 224 | ``` 225 | 226 | ### Database Migrations 227 | 228 | The chart automatically handles database migrations during upgrades using a pre-upgrade hook. When you upgrade the chart, it will: 229 | 230 | 1. Run `prefect server database upgrade -y` before updating the main deployment 231 | 2. Ensure your database schema is compatible with the new Prefect version 232 | 3. Block the upgrade if migrations fail 233 | 234 | **Important Notes:** 235 | - Migrations only run for PostgreSQL deployments (not SQLite) 236 | - The migration job uses the same database credentials as your main deployment 237 | - **Downgrades require manual intervention** - if you need to rollback, you may need to manually run database downgrade commands 238 | - For more details, see [Prefect's database migration documentation](https://docs.prefect.io/v3/advanced/self-hosted#database-migrations) 239 | 240 | #### Migration Configuration 241 | 242 | The migration behavior can be customized through the `migrations` section in your values. 243 | 244 | For example, to disable automatic migrations (not recommended): 245 | 246 | ```yaml 247 | migrations: 248 | # Enable/disable automatic migrations (default: true) 249 | enabled: false 250 | ``` 251 | 252 | Consult the `values.yaml` file for additional configuration options such as resource requests/limits, backoff limits, and timeouts. 253 | 254 | ## SQLite Configuration 255 | 256 | SQLite can be used as an alternative to PostgreSQL. As mentioned in the 257 | [documentation on hosting Prefect](https://docs-3.prefect.io/v3/manage/self-host), 258 | SQLite is only recommended for lightweight, single-server deployments. 259 | 260 | To use SQLite for the database, provide the following configuration values: 261 | 262 | ```yaml 263 | postgresql: 264 | enabled: false 265 | sqlite: 266 | enabled: true 267 | ``` 268 | 269 | More configuration options are available in [`values.yaml`](./values.yaml). 270 | 271 | By default, a PersistentVolumeClaim persists the SQLite database file between 272 | Pod restarts. 273 | 274 | Note that enabling SQLite enforces 1 replica in the Deployment, and disables 275 | the HorizontalPodAutoscaler. 276 | 277 | {{ template "chart.maintainersSection" . }} 278 | 279 | {{ template "chart.requirementsSection" . }} 280 | 281 | {{ template "chart.valuesSection" . }} 282 | 283 | {{ template "helm-docs.versionFooter" . }} 284 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Prefect Helm Charts 2 | 3 | This repository contains the official Prefect Helm charts for installing and configuring Prefect on Kubernetes. These charts support multiple use cases of Prefect on Kubernetes depending on the values provided and chart selected including: 4 | 5 | ## [Prefect worker](charts/prefect-worker/) 6 | 7 | [Workers](https://docs.prefect.io/latest/concepts/work-pools/#worker-overview) are lightweight polling services that retrieve scheduled runs from a work pool and execute them. 8 | 9 | Workers each have a type corresponding to the execution environment to which they will submit flow runs. Workers are only able to join work pools that match their type. As a result, when deployments are assigned to a work pool, you know in which execution environment scheduled flow runs for that deployment will run. 10 | 11 | ## [Prefect server](charts/prefect-server/) 12 | 13 | [Prefect server](https://docs.prefect.io/latest/guides/host/) is a self-hosted open source backend that makes it easy to observe and orchestrate your Prefect flows. It is an alternative to using the hosted [Prefect Cloud](https://docs.prefect.io/latest/cloud/) platform. Prefect Cloud provides additional features including automations and user management. 14 | 15 | ## [Prometheus Prefect Exporter](charts/prometheus-prefect-exporter/) 16 | 17 | The Prometheus Prefect Exporter is a tool to pull relevant Prefect metrics from a hosted Prefect Server instance 18 | 19 | ## Prefect agent 20 | 21 | Prefect Agents have been deprecated. `prefect-helm` version `2024.8.30163822` and earlier will contain the `prefect-agent` chart. 22 | 23 | ## Usage 24 | 25 | [Helm](https://helm.sh) must be installed to use the charts. 26 | Please refer to Helm's [documentation](https://helm.sh/docs/) to get started. 27 | 28 | ### TL;DR 29 | 30 | ```bash 31 | helm repo add prefect https://prefecthq.github.io/prefect-helm 32 | helm search repo prefect 33 | helm install my-release prefect/prefect- 34 | ``` 35 | 36 | ### Installing released versions 37 | 38 | Charts are automatically versioned and released together. The `appVersion` and `prefectTag` version are pinned at package time to the current release of Prefect 3. 39 | 40 | The charts are hosted in a [Helm repository](https://helm.sh/docs/chart_repository/) deployed to the web courtesy of GitHub Pages. 41 | 42 | 1. Add the Prefect Helm repository to Helm and list available charts and versions: 43 | 44 | ```bash 45 | helm repo add prefect https://prefecthq.github.io/prefect-helm 46 | helm repo update 47 | helm search repo prefect 48 | ``` 49 | 50 | 2. Install the Helm chart 51 | 52 | Each chart will require some specific configuration values to be provided, see the individual chart README's for more information on configuring and installing the chart. 53 | 54 | If chart installation fails, run the same command with `--debug` to see additional diagnostic information. 55 | 56 | Refer to the [Helm `install` documentation](https://helm.sh/docs/helm/helm_install/) for all options. 57 | 58 | The helm charts are tested against Kubernetes 1.26.0 and newer minor versions. 59 | 60 | ### Installing development versions 61 | 62 | Development versions of the Helm chart will always be available directly from this Github repository. 63 | 64 | 1. Clone repository 65 | 66 | 2. Change to this directory 67 | 68 | 3. Download the chart dependencies 69 | 70 | ```bash 71 | helm dependency update 72 | ``` 73 | 74 | 4. Install the chart 75 | 76 | ```bash 77 | helm install . --generate-name 78 | ``` 79 | 80 | ### Upgrading 81 | 82 | 1. Look up the name of the last release 83 | 84 | ```bash 85 | helm list 86 | ``` 87 | 88 | 2. Run the upgrade 89 | 90 | ```bash 91 | # Choose a version to upgrade to or omit the flag to use the latest version 92 | helm upgrade prefect-server prefect/prefect-server --version 2023.09.07 93 | ``` 94 | 95 | For development versions, make sure your cloned repository is updated (`git pull`) and reference the local chart 96 | 97 | ```bash 98 | helm upgrade prefect-server . 99 | ``` 100 | 101 | 3. Upgrades can also be used enable features or change options 102 | 103 | ```bash 104 | helm upgrade prefect-server prefect/prefect-server --set newValue=true 105 | ``` 106 | 107 | #### Important notes about upgrading 108 | 109 | - Updates will only update infrastructure that is modified. 110 | - You will need to continue to set any values that you set during the original install (e.g. `--set namespaceOverride=prefect` or `--values path/to/values.yaml`). 111 | - If you are using the postgresql subchart with an autogenerated password, it will complain that you have not provided that password for the upgrade. Export the password as the error asks then set it within the subchart using: 112 | ```bash 113 | helm upgrade ... --set postgresql.postgresqlPassword=$POSTGRESQL_PASSWORD 114 | ``` 115 | 116 | ## Chart Provenance 117 | 118 | You can verify the integrity and origin of Prefect Helm charts by using [Helm provenance](https://helm.sh/docs/topics/provenance/). 119 | 120 | The official Prefect Helm Chart public signing key must be used to verify the provenance of the Prefect Helm charts. Prefect uses [Keybase](https://keybase.io/) to host the public signing key. The key must first be downloaded and then imported into a local keyring. 121 | 122 | ### Download the Public Signing Key 123 | 124 | ```bash 125 | curl https://keybase.io/prefecthq/pgp_keys.asc | gpg --import 126 | ``` 127 | 128 | ### Verify a Chart 129 | 130 | A Prefect Helm chart can be verified either by: 131 | - Downloading the chart and running `helm verify`. 132 | - Using the `--verify` option during chart installation. 133 | 134 | #### Verify a Downloaded Chart 135 | 136 | You can use the `helm verify` command to verify a downloaded chart. To download a verifiable chart, use the `helm pull --prov` command. For example: 137 | 138 | ```bash 139 | helm pull --prov prefect/prefect-worker 140 | ``` 141 | 142 | You can then use the `helm verify` command to verify the downloaded chart. 143 | 144 | ```bash 145 | helm verify prefect-worker-.tgz 146 | Signed by: Jamie Zieziula 147 | Signed by: Jamie Zieziula 148 | Using Key With Fingerprint: 062AA2CFEFB2A02D54975B528DBDDA7074C40C6A 149 | Chart Hash Verified: sha256:90eecaf6650ec08045b82c1f3dbf75529105de1a7fb0e64927ab648752746cea 150 | ``` 151 | 152 | #### Verify a Chart During Installation 153 | 154 | You can verify a chart during installation by using the `--verify` option to either the `helm install` or `helm upgrade` command. 155 | 156 | ```bash 157 | # During installation 158 | helm install prefect-worker --verify prefect/prefect-worker 159 | 160 | # During upgrade 161 | helm upgrade prefect-worker --verify prefect/prefect-worker 162 | ``` 163 | 164 | ## Options: 165 | 166 | See comments in `values.yaml`. 167 | 168 | ### Security context 169 | 170 | By default, the worker, and server run as an unprivileged user with a read-only root filesystem. You can customize the security context settings for both the worker and server in the `values.yaml` file for your use case. 171 | 172 | If you need to install system packages or configure other settings at runtime, you can configure a writable filesystem and run as root by configuring the pod and container security context accordingly: 173 | 174 | ```yaml 175 | podSecurityContext: 176 | runAsUser: 0 177 | runAsNonRoot: false 178 | fsGroup: 0 179 | 180 | containerSecurityContext: 181 | runAsUser: 0 182 | # this must be false, since we are running as root 183 | runAsNonRoot: false 184 | # make the filesystem writable 185 | readOnlyRootFilesystem: false 186 | # this must be false, since we are running as root 187 | allowPrivilegeEscalation: false 188 | ``` 189 | 190 | If you are running in OpenShift, the default `restricted` security context constraint will prevent customization of the user. In this case, explicitly configure the `runAsUser` settings to `null` to use OpenShift-assigned settings: 191 | 192 | ```yaml 193 | podSecurityContext: 194 | runAsUser: null 195 | fsGroup: null 196 | 197 | containerSecurityContext: 198 | runAsUser: null 199 | ``` 200 | 201 | The other default settings, such as a read-only root filesystem, are suitable for an OpenShift environment. 202 | 203 | ## Version support policy 204 | 205 | Prefect follows the [upstream Kubernetes support policy](https://kubernetes.io/releases/version-skew-policy/), meaning that we test against the three most recent minor version releases of Kubernetes. The charts may be compatible with older releases of Kubernetes, however, we do not test against those versions and may choose to reject issues or patches to add support. 206 | 207 | ## Troubleshooting 208 | 209 | ### The database deploys correctly but other services fail with "bad password" 210 | 211 | If you are using the subchart deployed database with persistence enabled, it is likely the password for the user has persisted between deployments in the PVC for the database but the secret has been regenerated by the Helm chart and does not match. Deploy and set the 'postgresql.auth.existingSecret' option or set a constant password at `postgresql.auth.password`. 212 | 213 | ## Contributing 214 | 215 | Contributions to the Prefect Helm Charts are always welcome! We welcome your help - whether it's adding new functionality, tweaking documentation, or anything in between. In order to successfully contribute, you'll need to fork this repository and commit changes to your local prefect-helm repo. You can then open a PR against this upstream repo that the team will review! 216 | 217 | To get started, install the required dependencies by running: 218 | 219 | ```shell 220 | mise run tools 221 | ``` 222 | 223 | This will install tools like `helm`, `pre-commit`, and `mise`. 224 | 225 | To see a list of all available commands, run `mise tasks ls`. 226 | 227 | ### Testing & validation 228 | 229 | Make sure that any new functionality is well tested! You can do this by installing the chart locally, see [above](https://github.com/PrefectHQ/prefect-helm#installing-development-versions) for how to do this. 230 | 231 | #### Helm unit tests 232 | 233 | You can also create and run test suites via [helm-unittest](https://github.com/helm-unittest/helm-unittest). 234 | Related test files are stored under `./charts//tests/*_test.yaml`. 235 | Refer to the `helm-unittest` repository for more information. 236 | 237 | The following helper script will run the tests via the `helm-unittest` Docker image in case you don't have the binary installed locally: 238 | 239 | ```shell 240 | mise run helmtest 241 | ``` 242 | 243 | When `helm-unittest` is available via the [`mise` registry](https://mise.jdx.dev/registry.html), we'll add it to `.mise.toml` 244 | for easy local installation. 245 | 246 | #### Helm linting and validation 247 | 248 | We use [chart-testing](https://github.com/helm/chart-testing) for linting and validation of our charts. 249 | Configuration files are stored under `./github/linters/*-ct.yaml`. 250 | Refer to the `chart-testing` repository for more information. 251 | 252 | The following helper script will run the tests via the `chart-testing` Docker image. The `helm-ct` binary will 253 | be installed locally through `mise`, but the Docker image addresses the problem of a missing local `chart_schema.yaml` file. 254 | 255 | ```shell 256 | mise run charttest 257 | ``` 258 | 259 | ### Opening a PR 260 | 261 | A helpful PR explains WHAT changed and WHY the change is important. Please take time to make your PR descriptions as helpful as possible. If you are opening a PR from a forked repository - please follow [these](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) docs to allow `prefect-helm` maintainers to push commits to your local branch. 262 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------