Compare commits
10 commits
f1514e1929
...
6e645c6abf
Author | SHA1 | Date | |
---|---|---|---|
|
6e645c6abf | ||
|
65049a09b5 | ||
|
0ac0a6eeb2 | ||
|
29ea18b2a2 | ||
|
cd226ea065 | ||
|
40523875f0 | ||
|
3d8d3e5724 | ||
|
e9204a27ba | ||
|
d6eda322de | ||
|
e1fc192dbb |
26 changed files with 114 additions and 307 deletions
93
README.md
93
README.md
|
@ -10,49 +10,6 @@ with a double-digit user number,
|
|||
so all experiments happen carefully.
|
||||
Still, it is an experimental offering.
|
||||
|
||||
## Tools
|
||||
|
||||
Useful tools for administration:
|
||||
- my `stack` CLI helper, currently part of my dotfiles:
|
||||
https://git.jfischer.org/xeruf/dotfiles/src/branch/main/.config/shell/server#L11
|
||||
- stackspin docs:
|
||||
https://docs.stackspin.net/en/v2/system_administration/customizing.html
|
||||
|
||||
## Explanation - Typical App Deployment in Stackspout with Flux on Kubernetes
|
||||
|
||||
The diagram illustrates generically how continuous app deployment works in our Kubernetes cluster
|
||||
from Infrastructure-as-Code using flux.
|
||||
Not every app has database, backend and frontend,
|
||||
but in the end the deployments all work very similarly
|
||||
so there is no point showing it for each individual app.
|
||||
Except for the Single-Sign On,
|
||||
apps also do not really depend on each other.
|
||||
|
||||
Explanations:
|
||||
- deploy :: creates a resource on the cluster from a file in the GitRepository
|
||||
- create :: creates a resource on the cluster using Kubernetes logic
|
||||
- ... all :: creates multiple independent resources
|
||||
|
||||
All Flux Kustomizations refer to a directory in the GitRepository,
|
||||
but for clarity I omitted it beyond the initial one.
|
||||
|
||||
Clouds are created not via Flux GitOps,
|
||||
but through one-time scripts.
|
||||
|
||||

|
||||
|
||||
### Guide: Creating OAuth Credentials for an external service
|
||||
- push an OAuth2Client definition like for the apps,
|
||||
adjusting `metadata.name` and `spec.secretName` as well as `spec.redirectUris`
|
||||
- obtain the generated `client_secret` for your application from kubernetes:
|
||||
|
||||
kubectl get secret -n flux-system stackspin-APP-oauth-variables --template '{{.data.client_secret}}' | base64 -d
|
||||
|
||||
with client_id:
|
||||
|
||||
kubectl get secret -n flux-system stackspin-APP-oauth-variables --template '{{.data.client_id}}{{"\n"}}{{.data.client_secret}}{{"\n"}}' | while read in; do echo $in | base64 -d; echo; done
|
||||
|
||||
|
||||
## Customizations
|
||||
|
||||
### Overrides
|
||||
|
@ -60,7 +17,12 @@ but through one-time scripts.
|
|||
-> most notably `external` to add Applications into Nextcloud as hub
|
||||
|
||||
### New Applications
|
||||
below list is formatted as:
|
||||
|
||||
Following are the applications Stackspout adds beyond Stackspin.
|
||||
Unlike Stackspin, there is currently no mechanism to add those individually,
|
||||
they come in one package with the repository.
|
||||
|
||||
Below list is formatted as:
|
||||
> subdomain: Service (helmrepo, if not provided by the service authors)
|
||||
|
||||
#### Stable including Single-Sign-On
|
||||
|
@ -114,3 +76,46 @@ kubectl -n stackspout get pods
|
|||
```
|
||||
|
||||
But there are also ConfigMaps, Secrets, StatefulSets, PVCs, Helmrepos and more...
|
||||
|
||||
### Tools
|
||||
|
||||
Useful tools for administration:
|
||||
- my `stack` CLI helper, currently part of my dotfiles:
|
||||
https://git.jfischer.org/xeruf/dotfiles/src/branch/main/.config/shell/server#L11
|
||||
- stackspin docs:
|
||||
https://docs.stackspin.net/en/v2/system_administration/customizing.html
|
||||
|
||||
### Guide: Creating OAuth Credentials for an external service
|
||||
- push an OAuth2Client definition like for the apps,
|
||||
adjusting `metadata.name` and `spec.secretName` as well as `spec.redirectUris`
|
||||
- obtain the generated `client_secret` for your application from kubernetes:
|
||||
|
||||
kubectl get secret -n flux-system stackspin-APP-oauth-variables --template '{{.data.client_secret}}' | base64 -d
|
||||
|
||||
with client_id:
|
||||
|
||||
kubectl get secret -n flux-system stackspin-APP-oauth-variables --template '{{.data.client_id}}{{"\n"}}{{.data.client_secret}}{{"\n"}}' | while read in; do echo $in | base64 -d; echo; done
|
||||
|
||||
|
||||
## Explanation - Typical App Deployment in Stackspout with Flux on Kubernetes
|
||||
|
||||
The diagram illustrates generically how continuous app deployment works in our Kubernetes cluster
|
||||
from Infrastructure-as-Code using flux.
|
||||
Not every app has database, backend and frontend,
|
||||
but in the end the deployments all work very similarly
|
||||
so there is no point showing it for each individual app.
|
||||
Except for the Single-Sign On,
|
||||
apps also do not really depend on each other.
|
||||
|
||||
Explanations:
|
||||
- deploy :: creates a resource on the cluster from a file in the GitRepository
|
||||
- create :: creates a resource on the cluster using Kubernetes logic
|
||||
- ... all :: creates multiple independent resources
|
||||
|
||||
All Flux Kustomizations refer to a directory in the GitRepository,
|
||||
but for clarity I omitted it beyond the initial one.
|
||||
|
||||
Clouds are created not via Flux GitOps,
|
||||
but through one-time scripts.
|
||||
|
||||

|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
retryInterval: 2m
|
||||
wait: true
|
||||
timeout: 3m
|
||||
dependsOn:
|
||||
- name: single-sign-on
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: stackspout
|
||||
path: ./apps/code
|
||||
prune: true
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
#- kind: Secret
|
||||
# name: stackspin-gitea-variables
|
||||
- kind: Secret
|
||||
name: stackspin-gitea-oauth-variables
|
||||
- kind: Secret
|
||||
name: stackspin-cluster-variables
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
apiVersion: secretgenerator.mittwald.de/v1alpha1
|
||||
kind: StringSecret
|
||||
metadata:
|
||||
name: stackspin-gitea-oauth-variables
|
||||
namespace: flux-system
|
||||
spec:
|
||||
data:
|
||||
client_id: gitea
|
||||
fields:
|
||||
- fieldName: client_secret
|
||||
length: "32"
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
apiVersion: secretgenerator.mittwald.de/v1alpha1
|
||||
kind: StringSecret
|
||||
metadata:
|
||||
name: stackspin-gitea-variables
|
||||
namespace: flux-system
|
||||
spec:
|
||||
fields:
|
||||
- fieldName: gitea_mariadb_password
|
||||
- fieldName: gitea_mariadb_root_password
|
||||
- fieldName: gitea_session_secret
|
|
@ -1,15 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: gitea-data
|
||||
namespace: stackspout
|
||||
labels:
|
||||
stackspin.net/backupSet: "gitea"
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
volumeMode: Filesystem
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
storageClassName: local-path
|
|
@ -1,21 +0,0 @@
|
|||
apiVersion: hydra.ory.sh/v1alpha1
|
||||
kind: OAuth2Client
|
||||
metadata:
|
||||
name: gitea-oauth-client
|
||||
# Has to live in the same namespace as the stackspin-*-oauth-variables secret
|
||||
namespace: flux-system
|
||||
spec:
|
||||
# TODO copied from wekan: https://github.com/wekan/wekan/wiki/Keycloak
|
||||
grantTypes:
|
||||
- authorization_code
|
||||
- refresh_token
|
||||
- client_credentials
|
||||
- implicit
|
||||
responseTypes:
|
||||
- id_token
|
||||
- code
|
||||
scope: "openid profile email stackspin_roles"
|
||||
secretName: stackspin-gitea-oauth-variables
|
||||
redirectUris:
|
||||
- https://code.${domain}/user/oauth2/Stackspin/callback
|
||||
tokenEndpointAuthMethod: client_secret_post
|
|
@ -1,15 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: gitea-postgres
|
||||
namespace: stackspout
|
||||
labels:
|
||||
stackspin.net/backupSet: "gitea"
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
volumeMode: Filesystem
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
storageClassName: local-path
|
|
@ -1,28 +0,0 @@
|
|||
apiVersion: helm.toolkit.fluxcd.io/v2beta1
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: stackspout
|
||||
spec:
|
||||
releaseName: gitea
|
||||
chart:
|
||||
spec:
|
||||
# https://gitea.com/gitea/helm-chart/tags
|
||||
chart: gitea
|
||||
version: 6.0.5
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: gitea
|
||||
namespace: flux-system
|
||||
interval: 5m
|
||||
valuesFrom:
|
||||
- kind: ConfigMap
|
||||
name: stackspin-gitea-values
|
||||
optional: false
|
||||
# Allow overriding values by ConfigMap or Secret
|
||||
- kind: ConfigMap
|
||||
name: stackspin-gitea-override
|
||||
optional: true
|
||||
- kind: Secret
|
||||
name: stackspin-gitea-override
|
||||
optional: true
|
|
@ -1,56 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: stackspin-gitea-values
|
||||
namespace: stackspout
|
||||
data:
|
||||
values.yaml: |
|
||||
ingress:
|
||||
enabled: true
|
||||
annotations:
|
||||
kubernetes.io/tls-acme: "true"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
|
||||
hosts:
|
||||
- host: "code.${domain}"
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: gitea-tls
|
||||
hosts:
|
||||
- "code.${domain}"
|
||||
gitea:
|
||||
# https://gitea.com/gitea/helm-chart/src/branch/main#oauth2-settings
|
||||
oauth:
|
||||
- name: Stackspin
|
||||
provider: "openidConnect"
|
||||
key: "${client_id}"
|
||||
secret: "${client_secret}"
|
||||
autoDiscoverUrl: "https://${hydra_domain}/.well-known/openid-configuration"
|
||||
iconUrl: "https://dashboard.${domain}/favicon-32x32.png"
|
||||
# https://docs.gitea.io/en-us/config-cheat-sheet
|
||||
config:
|
||||
repository:
|
||||
DEFAULT_PUSH_CREATE_PRIVATE: false
|
||||
ENABLE_PUSH_CREATE_USER: true
|
||||
ENABLE_PUSH_CREATE_ORG: true
|
||||
server:
|
||||
ROOT_URL: "https://code.${domain}"
|
||||
LANDING_PAGE: login
|
||||
openid:
|
||||
ENABLE_OPENID_SIGNUP: true
|
||||
service:
|
||||
DISABLE_REGISTRATION: false
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION: true
|
||||
log:
|
||||
LEVEL: "Trace"
|
||||
persistence:
|
||||
enabled: true
|
||||
existingClaim: gitea-data
|
||||
postgresql:
|
||||
persistence:
|
||||
enabled: true
|
||||
existingClaim: gitea-postgres
|
||||
service:
|
||||
ssh:
|
||||
hostPort: 22
|
|
@ -1,7 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: tcp-services
|
||||
namespace: stackspout
|
||||
data:
|
||||
22: "gitea:22"
|
|
@ -1,9 +0,0 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- gitea-release.yaml
|
||||
- gitea-values-configmap.yaml
|
||||
- metallb-gitea.yaml
|
||||
- gitea-oauth-client.yaml
|
||||
- gitea-data-pvc.yaml
|
||||
- gitea-postgres-pvc.yaml
|
|
@ -1,18 +0,0 @@
|
|||
# https://metallb.org/usage/
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea-ssh
|
||||
namespace: stackspout
|
||||
annotations:
|
||||
metallb.universe.tf/allow-shared-ip: "share-ipv4"
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
loadBalancerIP: "${ip_address}"
|
||||
ports:
|
||||
- name: ssh
|
||||
protocol: TCP
|
||||
port: 22
|
||||
targetPort: 22
|
||||
selector:
|
||||
app: gitea
|
|
@ -1,4 +0,0 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- gitea-kustomization.yaml
|
|
@ -25,6 +25,8 @@ data:
|
|||
enabled: true
|
||||
annotations:
|
||||
kubernetes.io/tls-acme: "true"
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
more_set_headers "Content-Security-Policy: frame-ancestors 'self' files.${domain}";
|
||||
hosts:
|
||||
- host: "${n8n_domain}"
|
||||
paths: [ "/" ]
|
||||
|
|
|
@ -7,5 +7,6 @@ metadata:
|
|||
spec:
|
||||
fields:
|
||||
- fieldName: forgejo_admin_password
|
||||
- fieldName: lfs_jwt
|
||||
- fieldName: postgresql_password
|
||||
- fieldName: postgresql_admin_password
|
||||
|
|
|
@ -9,7 +9,9 @@ data:
|
|||
enabled: true
|
||||
annotations:
|
||||
kubernetes.io/tls-acme: "true"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "5g"
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
more_set_headers "Content-Security-Policy: frame-ancestors 'self' files.${domain}";
|
||||
hosts:
|
||||
- host: "${forgejo_domain}"
|
||||
paths:
|
||||
|
@ -58,9 +60,9 @@ data:
|
|||
# PROJECT_BOARD_BUG_TRIAGE_TYPE: Needs Triage, High Priority, Low Priority, Closed
|
||||
server:
|
||||
LANDING_PAGE: login
|
||||
PROTOCOL: "https"
|
||||
# ROOT_URL: "https://${forgejo_domain}"
|
||||
# DOMAIN:
|
||||
ROOT_URL: "https://${forgejo_domain}"
|
||||
LFS_START_SERVER: true
|
||||
LFS_JWT_SECRET: "${lfs_jwt}"
|
||||
openid:
|
||||
ENABLE_OPENID_SIGNUP: true
|
||||
service:
|
||||
|
@ -83,8 +85,8 @@ data:
|
|||
# forcessl: true
|
||||
cors:
|
||||
ENABLED: true
|
||||
# SCHEME: "https"
|
||||
ALLOW_DOMAIN: "files.ftt.gmbh"
|
||||
SCHEME: "https"
|
||||
ALLOW_DOMAIN: "files.${domain}"
|
||||
ALLOW_CREDENTIALS: true
|
||||
# log:
|
||||
# LEVEL: "Debug"
|
||||
|
@ -140,4 +142,4 @@ data:
|
|||
type: 'RollingUpdate'
|
||||
rollingUpdate:
|
||||
maxSurge: '25%'
|
||||
maxUnavailable: '25%'
|
||||
maxUnavailable: '100%'
|
||||
|
|
|
@ -8,3 +8,9 @@ stringData:
|
|||
NEXT_PUBLIC_WEBAPP_URL: "https://${calcom_domain}"
|
||||
NEXTAUTH_SECRET: "${nextauth_secret}"
|
||||
CALENDSO_ENCRYPTION_KEY: "${calendso_key}"
|
||||
EMAIL_FROM: "${outgoing_mail_from_address}"
|
||||
EMAIL_SERVER_HOST: "${outgoing_mail_smtp_host}"
|
||||
EMAIL_SERVER_PORT: "!!str ${outgoing_mail_smtp_port}"
|
||||
EMAIL_SERVER_USER: "${outgoing_mail_smtp_user}"
|
||||
EMAIL_SERVER_PASSWORD: "${outgoing_mail_smtp_password}"
|
||||
# email_enabled: "${outgoing_mail_enabled}"
|
||||
|
|
|
@ -33,6 +33,8 @@ data:
|
|||
enabled: true
|
||||
annotations:
|
||||
kubernetes.io/tls-acme: "true"
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
more_set_headers "Content-Security-Policy: frame-ancestors 'self' files.${domain}";
|
||||
hosts:
|
||||
- host: "${calcom_domain}"
|
||||
paths:
|
||||
|
@ -42,17 +44,3 @@ data:
|
|||
- secretName: calcom-tls
|
||||
hosts:
|
||||
- "${calcom_domain}"
|
||||
|
||||
# TODO Adjust calcom Mailing config
|
||||
# mailer:
|
||||
# enabled: "${outgoing_mail_enabled}"
|
||||
# host: "${outgoing_mail_smtp_host}"
|
||||
# port: "${outgoing_mail_smtp_port}"
|
||||
# username: "${outgoing_mail_smtp_user}"
|
||||
# password: "${outgoing_mail_smtp_password}"
|
||||
# fromemail: "${outgoing_mail_from_address}"
|
||||
# TODO Adjust calcom OpenID Connect Single Sign-On Configuration
|
||||
# - name: Stackspin
|
||||
# key: "${client_id}"
|
||||
# secret: "${client_secret}"
|
||||
# autoDiscoverUrl: 'https://${hydra_domain}/.well-known/openid-configuration'
|
||||
|
|
|
@ -17,7 +17,7 @@ data:
|
|||
certManager: true
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
more_set_headers "Content-Security-Policy: frame-ancestors 'self' ${nextcloud_domain}";
|
||||
more_set_headers "Content-Security-Policy: frame-ancestors 'self' files.${domain}";
|
||||
commonLabels:
|
||||
stackspin.net/backupSet: "invoiceninja"
|
||||
podLabels:
|
||||
|
|
|
@ -23,6 +23,8 @@ data:
|
|||
enabled: true
|
||||
annotations:
|
||||
kubernetes.io/tls-acme: "true"
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
more_set_headers "Content-Security-Policy: frame-ancestors 'self' files.${domain}";
|
||||
hosts:
|
||||
- host: "${taiga_domain}"
|
||||
paths:
|
||||
|
|
|
@ -16,6 +16,10 @@ data:
|
|||
hosts:
|
||||
- "${gatus_domain}"
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
existingClaim: "gatus-data"
|
||||
|
||||
security:
|
||||
oidc:
|
||||
issuer-url: "https://${hydra_domain}"
|
||||
|
@ -89,6 +93,14 @@ data:
|
|||
url: "https://forge.${domain}"
|
||||
<<: *defaults
|
||||
group: "Stackspout"
|
||||
- name: "Cal.com Appointment Booking"
|
||||
url: "https://meet.${domain}"
|
||||
<<: *defaults
|
||||
group: "Stackspout"
|
||||
- name: "Gatus Health Dashboard"
|
||||
url: "https://status.${domain}"
|
||||
<<: *defaults
|
||||
group: "Stackspout"
|
||||
|
||||
- name: "Mailserver STARTTLS"
|
||||
url: "starttls://${outgoing_mail_smtp_host}:587"
|
||||
|
|
|
@ -18,6 +18,8 @@ data:
|
|||
enabled: true
|
||||
annotations:
|
||||
kubernetes.io/tls-acme: "true"
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
more_set_headers "Content-Security-Policy: frame-ancestors 'self' files.${domain}";
|
||||
hosts:
|
||||
- host: "${zammad_domain}"
|
||||
paths:
|
||||
|
|
|
@ -5,6 +5,7 @@ metadata:
|
|||
namespace: stackspout
|
||||
data:
|
||||
values.yaml: |
|
||||
# https://git.lecygnenoir.info/LecygneNoir/peertube-helm/src/branch/master/values.yaml
|
||||
commonLabels:
|
||||
stackspin.net/backupSet: "peertube"
|
||||
podLabels:
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
apiVersion: source.toolkit.fluxcd.io/v1beta2
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 60m
|
||||
url: https://dl.gitea.io/charts/
|
|
@ -1,9 +0,0 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
#- stackspin-zulip-override.yaml # no push notifications for now
|
||||
- stackspin-nextcloud-override.yaml
|
||||
- stackspin-nginx-ingress-override.yaml
|
||||
- stackspin-apps-custom.yaml
|
||||
- storageclass-retain.yaml
|
||||
- source-controller-patch.yaml
|
|
@ -5,6 +5,30 @@ metadata:
|
|||
name: stackspin-zulip-override
|
||||
data:
|
||||
values.yaml: |
|
||||
zulip:
|
||||
environment:
|
||||
SETTING_PUSH_NOTIFICATION_BOUNCER_URL: 'https://push.zulipchat.com'
|
||||
ingress:
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
more_set_headers "Content-Security-Policy: frame-ancestors 'self' files.${domain}";
|
||||
|
||||
#zulip:
|
||||
# environment:
|
||||
# SETTING_PUSH_NOTIFICATION_BOUNCER_URL: 'https://push.zulipchat.com'
|
||||
## https://github.com/zulip/docker-zulip/blob/main/kubernetes/chart/zulip/values.yaml
|
||||
#ingress:
|
||||
# enabled: true
|
||||
# annotations:
|
||||
# # Tell cert-manager to automatically get a TLS certificate
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
# # Allow bigger uploads, for image and file attaching.
|
||||
# # 25M is the default limit of Zulip itself, so we just follow that
|
||||
# # suggestion here. If you want to increase this further, you'd have to
|
||||
# # configure that limit in Zulip as well.
|
||||
# nginx.ingress.kubernetes.io/proxy-body-size: "25m"
|
||||
# hosts:
|
||||
# - host: "${zulip_domain}"
|
||||
# paths:
|
||||
# - path: "/"
|
||||
# tls:
|
||||
# - hosts:
|
||||
# - "${zulip_domain}"
|
||||
# secretName: stackspin-zulip
|
||||
|
|
Loading…
Add table
Reference in a new issue