From 2ef99735d91417dcc36174c9350624dc63f598c2 Mon Sep 17 00:00:00 2001 From: Edvin Norling Date: Mon, 13 Apr 2026 07:04:16 +0200 Subject: [PATCH] feat: add Helm chart for deploying scion hub/broker to Kubernetes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a Helm chart at charts/scion/ that supports two deployment modes: - hub (default): co-located hub + broker + web UI with SQLite persistence - broker: standalone broker connecting to an external hub The chart includes Deployment (Recreate strategy for SQLite safety), Service, Ingress, PVC, ServiceAccount, RBAC (Role or ClusterRole for agent pod management), ConfigMap for env var configuration, and a settings-configmap with an init container to seed ~/.scion/settings.yaml (workaround for server start requiring image_registry even when running as a hub — see inline comment). Also adds .github/workflows/publish-chart.yml to package and push the chart as an OCI artifact to ghcr.io on tag push. Tested on a kind cluster: helm install succeeds, health probes pass, helm upgrade rolls cleanly. Ref: GoogleCloudPlatform/scion#133 Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/publish-chart.yml | 56 ++++ charts/scion/Chart.yaml | 17 ++ charts/scion/templates/NOTES.txt | 47 +++ charts/scion/templates/_helpers.tpl | 80 ++++++ charts/scion/templates/configmap.yaml | 54 ++++ charts/scion/templates/deployment.yaml | 185 ++++++++++++ charts/scion/templates/ingress.yaml | 44 +++ charts/scion/templates/pvc.yaml | 21 ++ charts/scion/templates/role.yaml | 47 +++ charts/scion/templates/rolebinding.yaml | 42 +++ charts/scion/templates/service.yaml | 32 +++ charts/scion/templates/serviceaccount.yaml | 17 ++ .../scion/templates/settings-configmap.yaml | 16 ++ charts/scion/values.yaml | 271 ++++++++++++++++++ 14 files changed, 929 insertions(+) create mode 100644 .github/workflows/publish-chart.yml create mode 100644 charts/scion/Chart.yaml create mode 100644 charts/scion/templates/NOTES.txt create mode 100644 charts/scion/templates/_helpers.tpl create mode 100644 charts/scion/templates/configmap.yaml create mode 100644 charts/scion/templates/deployment.yaml create mode 100644 charts/scion/templates/ingress.yaml create mode 100644 charts/scion/templates/pvc.yaml create mode 100644 charts/scion/templates/role.yaml create mode 100644 charts/scion/templates/rolebinding.yaml create mode 100644 charts/scion/templates/service.yaml create mode 100644 charts/scion/templates/serviceaccount.yaml create mode 100644 charts/scion/templates/settings-configmap.yaml create mode 100644 charts/scion/values.yaml diff --git a/.github/workflows/publish-chart.yml b/.github/workflows/publish-chart.yml new file mode 100644 index 000000000..dbbd35804 --- /dev/null +++ b/.github/workflows/publish-chart.yml @@ -0,0 +1,56 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Publish Helm Chart + +on: + push: + tags: + - '*' + +permissions: + contents: read + packages: write + +jobs: + publish: + name: Package and Push Helm Chart + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Helm + uses: azure/setup-helm@v4 + + - name: Log in to GHCR + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io --username "${{ github.actor }}" --password-stdin + + - name: Update chart version + run: | + TAG="${GITHUB_REF_NAME#v}" + sed -i "s/^version:.*/version: ${TAG}/" charts/scion/Chart.yaml + sed -i "s/^appVersion:.*/appVersion: \"${TAG}\"/" charts/scion/Chart.yaml + + - name: Lint chart + run: helm lint charts/scion + + - name: Package chart + run: helm package charts/scion + + - name: Push chart to GHCR + run: | + CHART_PKG=$(ls scion-*.tgz) + helm push "${CHART_PKG}" oci://ghcr.io/googlecloudplatform/scion/charts diff --git a/charts/scion/Chart.yaml b/charts/scion/Chart.yaml new file mode 100644 index 000000000..3bf4ac291 --- /dev/null +++ b/charts/scion/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +name: scion +description: Scion AI agent orchestration platform - hub and runtime broker +type: application +version: 0.1.0 +appVersion: "0.1.0" +home: https://github.com/GoogleCloudPlatform/scion +sources: + - https://github.com/GoogleCloudPlatform/scion +maintainers: + - name: GoogleCloudPlatform + url: https://github.com/GoogleCloudPlatform +keywords: + - scion + - ai + - agents + - kubernetes diff --git a/charts/scion/templates/NOTES.txt b/charts/scion/templates/NOTES.txt new file mode 100644 index 000000000..89858ee11 --- /dev/null +++ b/charts/scion/templates/NOTES.txt @@ -0,0 +1,47 @@ +{{- if eq .Values.mode "hub" }} +Scion Hub deployed successfully! + +1. Access the hub: +{{- if .Values.ingress.enabled }} +{{- range .Values.ingress.hosts }} + https://{{ .host }} +{{- end }} +{{- else }} + kubectl port-forward svc/{{ include "scion.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }} + Then open: http://localhost:{{ .Values.service.port }} +{{- end }} + +2. Check health: + kubectl get pods -l {{ include "scion.selectorLabels" . | replace ": " "=" | replace "\n" "," }} + +{{- if not .Values.auth.existingSecret }} + +WARNING: No session secret configured (auth.existingSecret is empty). +Create a secret with a random session key: + + kubectl create secret generic scion-session \ + --from-literal=session-secret=$(openssl rand -hex 32) + +Then set auth.existingSecret=scion-session in your values. +{{- end }} + +{{- if .Values.ingress.enabled }} + +NOTE: If using SSE (Server-Sent Events) or WebSocket connections, ensure +your Ingress controller supports long-lived connections and has appropriate +timeout settings (e.g., proxy-read-timeout >= 300s for nginx). +{{- end }} +{{- else }} +Scion Broker deployed successfully! + +The broker is running on port {{ .Values.broker.port }}. +{{- if .Values.broker.hubEndpoint }} +Hub endpoint: {{ .Values.broker.hubEndpoint }} +{{- else }} + +WARNING: No hub endpoint configured (broker.hubEndpoint is empty). +Set broker.hubEndpoint to the hub's URL. +{{- end }} +{{- end }} + +Documentation: https://github.com/GoogleCloudPlatform/scion diff --git a/charts/scion/templates/_helpers.tpl b/charts/scion/templates/_helpers.tpl new file mode 100644 index 000000000..177a6e0d2 --- /dev/null +++ b/charts/scion/templates/_helpers.tpl @@ -0,0 +1,80 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "scion.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "scion.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 }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "scion.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "scion.labels" -}} +helm.sh/chart: {{ include "scion.chart" . }} +{{ include "scion.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- with .Values.commonLabels }} +{{ toYaml . }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "scion.selectorLabels" -}} +app.kubernetes.io/name: {{ include "scion.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "scion.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "scion.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Return the image reference +*/}} +{{- define "scion.image" -}} +{{- $tag := default .Chart.AppVersion .Values.image.tag }} +{{- printf "%s:%s" .Values.image.repository $tag }} +{{- end }} + +{{/* +Return the agent namespace for RBAC (defaults to release namespace) +*/}} +{{- define "scion.agentNamespace" -}} +{{- default .Release.Namespace .Values.rbac.agentNamespace }} +{{- end }} diff --git a/charts/scion/templates/configmap.yaml b/charts/scion/templates/configmap.yaml new file mode 100644 index 000000000..a15d3ab99 --- /dev/null +++ b/charts/scion/templates/configmap.yaml @@ -0,0 +1,54 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "scion.fullname" . }} + labels: + {{- include "scion.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + {{- if eq .Values.mode "hub" }} + SCION_SERVER_HUB_HOST: "0.0.0.0" + SCION_SERVER_LOGFORMAT: "json" + {{- with .Values.server.logLevel }} + SCION_SERVER_LOGLEVEL: {{ . | quote }} + {{- end }} + {{- with .Values.database.path }} + SCION_SERVER_DATABASE_URL: {{ . | quote }} + {{- end }} + {{- with .Values.storage.provider }} + SCION_SERVER_STORAGE_PROVIDER: {{ . | quote }} + {{- end }} + {{- with .Values.storage.bucket }} + SCION_HUB_STORAGE_BUCKET: {{ . | quote }} + {{- end }} + {{- with .Values.secrets.backend }} + SCION_SERVER_SECRETS_BACKEND: {{ . | quote }} + {{- end }} + {{- with .Values.secrets.gcpProjectId }} + SCION_SERVER_SECRETS_GCPPROJECTID: {{ . | quote }} + {{- end }} + {{- with .Values.server.publicUrl }} + SCION_SERVER_BASE_URL: {{ . | quote }} + {{- end }} + {{- if .Values.server.adminEmails }} + SCION_SERVER_HUB_ADMINEMAILS: {{ join "," .Values.server.adminEmails | quote }} + {{- end }} + {{- end }} + {{- with .Values.imageRegistry }} + SCION_IMAGE_REGISTRY: {{ . | quote }} + {{- end }} + {{- if .Values.telemetry.cloudLogging.enabled }} + SCION_LOG_GCP: "true" + {{- with .Values.telemetry.cloudLogging.gcpProjectId }} + SCION_CLOUD_LOGGING_PROJECT_ID: {{ . | quote }} + {{- end }} + {{- with .Values.telemetry.cloudLogging.logId }} + SCION_CLOUD_LOGGING_LOG_ID: {{ . | quote }} + {{- end }} + {{- end }} + {{- if .Values.telemetry.otelLogBridge.enabled }} + SCION_OTEL_LOG_BRIDGE: "true" + {{- end }} diff --git a/charts/scion/templates/deployment.yaml b/charts/scion/templates/deployment.yaml new file mode 100644 index 000000000..9ffc61010 --- /dev/null +++ b/charts/scion/templates/deployment.yaml @@ -0,0 +1,185 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "scion.fullname" . }} + labels: + {{- include "scion.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicaCount }} + strategy: + type: Recreate + selector: + matchLabels: + {{- include "scion.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "scion.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "scion.serviceAccountName" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: scion + image: {{ include "scion.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + args: + - "--global" + - "server" + - "start" + - "--foreground" + - "--production" + {{- if eq .Values.mode "hub" }} + - "--enable-hub" + - "--enable-web" + - "--web-port" + - {{ .Values.server.port | quote }} + {{- if .Values.broker.enabled }} + - "--enable-runtime-broker" + - "--runtime-broker-port" + - {{ .Values.broker.port | quote }} + {{- if .Values.broker.autoProvide }} + - "--auto-provide" + {{- end }} + {{- end }} + {{- with .Values.database.path }} + - "--db" + - {{ . | quote }} + {{- end }} + {{- if eq .Values.storage.provider "gcs" }} + {{- with .Values.storage.bucket }} + - "--storage-bucket" + - {{ . | quote }} + {{- end }} + {{- else if eq .Values.storage.provider "local" }} + {{- with .Values.storage.localPath }} + - "--storage-dir" + - {{ . | quote }} + {{- end }} + {{- end }} + {{- if .Values.server.adminEmails }} + - "--admin-emails" + - {{ join "," .Values.server.adminEmails | quote }} + {{- end }} + {{- else }} + {{/* broker-only mode */}} + - "--enable-runtime-broker" + - "--runtime-broker-port" + - {{ .Values.broker.port | quote }} + {{- if .Values.broker.autoProvide }} + - "--auto-provide" + {{- end }} + {{- end }} + {{- if eq .Values.server.logLevel "debug" }} + - "--debug" + {{- end }} + {{- with .Values.server.extraArgs }} + {{- toYaml . | nindent 12 }} + {{- end }} + envFrom: + - configMapRef: + name: {{ include "scion.fullname" . }} + env: + {{- if and (eq .Values.mode "hub") .Values.auth.existingSecret }} + - name: SCION_SERVER_SESSION_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.auth.existingSecret }} + key: {{ .Values.auth.existingSecretKey }} + {{- end }} + {{- with .Values.server.extraEnv }} + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + {{- if eq .Values.mode "hub" }} + - name: http + containerPort: {{ .Values.server.port }} + protocol: TCP + {{- end }} + {{- if or (eq .Values.mode "broker") .Values.broker.enabled }} + - name: broker + containerPort: {{ .Values.broker.port }} + protocol: TCP + {{- end }} + {{- if eq .Values.mode "hub" }} + livenessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 10 + periodSeconds: 15 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /readyz + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + {{- if and (eq .Values.mode "hub") .Values.persistence.enabled }} + - name: data + mountPath: /data + {{- end }} + - name: tmp + mountPath: /tmp + - name: home + mountPath: /home/nonroot + - name: settings + mountPath: /home/nonroot/.scion/settings.yaml + subPath: settings.yaml + readOnly: true + volumes: + {{- if and (eq .Values.mode "hub") .Values.persistence.enabled }} + - name: data + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (include "scion.fullname" .) }} + {{- end }} + - name: tmp + emptyDir: {} + - name: home + emptyDir: {} + - name: settings + configMap: + name: {{ include "scion.fullname" . }}-settings + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/scion/templates/ingress.yaml b/charts/scion/templates/ingress.yaml new file mode 100644 index 000000000..d90ca32a8 --- /dev/null +++ b/charts/scion/templates/ingress.yaml @@ -0,0 +1,44 @@ +{{- if and (eq .Values.mode "hub") .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "scion.fullname" . }} + labels: + {{- include "scion.labels" . | nindent 4 }} + annotations: + {{- with .Values.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with .Values.ingress.className }} + ingressClassName: {{ . }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "scion.fullname" $ }} + port: + name: http + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/scion/templates/pvc.yaml b/charts/scion/templates/pvc.yaml new file mode 100644 index 000000000..fa9388899 --- /dev/null +++ b/charts/scion/templates/pvc.yaml @@ -0,0 +1,21 @@ +{{- if and (eq .Values.mode "hub") .Values.persistence.enabled (not .Values.persistence.existingClaim) -}} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "scion.fullname" . }} + labels: + {{- include "scion.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + - {{ .Values.persistence.accessMode }} + {{- with .Values.persistence.storageClass }} + storageClassName: {{ . }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size }} +{{- end }} diff --git a/charts/scion/templates/role.yaml b/charts/scion/templates/role.yaml new file mode 100644 index 000000000..7f572e0b7 --- /dev/null +++ b/charts/scion/templates/role.yaml @@ -0,0 +1,47 @@ +{{- if .Values.rbac.create -}} +{{- if .Values.rbac.clusterWide }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "scion.fullname" . }} + labels: + {{- include "scion.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- else }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "scion.fullname" . }} + namespace: {{ include "scion.agentNamespace" . }} + labels: + {{- include "scion.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "create", "delete"] + - apiGroups: [""] + resources: ["pods/exec"] + verbs: ["create"] + - apiGroups: [""] + resources: ["pods/log"] + verbs: ["get"] + - apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "list", "delete"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "create", "list", "delete"] + {{- if .Values.rbac.secretProviderClass }} + - apiGroups: ["secrets-store.csi.x-k8s.io"] + resources: ["secretproviderclasses"] + verbs: ["create", "list", "delete"] + {{- end }} +{{- end }} diff --git a/charts/scion/templates/rolebinding.yaml b/charts/scion/templates/rolebinding.yaml new file mode 100644 index 000000000..f3a3c5bb8 --- /dev/null +++ b/charts/scion/templates/rolebinding.yaml @@ -0,0 +1,42 @@ +{{- if .Values.rbac.create -}} +{{- if .Values.rbac.clusterWide }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "scion.fullname" . }} + labels: + {{- include "scion.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "scion.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "scion.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- else }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "scion.fullname" . }} + namespace: {{ include "scion.agentNamespace" . }} + labels: + {{- include "scion.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "scion.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "scion.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +{{- end }} diff --git a/charts/scion/templates/service.yaml b/charts/scion/templates/service.yaml new file mode 100644 index 000000000..fe1388bf4 --- /dev/null +++ b/charts/scion/templates/service.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "scion.fullname" . }} + labels: + {{- include "scion.labels" . | nindent 4 }} + {{- if or .Values.service.annotations .Values.commonAnnotations }} + annotations: + {{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + {{- if eq .Values.mode "hub" }} + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + {{- end }} + {{- if or (eq .Values.mode "broker") .Values.broker.enabled }} + - port: {{ .Values.broker.port }} + targetPort: broker + protocol: TCP + name: broker + {{- end }} + selector: + {{- include "scion.selectorLabels" . | nindent 4 }} diff --git a/charts/scion/templates/serviceaccount.yaml b/charts/scion/templates/serviceaccount.yaml new file mode 100644 index 000000000..a8e0132bd --- /dev/null +++ b/charts/scion/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "scion.serviceAccountName" . }} + labels: + {{- include "scion.labels" . | nindent 4 }} + {{- if or .Values.serviceAccount.annotations .Values.commonAnnotations }} + annotations: + {{- with .Values.serviceAccount.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/scion/templates/settings-configmap.yaml b/charts/scion/templates/settings-configmap.yaml new file mode 100644 index 000000000..b3b1d18bb --- /dev/null +++ b/charts/scion/templates/settings-configmap.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "scion.fullname" . }}-settings + labels: + {{- include "scion.labels" . | nindent 4 }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + settings.yaml: | + schema_version: "1" + {{- with .Values.imageRegistry }} + image_registry: {{ . | quote }} + {{- end }} diff --git a/charts/scion/values.yaml b/charts/scion/values.yaml new file mode 100644 index 000000000..2f662ebae --- /dev/null +++ b/charts/scion/values.yaml @@ -0,0 +1,271 @@ +# Scion Helm Chart Values +# See: https://github.com/GoogleCloudPlatform/scion + +# -- Deployment mode: "hub" (hub+broker co-located) or "broker" (broker-only) +mode: hub + +# -- Number of replicas. MUST be 1 when using SQLite (default). +replicaCount: 1 + +image: + # -- Container image repository + repository: ghcr.io/googlecloudplatform/scion + # -- Image tag (defaults to Chart appVersion) + tag: "" + # -- Image pull policy + pullPolicy: IfNotPresent + +# -- Image pull secrets +imagePullSecrets: [] + +# -- Override the chart name +nameOverride: "" +# -- Override the full release name +fullnameOverride: "" + +# -- Additional labels to add to all resources +commonLabels: {} + +# -- Additional annotations to add to all resources +commonAnnotations: {} + +# ============================================================================= +# Scion Server Configuration +# ============================================================================= + +server: + # -- Hub API + Web UI port (combined mode) + port: 8080 + # -- Public URL for the hub (used for OAuth callbacks, broker connections) + # Example: https://hub.example.com + publicUrl: "" + # -- Admin email addresses (auto-promoted to admin role) + adminEmails: [] + # -- Log level: debug, info, warn, error + logLevel: "info" + + # -- Additional CLI arguments passed to `scion server start` + extraArgs: [] + + # -- Additional environment variables (list of {name, value} or {name, valueFrom}) + extraEnv: [] + +# ============================================================================= +# Runtime Broker Configuration +# ============================================================================= + +broker: + # -- Enable runtime broker (always true in hub mode, configurable in broker mode) + enabled: true + # -- Broker port + port: 9800 + # -- How the broker connects to the hub (internal URL, auto-configured in hub mode) + hubEndpoint: "" + # -- URL that agents inside containers use to reach the hub + containerHubEndpoint: "" + # -- Auto-provide groves + autoProvide: true + # -- Broker name + name: "" + # -- Broker nickname + nickname: "" + + # -- For broker-only mode: K8s Secret containing broker-credentials.json + credentialsSecret: "" + +# ============================================================================= +# Database Configuration +# ============================================================================= + +database: + # -- Database driver (only "sqlite" is currently supported) + driver: "sqlite" + # -- Database path inside the container (on the PVC) + path: "/data/hub.db" + +# ============================================================================= +# Storage Configuration +# ============================================================================= + +storage: + # -- Storage provider: "local" or "gcs" + provider: "gcs" + # -- GCS bucket name (required when provider is "gcs") + bucket: "" + # -- Local storage path (only when provider is "local") + localPath: "/data/storage" + +# ============================================================================= +# Secrets Backend +# ============================================================================= + +secrets: + # -- Secrets backend: "local" or "gcpsm" + backend: "local" + # -- GCP project ID (required when backend is "gcpsm") + gcpProjectId: "" + +# ============================================================================= +# Authentication +# ============================================================================= + +auth: + # -- Authorized email domains for login + authorizedDomains: [] + # -- Session secret (required). Reference to an existing K8s Secret. + existingSecret: "" + # -- Key in the existing secret that contains the session secret + existingSecretKey: "session-secret" + +# -- Reference to a K8s Secret containing OAuth credentials. +# Expected keys: see values documentation for full list. +oauthSecret: "" + +# -- Reference to a K8s Secret containing GitHub App credentials. +githubAppSecret: "" + +# ============================================================================= +# Telemetry +# ============================================================================= + +telemetry: + # -- Enable Cloud Logging + cloudLogging: + enabled: false + gcpProjectId: "" + logId: "" + # -- Enable OTEL log bridge + otelLogBridge: + enabled: false + +# ============================================================================= +# Image Registry (for agent container images) +# ============================================================================= + +# -- Container image registry for agent images (e.g., ghcr.io/myorg) +imageRegistry: "" + +# ============================================================================= +# Kubernetes Resources +# ============================================================================= + +# -- Resource requests and limits for the hub pod +resources: + requests: + cpu: "500m" + memory: "512Mi" + limits: + cpu: "2" + memory: "2Gi" + +# ============================================================================= +# Persistence (SQLite) +# ============================================================================= + +persistence: + # -- Enable persistent storage for SQLite database + enabled: true + # -- Storage class name (empty = default) + storageClass: "" + # -- PVC size + size: "10Gi" + # -- Access mode + accessMode: ReadWriteOnce + # -- Use an existing PVC instead of creating one + existingClaim: "" + +# ============================================================================= +# Service +# ============================================================================= + +service: + # -- Service type + type: ClusterIP + # -- Service port + port: 8080 + # -- Additional annotations (e.g., for cloud load balancers) + annotations: {} + +# ============================================================================= +# Ingress +# ============================================================================= + +ingress: + # -- Enable Ingress resource + enabled: false + # -- Ingress class name + className: "" + # -- Ingress annotations + annotations: {} + # -- Ingress hosts + hosts: + - host: hub.example.com + paths: + - path: / + pathType: Prefix + # -- Ingress TLS configuration + tls: [] + # - secretName: hub-tls + # hosts: + # - hub.example.com + +# ============================================================================= +# Service Account +# ============================================================================= + +serviceAccount: + # -- Create a ServiceAccount + create: true + # -- ServiceAccount name (auto-generated if empty) + name: "" + # -- Annotations (e.g., for GKE Workload Identity) + annotations: {} + # iam.gke.io/gcp-service-account: scion-hub@my-project.iam.gserviceaccount.com + +# ============================================================================= +# RBAC +# ============================================================================= + +rbac: + # -- Create RBAC resources for managing agent pods + create: true + # -- Use ClusterRole (true) or namespace-scoped Role (false) + clusterWide: false + # -- Namespace for agent pods (only used when clusterWide is false). + # Defaults to the release namespace. + agentNamespace: "" + # -- Enable SecretProviderClass CRD permissions (GKE Secret Store CSI) + secretProviderClass: false + +# ============================================================================= +# Pod Configuration +# ============================================================================= + +# -- Node selector +nodeSelector: {} + +# -- Tolerations +tolerations: [] + +# -- Affinity rules +affinity: {} + +# -- Pod annotations +podAnnotations: {} + +# -- Pod labels +podLabels: {} + +# -- Pod security context +podSecurityContext: + fsGroup: 65532 + +# -- Container security context +securityContext: + runAsNonRoot: true + runAsUser: 65532 + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL