Merge pull request #62 from offendingcommit/worktree-feat+helm-chart
feat(helm): add Helm chart for self-hosted openconcho web UI
This commit is contained in:
31
.github/workflows/docker-publish.yml
vendored
31
.github/workflows/docker-publish.yml
vendored
@@ -44,3 +44,34 @@ jobs:
|
|||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
publish-chart:
|
||||||
|
name: Package & push Helm chart to GHCR
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [publish]
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: azure/setup-helm@v4
|
||||||
|
|
||||||
|
- name: Derive chart version
|
||||||
|
id: version
|
||||||
|
run: echo "VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Log in to GHCR (Helm OCI)
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io \
|
||||||
|
--username "${{ github.actor }}" \
|
||||||
|
--password-stdin
|
||||||
|
|
||||||
|
- name: Package chart
|
||||||
|
run: |
|
||||||
|
helm package charts/openconcho \
|
||||||
|
--version "${{ steps.version.outputs.VERSION }}" \
|
||||||
|
--app-version "${{ steps.version.outputs.VERSION }}"
|
||||||
|
|
||||||
|
- name: Push chart
|
||||||
|
run: |
|
||||||
|
helm push "openconcho-${{ steps.version.outputs.VERSION }}.tgz" \
|
||||||
|
oci://ghcr.io/${{ github.repository_owner }}/charts
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ Frontend UI for self-hosted Honcho instances — browse memories, peers, session
|
|||||||
| `packages/web/src/test/` | Vitest unit/integration tests + setup |
|
| `packages/web/src/test/` | Vitest unit/integration tests + setup |
|
||||||
| `packages/web/e2e/` | Playwright e2e specs |
|
| `packages/web/e2e/` | Playwright e2e specs |
|
||||||
| `packages/desktop/` | Tauri shell that bundles the built web app |
|
| `packages/desktop/` | Tauri shell that bundles the built web app |
|
||||||
|
| `charts/openconcho/` | Helm 3 chart for self-hosting on Kubernetes (OCI artifact on GHCR) |
|
||||||
| `.claude/rules/` | Coding conventions (auto-loaded; stack-agnostic, applies to all agents) |
|
| `.claude/rules/` | Coding conventions (auto-loaded; stack-agnostic, applies to all agents) |
|
||||||
| `docs/` | Architecture and references |
|
| `docs/` | Architecture and references |
|
||||||
|
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -114,6 +114,34 @@ profiles: `make up` runs the `dev` profile (`build: .`), `make prod` runs the
|
|||||||
(comma-separated host globs) for when you expose the proxy. Full details and env
|
(comma-separated host globs) for when you expose the proxy. Full details and env
|
||||||
vars are in [`docs/docker.md`](docs/docker.md).
|
vars are in [`docs/docker.md`](docs/docker.md).
|
||||||
|
|
||||||
|
### Kubernetes (Helm)
|
||||||
|
|
||||||
|
The chart is published as an OCI artifact to GHCR on every tagged release.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install openconcho oci://ghcr.io/offendingcommit/charts/openconcho \
|
||||||
|
--version 0.14.0 \
|
||||||
|
--create-namespace --namespace openconcho \
|
||||||
|
--set honcho.defaultUrl=https://honcho.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Enable an Ingress and TLS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install openconcho oci://ghcr.io/offendingcommit/charts/openconcho \
|
||||||
|
--version 0.14.0 \
|
||||||
|
--create-namespace --namespace openconcho \
|
||||||
|
--set honcho.defaultUrl=https://honcho.example.com \
|
||||||
|
--set ingress.enabled=true \
|
||||||
|
--set ingress.className=nginx \
|
||||||
|
--set 'ingress.hosts[0].host=openconcho.example.com' \
|
||||||
|
--set 'ingress.hosts[0].paths[0].path=/' \
|
||||||
|
--set 'ingress.tls[0].secretName=openconcho-tls' \
|
||||||
|
--set 'ingress.tls[0].hosts[0]=openconcho.example.com'
|
||||||
|
```
|
||||||
|
|
||||||
|
Full chart documentation, configuration reference, and an ArgoCD Application example are in [`charts/openconcho/README.md`](charts/openconcho/README.md).
|
||||||
|
|
||||||
### Connecting to your instance
|
### Connecting to your instance
|
||||||
|
|
||||||
1. Enter the base URL of your Honcho instance (e.g. `http://localhost:8000`)
|
1. Enter the base URL of your Honcho instance (e.g. `http://localhost:8000`)
|
||||||
|
|||||||
16
charts/openconcho/Chart.yaml
Normal file
16
charts/openconcho/Chart.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: openconcho
|
||||||
|
description: Self-hosted UI for Honcho — browse memories, peers, sessions, conclusions, and chat with memory context.
|
||||||
|
type: application
|
||||||
|
version: 0.14.0
|
||||||
|
appVersion: "0.14.0"
|
||||||
|
keywords:
|
||||||
|
- honcho
|
||||||
|
- memory
|
||||||
|
- ai
|
||||||
|
home: https://github.com/offendingcommit/openconcho
|
||||||
|
sources:
|
||||||
|
- https://github.com/offendingcommit/openconcho
|
||||||
|
maintainers:
|
||||||
|
- name: offendingcommit
|
||||||
|
url: https://github.com/offendingcommit
|
||||||
229
charts/openconcho/README.md
Normal file
229
charts/openconcho/README.md
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
# openconcho Helm Chart
|
||||||
|
|
||||||
|
Helm 3 chart for self-hosting the [openconcho](https://github.com/offendingcommit/openconcho) web UI on Kubernetes.
|
||||||
|
|
||||||
|
The chart deploys a single nginx-unprivileged container (port 8080, UID 101) that serves the React SPA and reverse-proxies Honcho API calls under `/api` to avoid browser CORS issues.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes 1.25+
|
||||||
|
- Helm 3.10+
|
||||||
|
- A running [Honcho](https://github.com/plastic-labs/honcho) instance reachable from within the cluster (or via a configured ingress)
|
||||||
|
|
||||||
|
## Installing
|
||||||
|
|
||||||
|
Add the chart repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm registry login ghcr.io --username <github-username> --password <github-token>
|
||||||
|
```
|
||||||
|
|
||||||
|
Install the chart:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install openconcho oci://ghcr.io/offendingcommit/charts/openconcho \
|
||||||
|
--version 0.14.0 \
|
||||||
|
--set honcho.defaultUrl=https://honcho.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with a values file (recommended):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install openconcho oci://ghcr.io/offendingcommit/charts/openconcho \
|
||||||
|
--version 0.14.0 \
|
||||||
|
-f my-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Upgrading
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade openconcho oci://ghcr.io/offendingcommit/charts/openconcho \
|
||||||
|
--version <new-version> \
|
||||||
|
-f my-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uninstalling
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm uninstall openconcho
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
All values with their defaults are documented in [`values.yaml`](values.yaml). Key options:
|
||||||
|
|
||||||
|
| Value | Default | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `replicaCount` | `1` | Number of pod replicas |
|
||||||
|
| `image.repository` | `ghcr.io/offendingcommit/openconcho-web` | Container image |
|
||||||
|
| `image.tag` | `""` | Tag; defaults to chart `appVersion` |
|
||||||
|
| `image.pullPolicy` | `IfNotPresent` | Image pull policy |
|
||||||
|
| `honcho.defaultUrl` | `""` | Honcho URL pre-seeded in the UI |
|
||||||
|
| `honcho.upstreamAllowlist` | `""` | SSRF guard (comma-separated host globs) |
|
||||||
|
| `service.type` | `ClusterIP` | `ClusterIP` / `NodePort` / `LoadBalancer` |
|
||||||
|
| `service.port` | `80` | Service port |
|
||||||
|
| `ingress.enabled` | `false` | Enable Ingress resource |
|
||||||
|
| `ingress.className` | `""` | IngressClass name |
|
||||||
|
| `autoscaling.enabled` | `false` | Enable HorizontalPodAutoscaler |
|
||||||
|
| `podDisruptionBudget.enabled` | `false` | Enable PodDisruptionBudget |
|
||||||
|
| `networkPolicy.enabled` | `false` | Enable NetworkPolicy (same-namespace only) |
|
||||||
|
| `resources.requests.memory` | `32Mi` | Memory request |
|
||||||
|
| `resources.limits.memory` | `128Mi` | Memory limit |
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Minimal (ClusterIP, no ingress)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
honcho:
|
||||||
|
defaultUrl: http://honcho.honcho.svc.cluster.local:8000
|
||||||
|
```
|
||||||
|
|
||||||
|
### With Ingress and TLS (cert-manager)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
honcho:
|
||||||
|
defaultUrl: https://honcho.example.com
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: nginx
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
hosts:
|
||||||
|
- host: openconcho.example.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: openconcho-tls
|
||||||
|
hosts:
|
||||||
|
- openconcho.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### With autoscaling and disruption budget
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
replicaCount: 2
|
||||||
|
|
||||||
|
autoscaling:
|
||||||
|
enabled: true
|
||||||
|
minReplicas: 2
|
||||||
|
maxReplicas: 10
|
||||||
|
targetCPUUtilizationPercentage: 70
|
||||||
|
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: true
|
||||||
|
minAvailable: 1
|
||||||
|
```
|
||||||
|
|
||||||
|
### With NetworkPolicy
|
||||||
|
|
||||||
|
> **Note:** When `networkPolicy.enabled=true` and `ingress.enabled=true`, you must add
|
||||||
|
> a policy that allows traffic from the ingress-controller namespace. Run
|
||||||
|
> `helm status <release>` for the exact `kubectl edit` command after install.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
networkPolicy:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: nginx
|
||||||
|
hosts:
|
||||||
|
- host: openconcho.example.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
```
|
||||||
|
|
||||||
|
### Private registry
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
image:
|
||||||
|
repository: registry.example.com/myorg/openconcho-web
|
||||||
|
tag: "0.14.0"
|
||||||
|
pullPolicy: Always
|
||||||
|
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: registry-credentials
|
||||||
|
```
|
||||||
|
|
||||||
|
## ArgoCD Application
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: openconcho
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: ghcr.io/offendingcommit/charts
|
||||||
|
chart: openconcho
|
||||||
|
targetRevision: 0.14.0
|
||||||
|
helm:
|
||||||
|
valuesObject:
|
||||||
|
honcho:
|
||||||
|
defaultUrl: https://honcho.example.com
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: nginx
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
hosts:
|
||||||
|
- host: openconcho.example.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: openconcho-tls
|
||||||
|
hosts:
|
||||||
|
- openconcho.example.com
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: openconcho
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
```
|
||||||
|
|
||||||
|
> OCI chart sources require ArgoCD 2.10+ (OCI Helm support GA).
|
||||||
|
|
||||||
|
## Helm tests
|
||||||
|
|
||||||
|
After install, run the bundled tests to verify the deployment is healthy:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm test openconcho
|
||||||
|
```
|
||||||
|
|
||||||
|
Two test pods run and exit 0 on success:
|
||||||
|
|
||||||
|
| Test | What it checks |
|
||||||
|
|---|---|
|
||||||
|
| `test-healthz` | `GET /healthz` body equals `ok` |
|
||||||
|
| `test-spa-root` | `GET /` returns HTTP 200 |
|
||||||
|
|
||||||
|
Pass `--logs` to see output from failing pods:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm test openconcho --logs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security posture
|
||||||
|
|
||||||
|
| Control | Value |
|
||||||
|
|---|---|
|
||||||
|
| Run as UID/GID | 101 (nginx-unprivileged) |
|
||||||
|
| `runAsNonRoot` | `true` |
|
||||||
|
| `readOnlyRootFilesystem` | `true` |
|
||||||
|
| Linux capabilities | all dropped |
|
||||||
|
| `seccompProfile` | `RuntimeDefault` |
|
||||||
|
| `allowPrivilegeEscalation` | `false` |
|
||||||
|
| `automountServiceAccountToken` | `false` |
|
||||||
|
| Writable paths | `/var/cache/nginx`, `/var/run`, `/tmp` (tmpfs) |
|
||||||
40
charts/openconcho/templates/NOTES.txt
Normal file
40
charts/openconcho/templates/NOTES.txt
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
OpenConcho {{ .Chart.AppVersion }} deployed to namespace {{ .Release.Namespace }}.
|
||||||
|
|
||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
Access:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .host }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else if eq .Values.service.type "NodePort" }}
|
||||||
|
Access (NodePort):
|
||||||
|
export NODE_PORT=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "openconcho.fullname" . }} -o jsonpath="{.spec.ports[0].nodePort}")
|
||||||
|
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||||
|
echo "http://$NODE_IP:$NODE_PORT"
|
||||||
|
{{- else if eq .Values.service.type "LoadBalancer" }}
|
||||||
|
Access (LoadBalancer — IP may take a few minutes):
|
||||||
|
export LB_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "openconcho.fullname" . }} --template '{{ "{{" }}range (index .status.loadBalancer.ingress 0){{ "}}" }}{{ "{{" }}.{{ "}}" }}{{ "{{" }}end{{ "}}" }}')
|
||||||
|
echo "http://$LB_IP:{{ .Values.service.port }}"
|
||||||
|
{{- else }}
|
||||||
|
Access (port-forward):
|
||||||
|
kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "openconcho.fullname" . }} 8080:{{ .Values.service.port }}
|
||||||
|
Then open http://localhost:8080
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
Run Helm tests to verify the deployment:
|
||||||
|
helm test {{ .Release.Name }}
|
||||||
|
|
||||||
|
{{- if and .Values.networkPolicy.enabled .Values.ingress.enabled }}
|
||||||
|
|
||||||
|
WARNING: NetworkPolicy + Ingress are both enabled.
|
||||||
|
The default NetworkPolicy allows port {{ .Values.service.containerPort }} only from pods within
|
||||||
|
namespace {{ .Release.Namespace }}. Ingress controllers typically run in a separate
|
||||||
|
namespace (ingress-nginx, kube-system, etc.) and will be blocked.
|
||||||
|
To allow ingress-controller traffic, add a namespaceSelector rule:
|
||||||
|
|
||||||
|
kubectl edit networkpolicy --namespace {{ .Release.Namespace }} {{ include "openconcho.fullname" . }}
|
||||||
|
|
||||||
|
# Under spec.ingress[0].from, add:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: <ingress-controller-namespace>
|
||||||
|
{{- end }}
|
||||||
46
charts/openconcho/templates/_helpers.tpl
Normal file
46
charts/openconcho/templates/_helpers.tpl
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{{- define "openconcho.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "openconcho.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride }}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "openconcho.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "openconcho.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "openconcho.chart" . }}
|
||||||
|
{{ include "openconcho.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "openconcho.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "openconcho.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "openconcho.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "openconcho.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "openconcho.imageTag" -}}
|
||||||
|
{{- .Values.image.tag | default .Chart.AppVersion }}
|
||||||
|
{{- end }}
|
||||||
84
charts/openconcho/templates/deployment.yaml
Normal file
84
charts/openconcho/templates/deployment.yaml
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "openconcho.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "openconcho.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
{{- if not .Values.autoscaling.enabled }}
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "openconcho.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "openconcho.selectorLabels" . | nindent 8 }}
|
||||||
|
{{- with .Values.podLabels }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "openconcho.serviceAccountName" . }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ include "openconcho.imageTag" . }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.service.containerPort }}
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: OPENCONCHO_DEFAULT_HONCHO_URL
|
||||||
|
value: {{ .Values.honcho.defaultUrl | quote }}
|
||||||
|
- name: OPENCONCHO_UPSTREAM_ALLOWLIST
|
||||||
|
value: {{ .Values.honcho.upstreamAllowlist | quote }}
|
||||||
|
livenessProbe:
|
||||||
|
{{- toYaml .Values.livenessProbe | nindent 12 }}
|
||||||
|
readinessProbe:
|
||||||
|
{{- toYaml .Values.readinessProbe | nindent 12 }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
{{- if .Values.tmpfsMounts }}
|
||||||
|
volumeMounts:
|
||||||
|
{{- range .Values.tmpfsMounts }}
|
||||||
|
- name: {{ .mountPath | trimPrefix "/" | replace "/" "-" | trunc 63 | trimSuffix "-" }}
|
||||||
|
mountPath: {{ .mountPath }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.tmpfsMounts }}
|
||||||
|
volumes:
|
||||||
|
{{- range .Values.tmpfsMounts }}
|
||||||
|
- name: {{ .mountPath | trimPrefix "/" | replace "/" "-" | trunc 63 | trimSuffix "-" }}
|
||||||
|
emptyDir:
|
||||||
|
medium: Memory
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.topologySpreadConstraints }}
|
||||||
|
topologySpreadConstraints:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
24
charts/openconcho/templates/hpa.yaml
Normal file
24
charts/openconcho/templates/hpa.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{{- if .Values.autoscaling.enabled }}
|
||||||
|
apiVersion: autoscaling/v2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: {{ include "openconcho.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "openconcho.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: {{ include "openconcho.fullname" . }}
|
||||||
|
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||||
|
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||||
|
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||||
|
metrics:
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
39
charts/openconcho/templates/ingress.yaml
Normal file
39
charts/openconcho/templates/ingress.yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{{- if .Values.ingress.enabled -}}
|
||||||
|
{{- $fullName := include "openconcho.fullname" . -}}
|
||||||
|
{{- $svcPort := .Values.service.port -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
labels:
|
||||||
|
{{- include "openconcho.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- toYaml .Values.ingress.tls | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.ingress.hosts }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType | default "Prefix" }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
port:
|
||||||
|
number: {{ $svcPort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
20
charts/openconcho/templates/networkpolicy.yaml
Normal file
20
charts/openconcho/templates/networkpolicy.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{{- if .Values.networkPolicy.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: {{ include "openconcho.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "openconcho.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "openconcho.selectorLabels" . | nindent 6 }}
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- ports:
|
||||||
|
- port: {{ .Values.service.containerPort }}
|
||||||
|
protocol: TCP
|
||||||
|
from:
|
||||||
|
- podSelector: {}
|
||||||
|
{{- end }}
|
||||||
17
charts/openconcho/templates/pdb.yaml
Normal file
17
charts/openconcho/templates/pdb.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{{- if .Values.podDisruptionBudget.enabled }}
|
||||||
|
apiVersion: policy/v1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
name: {{ include "openconcho.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "openconcho.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
{{- if not (kindIs "invalid" .Values.podDisruptionBudget.maxUnavailable) }}
|
||||||
|
maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
|
||||||
|
{{- else }}
|
||||||
|
minAvailable: {{ .Values.podDisruptionBudget.minAvailable | default 1 }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "openconcho.selectorLabels" . | nindent 6 }}
|
||||||
|
{{- end }}
|
||||||
15
charts/openconcho/templates/service.yaml
Normal file
15
charts/openconcho/templates/service.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "openconcho.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "openconcho.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{- include "openconcho.selectorLabels" . | nindent 4 }}
|
||||||
13
charts/openconcho/templates/serviceaccount.yaml
Normal file
13
charts/openconcho/templates/serviceaccount.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{{- if .Values.serviceAccount.create -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "openconcho.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "openconcho.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
|
||||||
|
{{- end }}
|
||||||
25
charts/openconcho/templates/tests/test-healthz.yaml
Normal file
25
charts/openconcho/templates/tests/test-healthz.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: "{{ include "openconcho.fullname" . }}-test-healthz"
|
||||||
|
labels:
|
||||||
|
{{- include "openconcho.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/hook: test
|
||||||
|
helm.sh/hook-delete-policy: before-hook-creation
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
activeDeadlineSeconds: 60
|
||||||
|
containers:
|
||||||
|
- name: healthz
|
||||||
|
image: busybox:1.36
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
RESPONSE=$(wget -T 10 -qO- http://{{ include "openconcho.fullname" . }}:{{ .Values.service.port }}/healthz)
|
||||||
|
if [ "$RESPONSE" != "ok" ]; then
|
||||||
|
echo "FAIL: expected 'ok', got '$RESPONSE'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "PASS: /healthz returned 'ok'"
|
||||||
24
charts/openconcho/templates/tests/test-spa-root.yaml
Normal file
24
charts/openconcho/templates/tests/test-spa-root.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: "{{ include "openconcho.fullname" . }}-test-spa-root"
|
||||||
|
labels:
|
||||||
|
{{- include "openconcho.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/hook: test
|
||||||
|
helm.sh/hook-delete-policy: before-hook-creation
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
activeDeadlineSeconds: 60
|
||||||
|
containers:
|
||||||
|
- name: spa-root
|
||||||
|
image: busybox:1.36
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
if ! wget -T 10 -q --spider http://{{ include "openconcho.fullname" . }}:{{ .Values.service.port }}/; then
|
||||||
|
echo "FAIL: GET / did not return HTTP 200"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "PASS: / returned HTTP 200"
|
||||||
67
charts/openconcho/values.schema.json
Normal file
67
charts/openconcho/values.schema.json
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"replicaCount": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["repository", "pullPolicy"],
|
||||||
|
"properties": {
|
||||||
|
"repository": { "type": "string", "minLength": 1 },
|
||||||
|
"tag": { "type": "string" },
|
||||||
|
"pullPolicy": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["Always", "IfNotPresent", "Never"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["type", "port", "containerPort"],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["ClusterIP", "NodePort", "LoadBalancer"]
|
||||||
|
},
|
||||||
|
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
|
||||||
|
"containerPort": { "type": "integer", "minimum": 1, "maximum": 65535 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"honcho": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"defaultUrl": { "type": "string" },
|
||||||
|
"upstreamAllowlist": { "type": "string" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoscaling": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"enabled": { "type": "boolean" },
|
||||||
|
"minReplicas": { "type": "integer", "minimum": 1 },
|
||||||
|
"maxReplicas": { "type": "integer", "minimum": 1 },
|
||||||
|
"targetCPUUtilizationPercentage": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"podDisruptionBudget": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"enabled": { "type": "boolean" },
|
||||||
|
"minAvailable": { "type": "integer", "minimum": 0 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"networkPolicy": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"enabled": { "type": "boolean" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
178
charts/openconcho/values.yaml
Normal file
178
charts/openconcho/values.yaml
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
# Number of pod replicas. Increase for high availability or use autoscaling instead.
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
image:
|
||||||
|
# Container image repository. Override to use a custom registry or fork.
|
||||||
|
repository: ghcr.io/offendingcommit/openconcho-web
|
||||||
|
# Image tag. Defaults to the chart appVersion when left empty.
|
||||||
|
tag: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# Secrets for pulling images from private registries.
|
||||||
|
# Example: [{ name: my-registry-secret }]
|
||||||
|
imagePullSecrets: []
|
||||||
|
|
||||||
|
# Override the name portion used in resource names and labels.
|
||||||
|
nameOverride: ""
|
||||||
|
# Override the full resource name (normally release-name + chart-name).
|
||||||
|
fullnameOverride: ""
|
||||||
|
|
||||||
|
serviceAccount:
|
||||||
|
# Create a dedicated ServiceAccount for the pod.
|
||||||
|
create: true
|
||||||
|
# Disable automatic ServiceAccount token mounting — the app never calls the Kubernetes API.
|
||||||
|
automount: false
|
||||||
|
# Annotations to add to the ServiceAccount (e.g. for IRSA, Workload Identity, Vault).
|
||||||
|
annotations: {}
|
||||||
|
# Use a pre-existing ServiceAccount instead of creating one. Ignored when create is true.
|
||||||
|
name: ""
|
||||||
|
|
||||||
|
# Annotations applied to every pod (not the Deployment). Useful for Prometheus scraping,
|
||||||
|
# Vault agent injection, Datadog unified service tagging, etc.
|
||||||
|
podAnnotations: {}
|
||||||
|
# Extra labels applied to every pod.
|
||||||
|
podLabels: {}
|
||||||
|
|
||||||
|
# Pod-level security context shared by all containers.
|
||||||
|
# UID/GID 101 matches the nginx-unprivileged base image — do not change without rebuilding.
|
||||||
|
podSecurityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 101
|
||||||
|
runAsGroup: 101
|
||||||
|
fsGroup: 101
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
|
||||||
|
# Container-level security context.
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: [ALL]
|
||||||
|
|
||||||
|
# Directories mounted as ephemeral tmpfs (in-memory) to satisfy nginx's write requirements
|
||||||
|
# when the root filesystem is read-only. Add entries for any additional writable paths.
|
||||||
|
tmpfsMounts:
|
||||||
|
- mountPath: /var/cache/nginx
|
||||||
|
- mountPath: /var/run
|
||||||
|
- mountPath: /tmp
|
||||||
|
|
||||||
|
service:
|
||||||
|
# Kubernetes Service type. Options: ClusterIP | NodePort | LoadBalancer
|
||||||
|
type: ClusterIP
|
||||||
|
# Port exposed by the Service (what the Ingress or other pods target).
|
||||||
|
port: 80
|
||||||
|
# Port the container actually listens on (nginx-unprivileged default).
|
||||||
|
containerPort: 8080
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
# IngressClass name. Leave empty to accept the cluster default.
|
||||||
|
# Examples: nginx | traefik | alb | kong
|
||||||
|
className: ""
|
||||||
|
# Annotations forwarded verbatim to the Ingress resource.
|
||||||
|
# Example (cert-manager + nginx-ingress):
|
||||||
|
# kubernetes.io/ingress.class: nginx
|
||||||
|
# cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
annotations: {}
|
||||||
|
hosts:
|
||||||
|
- host: openconcho.example.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
# TLS configuration. Provide a Secret containing the certificate.
|
||||||
|
# Example:
|
||||||
|
# - secretName: openconcho-tls
|
||||||
|
# hosts:
|
||||||
|
# - openconcho.example.com
|
||||||
|
tls: []
|
||||||
|
|
||||||
|
honcho:
|
||||||
|
# Default Honcho instance URL pre-populated in the UI on first load.
|
||||||
|
# Users can change or add instances at runtime; this only seeds the initial value.
|
||||||
|
# Example: https://honcho.example.com
|
||||||
|
defaultUrl: ""
|
||||||
|
# Optional SSRF guard: comma-separated host globs the nginx proxy is allowed to forward to.
|
||||||
|
# Leave empty to allow any upstream. Applies only when the proxy is publicly reachable.
|
||||||
|
# Example: honcho.example.com,*.internal.example.com
|
||||||
|
upstreamAllowlist: ""
|
||||||
|
|
||||||
|
# CPU and memory requests / limits for the web container.
|
||||||
|
# The SPA is static HTML/JS, so memory is the primary concern and CPU is negligible at rest.
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
|
||||||
|
autoscaling:
|
||||||
|
enabled: false
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 5
|
||||||
|
# Scale up when average CPU utilization across pods exceeds this percentage.
|
||||||
|
targetCPUUtilizationPercentage: 80
|
||||||
|
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: false
|
||||||
|
# Minimum number of pods that must remain available during voluntary disruptions
|
||||||
|
# (node drains, rolling upgrades). Set maxUnavailable instead to flip the direction.
|
||||||
|
minAvailable: 1
|
||||||
|
# Uncomment to use maxUnavailable instead — cannot set both simultaneously.
|
||||||
|
# maxUnavailable: 1
|
||||||
|
|
||||||
|
# Restrict pod-to-pod traffic at the network layer. When enabled, only pods in the
|
||||||
|
# same namespace may reach the web container.
|
||||||
|
# WARNING: if ingress is also enabled, you must add a policy that allows traffic from
|
||||||
|
# the ingress-controller namespace — run `helm status <release>` to see the reminder.
|
||||||
|
networkPolicy:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Spread pods across failure domains (availability zones, nodes, etc.) to reduce
|
||||||
|
# the blast radius of a single-node or single-zone failure.
|
||||||
|
# Example (zone spread):
|
||||||
|
# - maxSkew: 1
|
||||||
|
# topologyKey: topology.kubernetes.io/zone
|
||||||
|
# whenUnsatisfiable: DoNotSchedule
|
||||||
|
# labelSelector:
|
||||||
|
# matchLabels:
|
||||||
|
# app.kubernetes.io/name: openconcho
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
|
||||||
|
# Constrain pods to nodes whose labels match these key/value pairs.
|
||||||
|
# Example: kubernetes.io/arch: amd64
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
# Allow pods to be scheduled on tainted nodes.
|
||||||
|
# Example:
|
||||||
|
# - key: dedicated
|
||||||
|
# operator: Equal
|
||||||
|
# value: web
|
||||||
|
# effect: NoSchedule
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
# Advanced pod affinity / anti-affinity rules.
|
||||||
|
# Example (soft anti-affinity — prefer spreading across different nodes):
|
||||||
|
# podAntiAffinity:
|
||||||
|
# preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
# - weight: 100
|
||||||
|
# podAffinityTerm:
|
||||||
|
# labelSelector:
|
||||||
|
# matchLabels:
|
||||||
|
# app.kubernetes.io/name: openconcho
|
||||||
|
# topologyKey: kubernetes.io/hostname
|
||||||
|
affinity: {}
|
||||||
Reference in New Issue
Block a user