feat: add module3-6

This commit is contained in:
Jan Schnurpfeil 2025-04-28 13:11:47 +02:00
parent 6d6273a33b
commit a4b002dc61
95 changed files with 1848 additions and 1 deletions

1
module3/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
jwt.key

91
module3/README.md Normal file
View file

@ -0,0 +1,91 @@
# Scrumlr K8s Deployment
## Generate JWT Key
```bash
openssl ecparam -genkey -name secp521r1 -noout -out $(git rev-parse --show-toplevel)/module3/k8s/kustomize/scrumlr/jwt.key
```
## Differences in deployment between local minikube cluster and SKE cluster
* Skip PostgreSQL Deployment for SKE deployment, since we use external PostgreSQL
* Set the right `SCRUMLR_SERVER_DATABASE_URL` value in the scrumlr-backend secret
* Minikube: Ingress without Host and external-dns/ cert-manager annotations
* SKE: Ingress with Host and external-dns/ cert-manager annotations
## Deploy Scrumlr into local cluster using minikube
Local Deployment that can run on a lokal K8s cluster like a [minikube](https://minikube.sigs.k8s.io/docs/) cluster.
As we don't have Postgres as an external service here, we also install Postgres directly in our local cluster.
```sh
cd $(git rev-parse --show-toplevel)/module3/k8s/
# Create Cluster with kind and start cloud-provider-kind for Ingress
minikube start
minikube tunnel
# Install ingress-nginx and nats with helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo add nats https://nats-io.github.io/k8s/helm/charts/
helm repo update
helm upgrade \
ingress-nginx ingress-nginx/ingress-nginx \
--install \
--namespace ingress-nginx \
--create-namespace \
--version 4.12.1 \
--values helm/ingress-nginx/values.yaml
helm upgrade \
--install \
nats nats/nats \
--namespace nats \
--create-namespace \
--version 1.3.3 \
--values helm/nats/values.yaml
# Install kustomize applications
kubectl apply -k kustomize/postgres
kubectl apply -k kustomize/scrumlr
# Use external IP of your Ingress Controller in your Browser to open Scrumlr
kubectl get services --namespace ingress-nginx ingress-nginx-controller --output jsonpath='{.status.loadBalancer.ingress[0].ip}'
# Destroy Cluster
minikube stop
minikube delete
```
```shell
# Optional: Connect to your PostgreSQL instance with psql (psql must be installed)
kubectl port-forward -n postgres services/postgres-scrumlr
psql -h localhost -U scrumlr -d scrumlr
# List all tables
scrumlr-# \dt
List of relations
Schema | Name | Type | Owner
--------+------------------------+-------+---------
public | apple_users | table | scrumlr
public | azure_ad_users | table | scrumlr
public | board_session_requests | table | scrumlr
public | board_sessions | table | scrumlr
public | board_templates | table | scrumlr
public | boards | table | scrumlr
public | column_templates | table | scrumlr
public | columns | table | scrumlr
public | deleted_boards | table | scrumlr
public | github_users | table | scrumlr
public | google_users | table | scrumlr
public | microsoft_users | table | scrumlr
public | notes | table | scrumlr
public | oidc_users | table | scrumlr
public | reactions | table | scrumlr
public | schema_migrations | table | scrumlr
public | users | table | scrumlr
public | votes | table | scrumlr
public | votings | table | scrumlr
(19 rows)
```

View file

@ -0,0 +1,15 @@
# ingress-nginx
Docs: https://kubernetes.github.io/ingress-nginx/
Github Repo: https://github.com/kubernetes/ingress-nginx
```sh
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx --force-update
helm upgrade \
ingress-nginx ingress-nginx/ingress-nginx \
--install \
--namespace ingress-nginx \
--create-namespace \
--version 4.12.1 \
--values values.yaml
```

View file

@ -0,0 +1 @@
# Note: This file is intentionally empty and is more of a placeholder to ensure consistency.

View file

@ -0,0 +1,15 @@
# NATS
Docs: https://docs.nats.io/
Github Repo: https://github.com/nats-io/k8s
```sh
helm repo add nats https://nats-io.github.io/k8s/helm/charts/ --force-update
helm upgrade \
--install \
nats nats/nats \
--namespace nats \
--create-namespace \
--version 1.3.3 \
--values values.yaml
```

View file

@ -0,0 +1,4 @@
config:
cluster:
enabled: true
replicas: 3

View file

@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace-postgres.yaml
- statefulset-postgres-scrumlr.yaml
- service-postgres-scrumlr.yaml
- persistentvolumeclaim-postgres-scrumlr.yaml
- secret-postgres-scrumlr.yaml

View file

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: postgres

View file

@ -0,0 +1,15 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-scrumlr
namespace: postgres
labels:
app.kubernetes.io/name: "postgres"
app.kubernetes.io/component: "database"
app.kubernetes.io/part-of: "scrumlr"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi

View file

@ -0,0 +1,14 @@
apiVersion: v1
kind: Secret
metadata:
name: postgres-scrumlr
namespace: postgres
labels:
app.kubernetes.io/name: "postgres"
app.kubernetes.io/component: "database"
app.kubernetes.io/part-of: "scrumlr"
type: Opaque
data:
# echo -n 'super-secret-password' | base64
POSTGRES_USER: c2NydW1scg== # base64 encoded value of 'scrumlr'
POSTGRES_PASSWORD: c3VwZXItc2VjcmV0LXBhc3N3b3Jk # base64 encoded value of 'super-secret-password'

View file

@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: postgres-scrumlr
namespace: postgres
labels:
app.kubernetes.io/name: "postgres"
app.kubernetes.io/component: "database"
app.kubernetes.io/part-of: "scrumlr"
spec:
type: ClusterIP
ports:
- port: 5432
targetPort: 5432
selector:
app.kubernetes.io/name: "postgres"
app.kubernetes.io/component: "database"
app.kubernetes.io/part-of: "scrumlr"

View file

@ -0,0 +1,54 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres-scrumlr
namespace: postgres
labels:
app.kubernetes.io/name: "postgres"
app.kubernetes.io/component: "database"
app.kubernetes.io/part-of: "scrumlr"
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: "postgres"
app.kubernetes.io/component: "database"
app.kubernetes.io/part-of: "scrumlr"
serviceName: "postgres-scrumlr"
template:
metadata:
labels:
app.kubernetes.io/name: "postgres"
app.kubernetes.io/component: "database"
app.kubernetes.io/part-of: "scrumlr"
spec:
containers:
- name: postgres
image: postgres:17.4
resources:
requests:
memory: "256Mi"
cpu: "20m"
limits:
memory: "256Mi"
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-scrumlr
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-scrumlr
key: POSTGRES_PASSWORD
ports:
- containerPort: 5432
volumeMounts:
- name: postgres
mountPath: /var/lib/postgresql/data
subPath: postgres
volumes:
- name: postgres
persistentVolumeClaim:
claimName: postgres-scrumlr

View file

@ -0,0 +1,12 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: scrumlr-backend
labels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "backend"
app.kubernetes.io/part-of: "scrumlr"
data:
SCRUMLR_SERVER_PORT: "8080"
SCRUMLR_BASE_PATH: "/api"
SCRUMLR_SERVER_NATS_URL: "nats.nats.svc.cluster.local:4222"

View file

@ -0,0 +1,61 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: scrumlr-backend
labels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "backend"
app.kubernetes.io/part-of: "scrumlr"
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "backend"
app.kubernetes.io/part-of: "scrumlr"
template:
metadata:
labels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "backend"
app.kubernetes.io/part-of: "scrumlr"
spec:
containers:
- name: backend
image: ghcr.io/inovex/scrumlr.io/scrumlr-server:3.10.3
args:
- "/app/main"
- "-disable-check-origin"
resources:
requests:
cpu: "50m"
memory: "200Mi"
limits:
memory: "200Mi"
startupProbe:
httpGet:
path: /api/health
port: 8080
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /api/health
port: 8080
readinessProbe:
httpGet:
path: /api/health
port: 8080
envFrom:
- configMapRef:
name: scrumlr-backend
- secretRef:
name: scrumlr-backend
env:
- name: SCRUMLR_PRIVATE_KEY
valueFrom:
secretKeyRef:
name: scrumlr-ecdsa-key
key: jwt.key
ports:
- containerPort: 8080

View file

@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- configmap-scrumlr-backend.yaml
- secret-scrumlr-backend.yaml
- deployment-scrumlr-backend.yaml
- service-scrumlr-backend.yaml
- poddisruptionbudget-backend.yaml

View file

@ -0,0 +1,11 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: backend
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "backend"
app.kubernetes.io/part-of: "scrumlr"

View file

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: scrumlr-backend
labels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "backend"
app.kubernetes.io/part-of: "scrumlr"
type: Opaque
data:
SCRUMLR_SERVER_DATABASE_URL: "cG9zdGdyZXM6Ly9zY3J1bWxyOnN1cGVyLXNlY3JldC1wYXNzd29yZEBwb3N0Z3Jlcy1zY3J1bWxyLnBvc3RncmVzLnN2Yy5jbHVzdGVyLmxvY2FsOjU0MzIvc2NydW1scj9zc2xtb2RlPWRpc2FibGU=" # echo -n 'postgres://scrumlr:super-secret-password@postgres-scrumlr.postgres.svc.cluster.local:5432/scrumlr?sslmode=disable' | base64

View file

@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: scrumlr-backend
spec:
selector:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "backend"
app.kubernetes.io/part-of: "scrumlr"
ports:
- port: 8080
targetPort: 8080

View file

@ -0,0 +1,12 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: scrumlr-frontend
labels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "frontend"
app.kubernetes.io/part-of: "scrumlr"
data:
SCRUMLR_SERVER_URL: "/api"
SCRUMLR_SERVER_PORT: "8080"
SCRUMLR_SHOW_LEGAL_DOCUMENTS: "true"

View file

@ -0,0 +1,36 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: scrumlr-frontend
labels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "frontend"
app.kubernetes.io/part-of: "scrumlr"
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "frontend"
app.kubernetes.io/part-of: "scrumlr"
template:
metadata:
labels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "frontend"
app.kubernetes.io/part-of: "scrumlr"
spec:
containers:
- name: frontend
image: ghcr.io/inovex/scrumlr.io/scrumlr-frontend:3.10.3
resources:
requests:
cpu: "25m"
memory: "100Mi"
limits:
memory: "100Mi"
envFrom:
- configMapRef:
name: scrumlr-frontend
ports:
- containerPort: 8080

View file

@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- configmap-scrumlr-frontend.yaml
- deployment-scrumlr-frontend.yaml
- service-scrumlr-frontend.yaml
- poddisruptionbudget-frontend.yaml

View file

@ -0,0 +1,11 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: frontend
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "frontend"
app.kubernetes.io/part-of: "scrumlr"

View file

@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: scrumlr-frontend
spec:
selector:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/component: "frontend"
app.kubernetes.io/part-of: "scrumlr"
ports:
- port: 80
targetPort: 8080

View file

@ -0,0 +1,31 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: scrumlr
labels:
app.kubernetes.io/name: "scrumlr"
app.kubernetes.io/part-of: "scrumlr"
annotations:
nginx.ingress.kubernetes.io/limit-connections: "100"
# Websocket optimization https://kubernetes.github.io/ingress-nginx/user-guide/miscellaneous/#websockets
nginx.ingress.kubernetes.io/proxy-send-timeout: "7200"
nginx.ingress.kubernetes.io/proxy-read-timeout: "7200"
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: scrumlr-backend
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: scrumlr-frontend
port:
number: 80

View file

@ -0,0 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: scrumlr
resources:
- namespace-scrumlr.yaml
- backend/
- frontend/
- ingress-scrumlr.yaml
# Create key: openssl ecparam -genkey -name secp521r1 -noout -out jwt.key
secretGenerator:
- name: scrumlr-ecdsa-key
files:
- jwt.key

View file

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: scrumlr