diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0aaab4a..c60f06e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -87,6 +87,9 @@ jobs:
- name: Install dependencies
run: uv sync --all-extras
+ - name: Set up providers
+ run: uv run ref providers setup
+
- name: Fetch test data
run: |
mkdir -p "$REF_TEST_DATA_DIR"
diff --git a/.github/workflows/packaging.yaml b/.github/workflows/packaging.yaml
new file mode 100644
index 0000000..1f539c5
--- /dev/null
+++ b/.github/workflows/packaging.yaml
@@ -0,0 +1,172 @@
+name: Packaging
+
+on:
+ pull_request:
+ workflow_dispatch:
+ push:
+ branches:
+ - "main"
+ tags:
+ - "v*"
+
+permissions:
+ contents: read
+ packages: write
+ attestations: write
+ id-token: write
+
+jobs:
+ changes:
+ name: Detect Changes
+ runs-on: ubuntu-latest
+ outputs:
+ helm: ${{ steps.filter.outputs.helm }}
+ steps:
+ - uses: actions/checkout@v6
+ # - uses: dorny/paths-filter@v3
+ # id: filter
+ # with:
+ # filters: |
+ # helm:
+ # - 'helm/**'
+
+
+ helm:
+ name: Helm Chart
+ runs-on: ubuntu-latest
+ needs: [changes]
+ if: needs.changes.outputs.helm == 'true' || github.event_name != 'pull_request'
+ permissions:
+ packages: write
+ outputs:
+ generated-semver: ${{ steps.semantic-version.outputs.generated-semver }}
+ steps:
+ - uses: actions/checkout@v6
+ - uses: actions/setup-python@v6
+ - name: Install jq
+ run: |
+ sudo apt-get install --yes jq
+ - name: Install yq
+ run: |
+ pip install yq
+ - name: Generate SemVer
+ id: semantic-version
+ run: |
+ CHART_VERSION=$(yq -r '.version' helm/Chart.yaml)
+ if [ "${{ github.event_name }}" = "pull_request" ]; then
+ LOCAL_SEGMENT=+pr-${{ github.event.pull_request.number }}
+ elif [ "${{ github.ref_type }}" = "tag" ]; then
+ LOCAL_SEGMENT=""
+ else
+ SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
+ LOCAL_SEGMENT=+${SHORT_SHA}
+ fi
+ GENERATED_VERSION=${CHART_VERSION}${LOCAL_SEGMENT}
+ yq -Y -i ".version = \"$GENERATED_VERSION\"" helm/Chart.yaml
+ echo "generated-semver=$GENERATED_VERSION" >> $GITHUB_OUTPUT
+ - name: Chart | Push
+ uses: appany/helm-oci-chart-releaser@v0.5.0
+ with:
+ name: climate-ref-aft
+ repository: climate-ref/charts
+ tag: ${{ steps.semantic-version.outputs.generated-semver }}
+ path: helm
+ registry: ghcr.io
+ registry_username: ${{ github.actor }}
+ registry_password: ${{ secrets.GITHUB_TOKEN }}
+ update_dependencies: 'true'
+
+ test:
+ name: Test Helm Deployment
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ if: github.event_name == 'pull_request' && needs.changes.outputs.helm == 'true'
+ needs: [changes, helm]
+ steps:
+ - uses: actions/checkout@v6
+ - name: Cache Sample Data (Restore)
+ id: cache-sample-data-restore
+ uses: actions/cache/restore@v5
+ with:
+ path: ${{ github.workspace }}/cache/ref-config
+ key: ${{ runner.os }}-sample-data
+ enableCrossOsArchive: true
+ - name: Set permissions for cached data
+ run: |
+ sudo install -d --owner=1000 --group=1000 ${GITHUB_WORKSPACE}/cache/ref-config
+ - name: Start minikube
+ uses: medyagh/setup-minikube@latest
+ with:
+ mount-path: '${{ github.workspace }}/cache/ref-config:/cache/ref-config'
+ - name: Set up Helm
+ uses: azure/setup-helm@v4.3.1
+ - name: Install Chart
+ run: |
+ helm install test oci://ghcr.io/climate-ref/charts/climate-ref-aft \
+ --version=${{ needs.helm.outputs.generated-semver }} \
+ --set defaults.image.tag=pr-${{ github.event.pull_request.number }} \
+ -f helm/ci/gh-actions-values.yaml
+
+ sleep 60
+ kubectl get pods
+ echo ""
+ kubectl describe pod -l app.kubernetes.io/component=pmp
+ echo ""
+ kubectl logs -l app.kubernetes.io/component=pmp
+ - name: Run Migrations
+ run: |
+ kubectl exec deployment/test-climate-ref-aft-orchestrator -- ref config list
+ - name: Initialize Providers
+ run: |
+ # Imports ilamb3 which tries to create /home/app/.config/ilamb3 on import, no way to tell it to live somewhere else
+ # First, set up all providers without fetching data (handles conda envs)
+ kubectl exec deployment/test-climate-ref-aft-orchestrator -- ref providers setup --skip-data --skip-validate
+ # Fetch data for providers except esmvaltool (ERA5 data is too large for CI)
+ kubectl exec deployment/test-climate-ref-aft-orchestrator -- ref providers setup --provider pmp
+ kubectl exec deployment/test-climate-ref-aft-orchestrator -- ref providers setup --provider ilamb
+ - name: Fetch Test Data
+ run: |
+ kubectl exec deployment/test-climate-ref-aft-orchestrator -- ref datasets fetch-data --registry sample-data --output-directory /ref/sample-data
+
+ - name: Cache Sample Data (Save)
+ uses: actions/cache/save@v5
+ with:
+ path: ${{ github.workspace }}/cache/ref-config
+ key: ${{ runner.os }}-sample-data
+
+ - name: Ingest Test Data (CMIP6)
+ run: |
+ kubectl exec deployment/test-climate-ref-aft-orchestrator -- ref -v datasets ingest --source-type cmip6 /ref/sample-data/CMIP6
+ - name: Ingest Test Data (obs4mips)
+ run: |
+ kubectl exec deployment/test-climate-ref-aft-orchestrator -- ref -v datasets ingest --source-type obs4mips /ref/sample-data/obs4REF
+ - name: Simple Solve
+ run: |
+ # Use a fixed set of fast diagnostics to keep CI times predictable
+ kubectl exec deployment/test-climate-ref-aft-orchestrator -- ref -v solve --timeout 720 --one-per-provider \
+ --diagnostic global-mean-timeseries \
+ --diagnostic annual-cycle \
+ --diagnostic gpp-wecann
+ - name: Capture Worker Logs on Failure
+ if: failure()
+ run: |
+ echo "=== PMP Worker Logs ==="
+ kubectl logs -l app.kubernetes.io/component=pmp --tail=500 || true
+ echo ""
+ echo "=== ESMValTool Worker Logs ==="
+ kubectl logs -l app.kubernetes.io/component=esmvaltool --tail=500 || true
+ echo ""
+ echo "=== ILAMB Worker Logs ==="
+ kubectl logs -l app.kubernetes.io/component=ilamb --tail=500 || true
+ echo ""
+ echo "=== Example Worker Logs ==="
+ kubectl logs -l app.kubernetes.io/component=example --tail=500 || true
+ echo ""
+ echo "=== Orchestrator Worker Logs ==="
+ kubectl logs -l app.kubernetes.io/component=orchestrator --tail=500 || true
+ echo ""
+ echo "=== Flower Logs ==="
+ kubectl logs -l app.kubernetes.io/component=flower --tail=500 || true
+ echo ""
+ echo "=== Dragonfly Logs ==="
+ kubectl logs -l app.kubernetes.io/name=dragonfly --tail=500 || true
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0a2150f..d6718d9 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -34,7 +34,7 @@ jobs:
- name: Push chart
run: |
CHART_VERSION=$(grep '^version:' helm/Chart.yaml | awk '{print $2}')
- helm push ref-${CHART_VERSION}.tgz oci://ghcr.io/climate-ref/charts
+ helm push climate-ref-aft-${CHART_VERSION}.tgz oci://ghcr.io/climate-ref/charts
release:
name: GitHub Release
diff --git a/README.md b/README.md
index 61f9527..e83d40e 100644
--- a/README.md
+++ b/README.md
@@ -23,9 +23,11 @@ The AFT deployment brings together independently versioned packages:
| `climate-ref-core` | [Climate-REF/climate-ref](https://github.com/Climate-REF/climate-ref) | Core library with base classes and interfaces |
| `climate-ref` | [Climate-REF/climate-ref](https://github.com/Climate-REF/climate-ref) | Main application, CLI, database, solver |
| `climate-ref-celery` | [Climate-REF/climate-ref](https://github.com/Climate-REF/climate-ref) | Celery executor for distributed execution |
-| `climate-ref-esmvaltool` | [Climate-REF/climate-ref-esmvaltool](https://github.com/Climate-REF/climate-ref-esmvaltool) | ESMValTool diagnostic provider |
-| `climate-ref-pmp` | [Climate-REF/climate-ref-pmp](https://github.com/Climate-REF/climate-ref-pmp) | PCMDI Metrics Package diagnostic provider |
-| `climate-ref-ilamb` | [Climate-REF/climate-ref-ilamb](https://github.com/Climate-REF/climate-ref-ilamb) | ILAMB diagnostic provider |
+| `climate-ref-esmvaltool` | [Climate-REF/climate-ref](https://github.com/Climate-REF/climate-ref) | ESMValTool diagnostic provider |
+| `climate-ref-pmp` | [Climate-REF/climate-ref](https://github.com/Climate-REF/climate-ref) | PCMDI Metrics Package diagnostic provider |
+| `climate-ref-ilamb` | [Climate-REF/climate-ref](https://github.com/Climate-REF/climate-ref) | ILAMB diagnostic provider |
+
+Note: we intend to split the providers out into their own repositories in the coming weeks.
## Versioning
@@ -53,7 +55,7 @@ bash scripts/smoke-test.sh
helm install ref ./helm -f helm/local-test-values.yaml
# Or from the OCI registry
-helm install ref oci://ghcr.io/climate-ref/charts/ref --version 0.9.1
+helm install ref oci://ghcr.io/climate-ref/charts/climate-ref-aft --version 0.9.1
```
### Integration Tests
@@ -74,6 +76,7 @@ uv run pytest tests/ -v --slow
| Workflow | Trigger | What It Does |
|----------|---------|--------------|
| `ci.yml` | Push, PR | Lint, install pinned versions, run integration tests |
+| `packaging.yaml` | Push, PR | Helm chart OCI publish and minikube deployment test |
| `nightly.yml` | Scheduled (daily) | Test against latest versions of all components |
| `release.yml` | Tag push | Publish Helm chart, create GitHub release |
diff --git a/changelog/3.feature.md b/changelog/3.feature.md
new file mode 100644
index 0000000..0d9c409
--- /dev/null
+++ b/changelog/3.feature.md
@@ -0,0 +1 @@
+Add ref-app API component and Gateway API HTTPRoute support to the Helm chart.
diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml
index 8b074ae..e5ad9fe 100644
--- a/docker/docker-compose.yaml
+++ b/docker/docker-compose.yaml
@@ -26,6 +26,21 @@ services:
ports:
- "5432:5432"
+ ref-app:
+ image: ghcr.io/climate-ref/climate-ref-frontend:main
+ platform: linux/amd64
+ restart: always
+ depends_on:
+ - postgres
+ - redis
+ environment:
+ - REF_DATABASE_URL=postgresql://postgres:example@postgres:5432/postgres
+ - ENVIRONMENT=local
+ - SECRET_KEY=local-dev-secret
+ - REF_CONFIGURATION=/app/.ref
+ ports:
+ - "8000:8000"
+
flower:
image: mher/flower:2.0.1
restart: always
@@ -40,7 +55,8 @@ services:
# Base worker to track the executions of async tasks
climate-ref:
- image: ghcr.io/climate-ref/climate-ref:latest
+ image: ghcr.io/climate-ref/climate-ref:main
+ platform: linux/amd64
restart: always
depends_on:
- postgres
diff --git a/helm/Chart.yaml b/helm/Chart.yaml
index 016dc29..84a37e6 100644
--- a/helm/Chart.yaml
+++ b/helm/Chart.yaml
@@ -1,6 +1,6 @@
apiVersion: v2
-name: ref
-description: A Helm chart for Kubernetes
+name: climate-ref-aft
+description: A Helm chart for deploying the Climate REF application for the CMIP7 Assessment Fasttrack (AFT)
type: application
# This is the chart version. This version number should be incremented each time you make changes
diff --git a/helm/README.md b/helm/README.md
index 405e3d7..573af41 100644
--- a/helm/README.md
+++ b/helm/README.md
@@ -1,12 +1,17 @@
# Climate REF Helm Chart
A Helm chart for deploying the Climate REF (Rapid Evaluation Framework) on Kubernetes.
-This chart deploys a distributed task execution system using Celery workers for running climate diagnostics.
+This chart deploys the full stack:
+
+- the ref-app API/website
+- celery monitoring UI
+- distributed Celery workers for running climate diagnostics.
## Overview
The chart deploys:
+- **ref-app (API)**: FastAPI application serving the REST API and static React frontend
- **Dragonfly** (Redis-compatible): Message broker and result backend for Celery
- **Flower**: Web UI for monitoring Celery tasks
- **Provider Workers**: Celery workers for each diagnostic provider (orchestrator, esmvaltool, pmp, ilamb, example)
@@ -16,6 +21,7 @@ The chart deploys:
- Kubernetes 1.19+
- Helm 3.0+
- Access to container images:
+ - `ghcr.io/climate-ref/ref-app`
- `ghcr.io/climate-ref/climate-ref`
- `mher/flower`
@@ -57,9 +63,12 @@ helm dependency update
```mermaid
flowchart TB
- ingress[Ingress
optional]
+ apiIngress[API Ingress
optional]
+ flowerIngress[Flower Ingress
optional]
+ api[ref-app
API + frontend]
flower[Flower
monitoring]
dragonfly[Dragonfly
Redis broker]
+ db[(PostgreSQL
external)]
subgraph workers[Provider Workers]
orchestrator[Orchestrator
Worker]
@@ -70,7 +79,9 @@ flowchart TB
pvcs[(PVCs
shared data storage)]
- ingress --> flower
+ apiIngress --> api
+ flowerIngress --> flower
+ api --> db
flower --> dragonfly
dragonfly --> orchestrator
dragonfly --> esmvaltool
@@ -104,15 +115,55 @@ Each provider worker listens to a specific Celery queue:
| `nameOverride` | Override chart name | `""` |
| `fullnameOverride` | Override full release name | `""` |
-### Ingress Configuration
-
-| Parameter | Description | Default |
-| --------------------- | ------------------- | ------- |
-| `ingress.enabled` | Enable ingress | `false` |
-| `ingress.host` | Ingress hostname | `""` |
-| `ingress.className` | Ingress class name | `""` |
-| `ingress.annotations` | Ingress annotations | `{}` |
-| `ingress.labels` | Ingress labels | `{}` |
+### API Configuration
+
+The `api` section configures the ref-app (FastAPI + React frontend).
+
+| Parameter | Description | Default |
+| --------------------------------- | --------------------------- | --------------------------------- |
+| `api.enabled` | Enable the API deployment | `true` |
+| `api.replicaCount` | Number of API replicas | `1` |
+| `api.image.repository` | API image repository | `ghcr.io/climate-ref/ref-app` |
+| `api.image.tag` | API image tag | `latest` |
+| `api.image.pullPolicy` | Image pull policy | `IfNotPresent` |
+| `api.service.type` | Service type | `ClusterIP` |
+| `api.service.port` | Service port | `80` |
+| `api.resources` | Resource requests/limits | `{}` |
+| `api.nodeSelector` | Node selector | `{}` |
+| `api.tolerations` | Tolerations | `[]` |
+| `api.affinity` | Affinity rules | `{}` |
+
+#### API Environment Variables
+
+Set via `api.env`:
+
+| Variable | Description | Default |
+| ------------------- | ------------------------------ | --------------------------------- |
+| `ENVIRONMENT` | Runtime environment | `production` |
+| `LOG_LEVEL` | Logging level | `INFO` |
+| `SECRET_KEY` | Application secret key | `changethis` (override in prod!) |
+| `REF_DATABASE_URL` | Database connection string | `""` (required) |
+| `REF_CONFIGURATION` | Path to REF configuration | `/app/.ref` |
+
+#### API Ingress
+
+| Parameter | Description | Default |
+| -------------------------- | ------------------- | ------- |
+| `api.ingress.enabled` | Enable API ingress | `false` |
+| `api.ingress.host` | Ingress hostname | `""` |
+| `api.ingress.className` | Ingress class name | `""` |
+| `api.ingress.annotations` | Ingress annotations | `{}` |
+| `api.ingress.labels` | Ingress labels | `{}` |
+
+#### API HTTPRoute (Gateway API)
+
+| Parameter | Description | Default |
+| ---------------------------- | ---------------------------- | ------- |
+| `api.httpRoute.enabled` | Enable API HTTPRoute | `false` |
+| `api.httpRoute.hostnames` | List of hostnames to match | `[]` |
+| `api.httpRoute.parentRefs` | Gateway parent references | `[]` |
+| `api.httpRoute.annotations` | HTTPRoute annotations | `{}` |
+| `api.httpRoute.labels` | HTTPRoute labels | `{}` |
### Dragonfly (Redis) Configuration
@@ -139,6 +190,26 @@ See [Dragonfly Helm chart](https://github.com/dragonflydb/dragonfly/tree/main/co
| `flower.tolerations` | Tolerations | `[]` |
| `flower.affinity` | Affinity rules | `{}` |
+#### Flower Ingress
+
+| Parameter | Description | Default |
+| ----------------------------- | ----------------------- | ------- |
+| `flower.ingress.enabled` | Enable Flower ingress | `false` |
+| `flower.ingress.host` | Ingress hostname | `""` |
+| `flower.ingress.className` | Ingress class name | `""` |
+| `flower.ingress.annotations` | Ingress annotations | `{}` |
+| `flower.ingress.labels` | Ingress labels | `{}` |
+
+#### Flower HTTPRoute (Gateway API)
+
+| Parameter | Description | Default |
+| ------------------------------- | ---------------------------- | ------- |
+| `flower.httpRoute.enabled` | Enable Flower HTTPRoute | `false` |
+| `flower.httpRoute.hostnames` | List of hostnames to match | `[]` |
+| `flower.httpRoute.parentRefs` | Gateway parent references | `[]` |
+| `flower.httpRoute.annotations` | HTTPRoute annotations | `{}` |
+| `flower.httpRoute.labels` | HTTPRoute labels | `{}` |
+
### Provider Defaults
These defaults apply to all providers unless overridden per-provider.
@@ -279,17 +350,32 @@ kubectl port-forward svc/ref-flower 5555:5555
Open in your browser.
+### Accessing the API
+
+Access the ref-app API:
+
+```bash
+kubectl port-forward svc/ref-api 8000:80
+```
+
+Open in your browser, or check the health endpoint:
+
+```bash
+curl http://localhost:8000/api/v1/utils/health-check/
+```
+
## Resources Created
The chart creates the following Kubernetes resources:
-| Resource | Count | Description |
-| ----------------------- | --------------- | -------------------------------- |
-| Deployment | 1 + N providers | Flower + one per provider |
-| Service | 2 | Flower + Dragonfly |
-| ServiceAccount | 1 + N providers | Flower + one per provider |
-| Secret | 1 + N providers | Environment config per component |
-| ServiceMonitor | 0-1 | Optional Prometheus integration |
-| HorizontalPodAutoscaler | 0-N | Optional per-provider |
-| PersistentVolumeClaim | N | As configured in createPVCs |
-| Ingress | 0-1 | Optional |
+| Resource | Count | Description |
+| ----------------------- | --------------- | ---------------------------------- |
+| Deployment | 2 + N providers | API + Flower + one per provider |
+| Service | 3 | API + Flower + Dragonfly |
+| ServiceAccount | 2 + N providers | API + Flower + one per provider |
+| Secret | 2 + N providers | Environment config per component |
+| ServiceMonitor | 0-1 | Optional Prometheus integration |
+| HorizontalPodAutoscaler | 0-N | Optional per-provider |
+| PersistentVolumeClaim | N | As configured in createPVCs |
+| Ingress | 0-2 | Optional API and/or Flower ingress |
+| HTTPRoute | 0-2 | Optional Gateway API routes |
diff --git a/helm/ci/gh-actions-values.yaml b/helm/ci/gh-actions-values.yaml
index c13a40a..d7318ea 100644
--- a/helm/ci/gh-actions-values.yaml
+++ b/helm/ci/gh-actions-values.yaml
@@ -1,5 +1,14 @@
-ingress:
- host: Climate-ref.test
+api:
+ env:
+ SECRET_KEY: ci-test-secret
+ REF_DATABASE_URL: sqlite:////tmp/ref.db
+ volumes:
+ - name: tmp
+ emptyDir: {}
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ readOnly: false
service:
type: NodePort
diff --git a/helm/local-test-values.yaml b/helm/local-test-values.yaml
index 8809004..44ceebe 100644
--- a/helm/local-test-values.yaml
+++ b/helm/local-test-values.yaml
@@ -4,7 +4,7 @@ defaults:
image:
repository: ghcr.io/climate-ref/climate-ref
pullPolicy: IfNotPresent
- tag: pr-492 # Using current PR tag
+ tag: latest
podSecurityContext:
runAsUser: 1000
@@ -52,3 +52,19 @@ providers:
pmp: {}
ilamb: {}
example: {}
+
+api:
+ image:
+ tag: latest
+ env:
+ ENVIRONMENT: local
+ SECRET_KEY: local-test-secret
+ REF_DATABASE_URL: sqlite:////tmp/ref.db
+ REF_CONFIGURATION: /app/.ref
+ volumes:
+ - name: tmp
+ emptyDir: {}
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ readOnly: false
diff --git a/helm/templates/api/deployment.yaml b/helm/templates/api/deployment.yaml
new file mode 100644
index 0000000..162c035
--- /dev/null
+++ b/helm/templates/api/deployment.yaml
@@ -0,0 +1,80 @@
+{{- if .Values.api.enabled -}}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ include "ref.fullname" . }}-api
+ labels:
+ app.kubernetes.io/component: api
+ {{- include "ref.labels" . | nindent 4 }}
+spec:
+ replicas: {{ .Values.api.replicaCount }}
+ selector:
+ matchLabels:
+ app.kubernetes.io/component: api
+ {{- include "ref.selectorLabels" . | nindent 6 }}
+ template:
+ metadata:
+ annotations:
+ checksum/config: {{ include (print $.Template.BasePath "/api/secret.yaml") . | sha256sum }}
+ {{- with .Values.api.podAnnotations }}
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ labels:
+ app.kubernetes.io/component: api
+ {{- include "ref.labels" . | nindent 8 }}
+ {{- with .Values.api.podLabels }}
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ spec:
+ {{- with .Values.imagePullSecrets }}
+ imagePullSecrets:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ serviceAccountName: {{ include "ref.fullname" . }}-api
+ {{- with .Values.api.podSecurityContext }}
+ securityContext:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ containers:
+ - name: api
+ {{- with .Values.api.securityContext }}
+ securityContext:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ image: "{{ .Values.api.image.repository }}:{{ .Values.api.image.tag }}"
+ imagePullPolicy: {{ .Values.api.image.pullPolicy }}
+ envFrom:
+ - secretRef:
+ name: {{ include "ref.fullname" . }}-api
+ ports:
+ - name: http
+ containerPort: 8000
+ readinessProbe:
+ httpGet:
+ path: /api/v1/utils/health-check/
+ port: http
+ {{- with .Values.api.resources }}
+ resources:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ {{- with .Values.api.volumeMounts }}
+ volumeMounts:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ {{- with .Values.api.volumes }}
+ volumes:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.api.nodeSelector }}
+ nodeSelector:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.api.affinity }}
+ affinity:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.api.tolerations }}
+ tolerations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+{{- end }}
diff --git a/helm/templates/api/httproute.yaml b/helm/templates/api/httproute.yaml
new file mode 100644
index 0000000..6fec81e
--- /dev/null
+++ b/helm/templates/api/httproute.yaml
@@ -0,0 +1,33 @@
+{{- if and .Values.api.enabled .Values.api.httpRoute.enabled -}}
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+ name: {{ include "ref.fullname" . }}-api
+ labels:
+ app.kubernetes.io/component: api
+ {{- include "ref.labels" . | nindent 4 }}
+ {{- with .Values.api.httpRoute.labels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ {{- with .Values.api.httpRoute.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ {{- with .Values.api.httpRoute.parentRefs }}
+ parentRefs:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ {{- with .Values.api.httpRoute.hostnames }}
+ hostnames:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ rules:
+ - matches:
+ - path:
+ type: PathPrefix
+ value: /
+ backendRefs:
+ - name: {{ include "ref.fullname" . }}-api
+ port: {{ .Values.api.service.port }}
+{{- end }}
diff --git a/helm/templates/api/ingress.yaml b/helm/templates/api/ingress.yaml
new file mode 100644
index 0000000..b3f1058
--- /dev/null
+++ b/helm/templates/api/ingress.yaml
@@ -0,0 +1,35 @@
+{{- if and .Values.api.enabled .Values.api.ingress.enabled -}}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: {{ include "ref.fullname" . }}-api
+ labels:
+ app.kubernetes.io/component: api
+ {{- include "ref.labels" . | nindent 4 }}
+ {{- with .Values.api.ingress.labels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ {{- with .Values.api.ingress.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ {{- with .Values.api.ingress.className }}
+ ingressClassName: {{ . }}
+ {{- end }}
+ tls:
+ - hosts:
+ - {{ .Values.api.ingress.host | quote }}
+ secretName: {{ include "ref.fullname" . }}-api-ingress-cert
+ rules:
+ - host: {{ .Values.api.ingress.host | quote }}
+ http:
+ paths:
+ - path: /
+ pathType: ImplementationSpecific
+ backend:
+ service:
+ name: {{ include "ref.fullname" . }}-api
+ port:
+ number: {{ .Values.api.service.port }}
+{{- end }}
diff --git a/helm/templates/api/secret.yaml b/helm/templates/api/secret.yaml
new file mode 100644
index 0000000..a3b831f
--- /dev/null
+++ b/helm/templates/api/secret.yaml
@@ -0,0 +1,11 @@
+{{- if .Values.api.enabled -}}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ include "ref.fullname" . }}-api
+ labels:
+ app.kubernetes.io/component: api
+ {{- include "ref.labels" . | nindent 4 }}
+stringData:
+ {{- tpl (toYaml .Values.api.env) . | nindent 2}}
+{{- end }}
diff --git a/helm/templates/api/service.yaml b/helm/templates/api/service.yaml
new file mode 100644
index 0000000..0452521
--- /dev/null
+++ b/helm/templates/api/service.yaml
@@ -0,0 +1,19 @@
+{{- if .Values.api.enabled -}}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ include "ref.fullname" . }}-api
+ labels:
+ app.kubernetes.io/component: api
+ {{- include "ref.labels" . | nindent 4 }}
+spec:
+ type: {{ .Values.api.service.type }}
+ ports:
+ - port: {{ .Values.api.service.port }}
+ targetPort: http
+ protocol: TCP
+ name: http
+ selector:
+ app.kubernetes.io/component: api
+ {{- include "ref.selectorLabels" . | nindent 4 }}
+{{- end }}
diff --git a/helm/templates/api/serviceaccount.yaml b/helm/templates/api/serviceaccount.yaml
new file mode 100644
index 0000000..074d043
--- /dev/null
+++ b/helm/templates/api/serviceaccount.yaml
@@ -0,0 +1,14 @@
+{{- if and .Values.api.enabled .Values.api.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ include "ref.fullname" . }}-api
+ labels:
+ app.kubernetes.io/component: api
+ {{- include "ref.labels" . | nindent 4 }}
+ {{- with .Values.api.serviceAccount.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+automountServiceAccountToken: {{ .Values.api.serviceAccount.automount }}
+{{- end }}
diff --git a/helm/templates/flower/httproute.yaml b/helm/templates/flower/httproute.yaml
new file mode 100644
index 0000000..6f194a0
--- /dev/null
+++ b/helm/templates/flower/httproute.yaml
@@ -0,0 +1,33 @@
+{{- if .Values.flower.httpRoute.enabled -}}
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+ name: {{ include "ref.fullname" . }}-flower
+ labels:
+ app.kubernetes.io/component: flower
+ {{- include "ref.labels" . | nindent 4 }}
+ {{- with .Values.flower.httpRoute.labels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ {{- with .Values.flower.httpRoute.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ {{- with .Values.flower.httpRoute.parentRefs }}
+ parentRefs:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ {{- with .Values.flower.httpRoute.hostnames }}
+ hostnames:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ rules:
+ - matches:
+ - path:
+ type: PathPrefix
+ value: /
+ backendRefs:
+ - name: {{ include "ref.fullname" . }}-flower
+ port: {{ .Values.flower.service.port }}
+{{- end }}
diff --git a/helm/templates/ingress.yaml b/helm/templates/flower/ingress.yaml
similarity index 55%
rename from helm/templates/ingress.yaml
rename to helm/templates/flower/ingress.yaml
index 4e87201..fa83e3f 100644
--- a/helm/templates/ingress.yaml
+++ b/helm/templates/flower/ingress.yaml
@@ -1,27 +1,28 @@
-{{- if .Values.ingress.enabled -}}
+{{- if .Values.flower.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
- name: {{ include "ref.fullname" . }}
+ name: {{ include "ref.fullname" . }}-flower
labels:
+ app.kubernetes.io/component: flower
{{- include "ref.labels" . | nindent 4 }}
- {{- with .Values.ingress.labels }}
+ {{- with .Values.flower.ingress.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
- {{- with .Values.ingress.annotations }}
+ {{- with .Values.flower.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
- {{- with .Values.ingress.className }}
+ {{- with .Values.flower.ingress.className }}
ingressClassName: {{ . }}
{{- end }}
tls:
- hosts:
- - {{ .Values.ingress.host | quote }}
- secretName: {{ include "ref.fullname" . }}-ingress-cert
+ - {{ .Values.flower.ingress.host | quote }}
+ secretName: {{ include "ref.fullname" . }}-flower-ingress-cert
rules:
- - host: {{ .Values.ingress.host | quote }}
+ - host: {{ .Values.flower.ingress.host | quote }}
http:
paths:
- path: /
diff --git a/helm/values.yaml b/helm/values.yaml
index b084e9b..ee70d0f 100644
--- a/helm/values.yaml
+++ b/helm/values.yaml
@@ -2,14 +2,65 @@ imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
-ingress:
- enabled: false
- host:
- className: ""
- annotations: {}
- # kubernetes.io/ingress.class: nginx
- # kubernetes.io/tls-acme: "true"
- labels: {}
+api:
+ enabled: true
+ replicaCount: 1
+
+ image:
+ repository: ghcr.io/climate-ref/climate-ref-frontend
+ pullPolicy: IfNotPresent
+ tag: main
+
+ env:
+ ENVIRONMENT: production
+ LOG_LEVEL: INFO
+ SECRET_KEY: changethis # Must override in production
+ REF_DATABASE_URL: "" # Required: e.g. postgresql://user:pass@host:5432/db
+ REF_CONFIGURATION: /app/.ref
+
+ ingress:
+ enabled: false
+ host:
+ className: ""
+ annotations: {}
+ labels: {}
+
+ httpRoute:
+ enabled: false
+ hostnames: []
+ parentRefs: []
+ annotations: {}
+ labels: {}
+
+ serviceAccount:
+ create: true
+ automount: false
+ annotations: {}
+ name: ""
+
+ podAnnotations: {}
+ podLabels: {}
+
+ podSecurityContext: {}
+
+ securityContext:
+ capabilities:
+ drop:
+ - ALL
+ readOnlyRootFilesystem: true
+ runAsNonRoot: true
+
+ service:
+ type: ClusterIP
+ port: 80
+
+ resources: {}
+
+ volumes: []
+ volumeMounts: []
+ nodeSelector: {}
+ tolerations: []
+ affinity: {}
dragonfly:
storage:
@@ -20,6 +71,20 @@ flower:
CELERY_BROKER_URL: redis://{{ include "dragonfly.fullname" .Subcharts.dragonfly }}:{{ .Values.dragonfly.service.port }}
CELERY_RESULT_BACKEND: redis://{{ include "dragonfly.fullname" .Subcharts.dragonfly }}:{{ .Values.dragonfly.service.port }}
+ ingress:
+ enabled: false
+ host:
+ className: ""
+ annotations: {}
+ labels: {}
+
+ httpRoute:
+ enabled: false
+ hostnames: []
+ parentRefs: []
+ annotations: {}
+ labels: {}
+
serviceMonitor:
enabled: false