Compare commits

...

10 commits

Author SHA1 Message Date
xeruf
6e645c6abf apps: allow embedding for more tools 2024-04-10 15:21:21 +02:00
xeruf
65049a09b5 Allow iframing from Nextcloud for more apps again 2024-04-10 15:12:14 +02:00
xeruf
0ac0a6eeb2 apps/forge: allow up to 5GB in one request 2024-04-10 15:04:10 +02:00
xeruf
29ea18b2a2 readme: restructure 2024-04-08 17:21:15 +02:00
xeruf
cd226ea065 apps/status: add monitors for new apps 2024-04-08 09:08:49 +02:00
xeruf
40523875f0 apps/meet: force mail port to string
https://github.com/fluxcd/flux2/issues/4154
2024-04-05 21:15:54 +02:00
xeruf
3d8d3e5724 apps/meet: calcom mailing config 2024-04-05 14:41:42 +02:00
xeruf
e9204a27ba apps/forge: enable git lfs 2024-04-04 19:11:08 +02:00
xeruf
d6eda322de apps/forge: fix url config 2024-04-04 15:33:55 +02:00
xeruf
e1fc192dbb apps: remove gitea because forgejo is fine 2024-04-04 12:32:41 +02:00
26 changed files with 114 additions and 307 deletions

View file

@ -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.
![Flux Diagram](./stackspout.png)
### 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.
![Flux Diagram](./stackspout.png)

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,7 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: tcp-services
namespace: stackspout
data:
22: "gitea:22"

View file

@ -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

View file

@ -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

View file

@ -1,4 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- gitea-kustomization.yaml

View file

@ -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: [ "/" ]

View file

@ -7,5 +7,6 @@ metadata:
spec:
fields:
- fieldName: forgejo_admin_password
- fieldName: lfs_jwt
- fieldName: postgresql_password
- fieldName: postgresql_admin_password

View file

@ -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%'

View file

@ -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}"

View file

@ -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'

View file

@ -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:

View file

@ -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:

View file

@ -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"

View file

@ -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:

View file

@ -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:

View file

@ -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/

View file

@ -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

View file

@ -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