Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • stackspin/stackspin-flux-example
  • xeruf/stackspout
2 results
Show changes
Commits on Source (443)
Showing
with 576 additions and 47 deletions
# Example repository for customizing a Stackspin cluster
# Stackspin Outwards - Stackspout
This repository extends [Stackspin](https://open.greenhost.net/stackspin/stackspin)
with extra applications and overrides
focused on business use.
Once stabilized, the aim is to contribute as much upstream as possible.
Stackspout is used in day-to-day business
with a double-digit user number,
so all experiments happen carefully.
Still, it is an experimental offering.
## Customizations
### Overrides
- Adds many Nextcloud extensions and some configuration
-> most notably `external` to add Applications into Nextcloud as hub
- Allow iFraming of applications into Nextcloud
### New Applications
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 by the application authors themselves)
#### Stable including Single-Sign-On
- forge: Forgejo
- do: Vikunja [needs upgrade]
- status: Gatus (minicloudlabs)
#### No SSO
- ninja: InvoiceNinja
- support: Zammad [needs PVC fixed]
- flow: n8n (8gears)
- meet: cal.com (pyrrha)
#### Planned
- design: penpot (truecharts, waiting on PR)
- sprint: taiga (nemonik)
- video: Peertube ([LecygneNoir](https://git.lecygnenoir.info/LecygneNoir/peertube-helm)
)
- call: Jitsi Meet / OpenTalk / Element Call
- wiki: Wiki (maybe wikijs, but I'd like something that integrates with Nextcloud and Markdown/Orgdown)
#### Ideas
- link: URL Shortener
- connect: Bonfire
#### Stale
- people: SuiteCRM (bitnami repo)
- time: Kimai (robjuz repo)
#### Functionally
- Nextcloud too slow - add Redis?
- Preconfigure user settings in Nextcloud, Vikunja and more
## Setup
> Warning: Lots of experiments happening here!
First [install Stackspin](https://docs.stackspin.net/en/latest/installation/install_stackspin.html).
Then apply the configuration to your cluster:
Example boilerplate for a custom [flux](https://fluxcd.io/) repository
which can be added to a [Stackspin](https://stackspin.net) cluster.
The main use-case is to add additional applications
which are not integrated into Stackspin (yet).
```sh
./install.sh
```
For a more advanced example
see the [flux2-kustomize-helm-example](https://github.com/fluxcd/flux2-kustomize-helm-example)
repository.
This repo's directory structure is similar to the `flux2-kustomize-helm-example`
one.
Done!
Note that the added applications are currently only toggled via repository changes
and integration with Stackspin mechanisms is very rudimentary.
To list the central resource related to this repo:
## Basic configuration
```sh
kubectl get gitrepositories -A
kubectl get kustomization -A -o=jsonpath='{.items[?(@.spec.sourceRef.name=="stackspout")].metadata.name}'
kubectl -n stackspout get helmreleases
kubectl -n stackspout get pods
```
We'll start with a very basic configuration:
But there are also ConfigMaps, Secrets, StatefulSets, PVCs, Helmrepos and more...
* It uses a public git repo
* No secrets are included
* No forking/modifications needed, install as it is
### Tools
Apply it to your cluster:
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
```sh
basic/install.sh
```
### 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:
List the resource created by this flux repo:
kubectl get secret -n flux-system stackspin-APP-oauth-variables --template '{{.data.client_secret}}' | base64 -d
```sh
kubectl -n example-basic get gitrepositories
kubectl -n example-basic get kustomizations
kubectl -n example-basic get helmreleases
kubectl -n example-basic get pods
```
with client_id:
Show output of the single app applied, [podinfo](https://github.com/stefanprodan/podinfo)
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
```sh
curl --resolve podinfo.local:80:CLUSTER_IPV4_ADDRESS http://podinfo.local
```
## What's next ?
## Explanation - Typical App Deployment in Stackspout with Flux on Kubernetes
There are two ways of using a custom flux repo to host your custom config/apps
on a Stackspin cluster.
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.
### A) Manage secrets manually
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
This approach is easier to start with,
because you don't need to configure your cluster to handle encrypted secrets
and access to a private git repository.
All Flux Kustomizations refer to a directory in the GitRepository,
but for clarity I omitted it beyond the initial one.
* Fork this repository into a public git repo, cloneable via `https://`
Clouds are created not via Flux GitOps,
but through one-time scripts.
### Everything in version control, including secrets
![Flux Diagram](util/stackspout.png)
* Fork this repository into a private git repo, cloneable via `ssh://`
* [Configure flux to use ssh instead of https for cloning](https://fluxcd.io/docs/components/source/gitrepositories/#ssh-authentication)
* You shouln't rely solely on transport encryption for your git repository
but rather end-to-end encrypt your secrets.
Different methods are available for flux:
* [Sops](https://fluxcd.io/docs/guides/mozilla-sops/)
[Sops section in flux2-kustomize-helm-example](https://github.com/fluxcd/flux2-kustomize-helm-example#encrypt-kubernetes-secrets)
* [Sealed Secrets](https://fluxcd.io/docs/guides/sealed-secrets/)
See also https://about.ftt.gmbh/projects/polygon.html#state-of-stackspout-2022
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: add-design
namespace: flux-system
spec:
interval: 10m
prune: true
path: ./apps/design
sourceRef:
kind: GitRepository
name: stackspout
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- penpot-kustomization.yaml
- penpot-secrets-kustomization.yaml
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: penpot
namespace: flux-system
spec:
interval: 5m
retryInterval: 2m
timeout: 10m
wait: true
prune: true
path: ./apps/design/penpot
sourceRef:
kind: GitRepository
name: stackspout
dependsOn:
- name: flux
- name: local-path-provisioner
- name: penpot-secrets
- name: nginx
- name: single-sign-on
postBuild:
substituteFrom:
- kind: Secret
name: stackspin-cluster-variables
- kind: ConfigMap
name: stackspin-penpot-kustomization-variables
- kind: Secret
name: stackspin-penpot-variables
# OIDC
- kind: Secret
name: stackspin-penpot-oauth-variables
- kind: ConfigMap
name: stackspin-single-sign-on-kustomization-variables
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: penpot-secrets
namespace: flux-system
spec:
interval: 5m
timeout: 4m
wait: true
prune: true
path: ./apps/design/penpot-secrets
sourceRef:
kind: GitRepository
name: stackspout
dependsOn:
- name: flux
- name: secrets-controller
postBuild:
substituteFrom:
- kind: Secret
name: stackspin-cluster-variables
apiVersion: v1
kind: ConfigMap
metadata:
name: stackspin-penpot-kustomization-variables
namespace: flux-system
data:
penpot_domain: design.${domain}
---
apiVersion: secretgenerator.mittwald.de/v1alpha1
kind: StringSecret
metadata:
name: stackspin-penpot-oauth-variables
namespace: flux-system
spec:
data:
client_id: penpot
fields:
- fieldName: client_secret
length: "32"
---
apiVersion: secretgenerator.mittwald.de/v1alpha1
kind: StringSecret
metadata:
name: stackspin-penpot-variables
namespace: flux-system
spec:
fields:
- fieldName: api_key
apiVersion: hydra.ory.sh/v1alpha1
kind: OAuth2Client
metadata:
name: penpot-oauth-client
# Has to live in the same namespace as the stackspin-penpot-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-penpot-oauth-variables
#redirectUris:
# - https://${penpot_domain}/oauth/openid/
#tokenEndpointAuthMethod: client_secret_post
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: penpot-assets
namespace: stackspout
labels:
stackspin.net/backupSet: "penpot"
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 2Gi
storageClassName: local-path
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: penpot
namespace: stackspout
spec:
releaseName: penpot
chart:
spec:
chart: penpot
version: 0.5.0
sourceRef:
kind: HelmRepository
name: penpot
namespace: flux-system
interval: 5m
valuesFrom:
- kind: ConfigMap
name: stackspin-penpot-values
optional: false
# Allow overriding values by ConfigMap or Secret
- kind: ConfigMap
name: stackspin-penpot-override
optional: true
- kind: Secret
name: stackspin-penpot-override
optional: true
apiVersion: v1
kind: ConfigMap
metadata:
name: stackspin-penpot-values
namespace: stackspout
data:
values.yaml: |
global:
postgresqlEnabled: true
redisEnabled: true
frontend:
podLabels:
stackspin.net/backupSet: "penpot"
backend:
podLabels:
stackspin.net/backupSet: "penpot"
exporter:
podLabels:
stackspin.net/backupSet: "penpot"
backend:
podAnnotations:
backup.velero.io/backup-volumes: "app-data"
persistence:
assets:
existingClaim: "penpot-data"
ingress:
enabled: true
annotations:
kubernetes.io/tls-acme: "true"
hosts: ["${penpot_domain}"]
tls:
- secretName: penpot-tls
hosts:
- "${penpot_domain}"
integrations:
certManager:
enabled: true
config:
publicUri: "https://${penpot_domain}"
#apiSecretKey: "W8oErul6XcazLUhpsP_y0zttNSx_EkItWmD0TKTEvJuWSsjvkfEHxk9uNmrCOZ-p_Y6gIRV7yqQ4j04JcQX3xg"
apiSecretKey: "${api_key}"
# -- Comma separated list of allowed domains to register. Empty to allow all domains.
registrationDomainWhitelist: "ftt.gmbh"
telemetryEnabled: false
# -- The feature flags to enable. Check [the official docs](https://help.penpot.app/technical-guide/configuration/) for more info.
# @section -- Configuration parameters
#flags: "enable-registration enable-login-with-password disable-email-verification enable-smtp"
#flags:
# backend_api_doc: false
# cors: false
# demo_users: false
# demo_warning: false
# insecure_register: false
# log_emails: false
# log_invitation_token: false
# login: true
# mail_verification: true
# registration: true
# secure_session_cookies: true
# user_feedback: false
smtp:
enabled: "${outgoing_mail_enabled}"
host: "${outgoing_mail_smtp_host}"
port: "${outgoing_mail_smtp_port}"
username: "${outgoing_mail_smtp_user}"
password: "${outgoing_mail_smtp_password}"
defaultFrom: "${outgoing_mail_from_address}"
defaultReplyTo: "${outgoing_mail_from_address}"
providers:
oidc:
enabled: true
clientID: "${client_id}"
clientSecret: "${client_secret}"
baseURI: "https://${hydra_domain}"
#autoDiscoverUrl: 'https://${hydra_domain}/.well-known/openid-configuration'
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: add-do
namespace: flux-system
spec:
interval: 10m
prune: true
path: ./apps/do
sourceRef:
kind: GitRepository
name: stackspout
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- vikunja-secrets-kustomization.yaml
- vikunja-kustomization.yaml
- vikunja-test-kustomization.yaml
- vikunja-extra-kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: vikunja-extra
namespace: flux-system
spec:
interval: 5m
retryInterval: 2m
timeout: 10m
wait: true
prune: true
path: ./apps/do/vikunja-extra
sourceRef:
kind: GitRepository
name: stackspout
dependsOn:
- name: flux
- name: local-path-provisioner
- name: vikunja-secrets
- name: nginx
- name: single-sign-on
postBuild:
substituteFrom:
- kind: Secret
name: stackspin-cluster-variables
- kind: ConfigMap
name: stackspin-vikunja-kustomization-variables
- kind: Secret
name: stackspin-vikunja-variables
# OIDC
- kind: Secret
name: stackspin-vikunja-oauth-variables
- kind: ConfigMap
name: stackspin-single-sign-on-kustomization-variables
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: vikunja-extra-files
namespace: stackspout
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 2Gi
storageClassName: local-path
apiVersion: hydra.ory.sh/v1alpha1
kind: OAuth2Client
metadata:
name: vikunja-extra-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 name"
secretName: stackspin-vikunja-extra-oauth-variables
redirectUris:
- https://{vikunja_extra_domain}/auth/openid/stackspin
tokenEndpointAuthMethod: client_secret_post
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: vikunja-extra-postgres
namespace: stackspout
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 2Gi
storageClassName: local-path
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: vikunja-extra
namespace: stackspout
spec:
releaseName: vikunja-extra
chart:
spec:
chart: vikunja
version: 1.0.0
sourceRef:
kind: HelmRepository
name: vikunja-xeruf
namespace: flux-system
interval: 5m
valuesFrom:
- kind: ConfigMap
name: stackspin-vikunja-extra-values
optional: false
# Allow overriding values by ConfigMap or Secret
- kind: ConfigMap
name: stackspin-vikunja-extra-override
optional: true
- kind: Secret
name: stackspin-vikunja-extra-override
optional: true
apiVersion: v1
kind: ConfigMap
metadata:
name: stackspin-vikunja-extra-values
namespace: stackspout
data:
# https://kolaente.dev/vikunja/helm-chart/src/branch/main/values.yaml
values.yaml: |
vikunja:
persistence:
data:
existingClaim: vikunja-extra-files
ingress:
main:
enabled: true
annotations:
kubernetes.io/tls-acme: "true"
hosts:
- host: "${vikunja_extra_domain}"
paths:
- path: /api
tls:
- secretName: vikunja-tls
hosts:
- "${vikunja_extra_domain}"
configMaps:
config:
data:
config.yml: |-
auth:
openid:
# https://vikunja.io/docs/openid-example-configurations/
# Example: https://kolaente.dev/vikunja/vikunja/src/branch/main/config.yml.sample#L313
enabled: true
redirecturl: "https://${vikunja_extra_domain}/auth/openid/"
providers:
- name: Stackspin
authurl: "https://${hydra_domain}/"
clientid: "${client_id}"
clientsecret: "${client_secret}"
local:
enabled: false
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}"
forcessl: true
service:
#rootpath: "/app/vikunja"
#frontendurl: "https://${vikunja_extra_domain}"
timezone: "CET"
JWTSecret: "${jwt}"
motd: "Welcome to ${domain_extra}!"
database:
type: postgres
host: vikunja-postgresql
password: "${postgresql_password}"
# https://vikunja.io/docs/config-options/#log
log:
standard: stderr
level: debug
databaselevel: debug
mail: stderr
maillevel: debug
defaultsettings:
avatar_provider: gravatar
discoverable_by_name: true
discoverable_by_email: true
week_start: 1
timezone: CET
# TODO default_project_id
global:
labels:
stackspin.net/backupSet: "vikunja-extra"
podLabels:
stackspin.net/backupSet: "vikunja-extra"
podAnnotations:
backup.velero.io/backup-volumes: "data"
postgresql:
enabled: true
commonLabels:
stackspin.net/backupSet: "vikunja-extra"
global:
postgresql:
auth:
database: vikunja
username: vikunja
password: "${postgresql_password}"
postgresPassword: "${postgresql_admin_password}"
primary:
persistence:
existingClaim: vikunja-extra-postgres
podAnnotations:
backup.velero.io/backup-volumes: "data"
typesense:
enabled: false