From a6d3eaf404c802936097a68fdee08ae1f8a3ed14 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 13 Mar 2024 04:43:14 -0600 Subject: [PATCH] add outline --- charts/outline/Chart.yaml | 18 ++ charts/outline/README.md | 17 ++ charts/outline/templates/deployment.yaml | 170 ++++++++++++++++++ charts/outline/templates/ingress.yaml | 32 ++++ .../templates/persistent-volume-claim.yaml | 20 +++ charts/outline/templates/service-account.yaml | 11 ++ charts/outline/templates/service.yaml | 21 +++ charts/outline/values.yaml | 89 +++++++++ 8 files changed, 378 insertions(+) create mode 100644 charts/outline/Chart.yaml create mode 100644 charts/outline/README.md create mode 100644 charts/outline/templates/deployment.yaml create mode 100644 charts/outline/templates/ingress.yaml create mode 100644 charts/outline/templates/persistent-volume-claim.yaml create mode 100644 charts/outline/templates/service-account.yaml create mode 100644 charts/outline/templates/service.yaml create mode 100644 charts/outline/values.yaml diff --git a/charts/outline/Chart.yaml b/charts/outline/Chart.yaml new file mode 100644 index 0000000..ced379b --- /dev/null +++ b/charts/outline/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v2 +name: outline +version: 0.0.1 +description: Chart for Outline wiki +keywords: + - wiki + - documentation +sources: + - https://github.com/outline/outline + - https://github.com/bitnami/charts/tree/main/bitnami/redis +maintainers: + - name: alexlebens +icon: https://avatars.githubusercontent.com/u/1765001?s=48&v=4 +dependencies: + - name: redis + repository: https://charts.bitnami.com/bitnami + version: 18.x.x +appVersion: v0.75.2 diff --git a/charts/outline/README.md b/charts/outline/README.md new file mode 100644 index 0000000..7aa7e4a --- /dev/null +++ b/charts/outline/README.md @@ -0,0 +1,17 @@ +## Introduction + +[Outline](https://github.com/outline/outline) + +The fastest knowledge base for growing teams. Beautiful, realtime collaborative, feature packed, and markdown compatible. + +This chart bootstraps an [Outline](https://github.com/outline/outline) deployment on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Prerequisites + +- Kubernetes +- Helm +- Bitnami Redis Chart + +## Parameters + +See the [values files](values.yaml). diff --git a/charts/outline/templates/deployment.yaml b/charts/outline/templates/deployment.yaml new file mode 100644 index 0000000..3555e5d --- /dev/null +++ b/charts/outline/templates/deployment.yaml @@ -0,0 +1,170 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: outline + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: outline + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: outline +spec: + revisionHistoryLimit: 3 + replicas: {{ .Values.deployment.replicas }} + strategy: + type: {{ .Values.deployment.strategy }} + selector: + matchLabels: + app.kubernetes.io/name: outline + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: outline + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + serviceAccountName: outline + automountServiceAccountToken: true + containers: + - name: {{ .Release.Name }} + image: "{{ .Values.deployment.image.repository }}:{{ .Values.deployment.image.tag }}" + imagePullPolicy: {{ .Values.deployment.image.imagePullPolicy }} + ports: + - name: web + containerPort: {{ .Values.service.web.port }} + protocol: TCP + env: + - name: NODE_ENV + value: "{{ .Values.outline.nodeEnv }}" + - name: URL + value: "{{ .Values.outline.url }}" + - name: PORT + value: "{{ .Values.service.web.port }}" + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: "{{ .Values.outline.secretKey.existingSecretName }}" + key: "{{ .Values.outline.secretKey.existingSecretKey }}" + - name: UTILS_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Values.outline.utilsSecret.existingSecretName }}" + key: "{{ .Values.outline.secretKey.existingSecretKey }}" + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: "{{ .Values.outline.database.passwordSecret.existingSecretName }}" + key: "{{ .Values.outline.database.passwordSecret.existingSecretKey }}" + - name: POSTGRES_USERNAME + valueFrom: + secretKeyRef: + name: "{{ .Values.outline.database.usernameSecret.existingSecretName }}" + key: "{{ .Values.outline.database.usernameSecret.existingSecretKey }}" + - name: POSTGRES_DATABASE_NAME + value: {{ .Values.outline.database.databaseName }} + - name: POSTGRES_DATABASE_HOST + value: {{ .Values.outline.database.databaseHost }} + - name: DATABASE_URL + value: "postgres://$(POSTGRES_USERNAME):$(POSTGRES_PASSWORD)@postgresql-{{ .Release.Name }}-cluster-rw:5432/$(POSTGRES_DATABASE_NAME)" + - name: DATABASE_URL_TEST + value: "postgres://$(POSTGRES_USERNAME):$(POSTGRES_PASSWORD)@postgresql-{{ .Release.Name }}-cluster-rw:5432/$(POSTGRES_DATABASE_NAME)-test" + - name: DATABASE_CONNECTION_POOL_MIN + value: "{{ .Values.outline.database.connectionPoolMin }}" + - name: DATABASE_CONNECTION_POOL_MAX + value: "{{ .Values.outline.database.connectionPoolMax }}" + - name: PGSSLMODE + value: "{{ .Values.outline.database.sslMode }}" + - name: REDIS_URL + value: "redis://{{ .Release.Name }}-redis-master:6379" + - name: FILE_STORAGE + value: "{{ .Values.persistence.type }}" + + {{- if eq .Values.persistence.type "s3" }} + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: "{{ .Values.persistence.s3.credentialsSecret }}" + key: AWS_ACCESS_KEY_ID + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: "{{ .Values.persistence.s3.credentialsSecret }}" + key: AWS_SECRET_ACCESS_KEY + - name: AWS_REGION + value: "{{ .Values.persistence.s3.region }}" + - name: AWS_S3_UPLOAD_BUCKET_NAME + value: "{{ .Values.persistence.s3.bucketName }}" + - name: AWS_S3_UPLOAD_BUCKET_URL + value: "{{ .Values.persistence.s3.endpoint }}" + - name: AWS_S3_FORCE_PATH_STYLE + value: "{{ .Values.persistence.s3.forcePathStyle }}" + - name: AWS_S3_ACL + value: "{{ .Values.persistence.s3.acl }}" + - name: FILE_STORAGE_UPLOAD_MAX_SIZE + value: "{{ .Values.persistence.s3.uploadMaxSize }}" + {{- else if eq .Values.persistence.type "local" }} + - name: FILE_STORAGE_LOCAL_ROOT_DIR + value: "{{ .Values.persistence.local.localRootDir }}" + - name: FILE_STORAGE_UPLOAD_MAX_SIZE + value: "{{ .Values.persistence.local.uploadMaxSize }}" + {{- end }} + + - name: FORCE_HTTPS + value: "{{ .Values.outline.optional.forceHttps }}" + - name: ENABLE_UPDATES + value: "{{ .Values.outline.optional.enableUpdates }}" + - name: WEB_CONCURRENCY + value: "{{ .Values.outline.optional.webConcurrency }}" + - name: MAXIMUM_IMPORT_SIZE + value: "{{ .Values.outline.optional.maximumImportSize }}" + - name: LOG_LEVEL + value: "{{ .Values.outline.optional.logLevel }}" + - name: DEFAULT_LANGUAGE + value: "{{ .Values.outline.optional.defaultLanguage }}" + - name: RATE_LIMITER_ENABLED + value: "{{ .Values.outline.optional.rateLimiter.enabled }}" + - name: RATE_LIMITER_REQUESTS + value: "{{ .Values.outline.optional.rateLimiter.requests }}" + - name: RATE_LIMITER_DURATION_WINDOW + value: "{{ .Values.outline.optional.rateLimiter.durationWindow }}" + - name: DEVELOPMENT_UNSAFE_INLINE_CSP + value: "{{ .Values.outline.optional.developmentUnsafeInlineCsp }}" + + {{- if .Values.outline.auth.oidc.enabled }} + - name: OIDC_CLIENT_ID + valueFrom: + secretKeyRef: + name: "{{ .Values.outline.auth.oidc.clientId.existingSecretName }}" + key: "{{ .Values.outline.auth.oidc.clientId.existingSecretKey }}" + - name: OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Values.outline.auth.oidc.clientSecret.existingSecretName }}" + key: "{{ .Values.outline.auth.oidc.clientSecret.existingSecretKey }}" + - name: OIDC_AUTH_URI + value: "{{ .Values.outline.auth.oidc.authUri }}" + - name: OIDC_TOKEN_URI + value: "{{ .Values.outline.auth.oidc.tokenUri }}" + - name: OIDC_USERINFO_URI + value: "{{ .Values.outline.auth.oidc.userinfoUri }}" + - name: OIDC_USERNAME_CLAIM + value: "{{ .Values.outline.auth.oidc.usernameClaim }}" + - name: OIDC_DISPLAY_NAME + value: "{{ .Values.outline.auth.oidc.displayName }}" + - name: OIDC_SCOPES + value: "{{ .Values.outline.auth.oidc.scopes }}" + {{- end }} + + resources: + {{- toYaml .Values.deployment.resources | nindent 12 }} + + {{- if eq .Values.persistence.type "local" }} + volumeMounts: + - name: "{{ .Release.Name }}-volume-claim" + mountPath: {{ .Values.persistence.local.localRootDir }} + volumes: + - name: "{{ .Release.Name }}-volume-claim" + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-volume-claim" + {{- end }} diff --git a/charts/outline/templates/ingress.yaml b/charts/outline/templates/ingress.yaml new file mode 100644 index 0000000..40c09d8 --- /dev/null +++ b/charts/outline/templates/ingress.yaml @@ -0,0 +1,32 @@ +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: outline-web + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: outline-web + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: outline + annotations: + {{- toYaml .Values.ingress.annotations | nindent 4 }} +spec: + ingressClassName: {{ .Values.ingress.className }} + tls: + - hosts: + - {{ .Values.ingress.host }} + secretName: {{ .Release.Name }}-tls-secret + rules: + - host: {{ .Values.ingress.host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: outline-web + port: + name: web +{{- end }} diff --git a/charts/outline/templates/persistent-volume-claim.yaml b/charts/outline/templates/persistent-volume-claim.yaml new file mode 100644 index 0000000..5be50ca --- /dev/null +++ b/charts/outline/templates/persistent-volume-claim.yaml @@ -0,0 +1,20 @@ +{{- if eq .Values.persistence.type "local" }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-volume-claim + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: outline + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: storage + app.kubernetes.io/part-of: outline +spec: + storageClassName: {{ .Values.persistence.local.storageClassName }} + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.persistence.local.storageSize }} +{{- end }} diff --git a/charts/outline/templates/service-account.yaml b/charts/outline/templates/service-account.yaml new file mode 100644 index 0000000..45cc04c --- /dev/null +++ b/charts/outline/templates/service-account.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: outline + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: outline + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: outline diff --git a/charts/outline/templates/service.yaml b/charts/outline/templates/service.yaml new file mode 100644 index 0000000..9723490 --- /dev/null +++ b/charts/outline/templates/service.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + name: outline-web + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: outline-web + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: web + app.kubernetes.io/part-of: outline +spec: + type: ClusterIP + ports: + - port: {{ .Values.service.web.port }} + targetPort: web + protocol: TCP + name: web + selector: + app.kubernetes.io/name: outline-web + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/charts/outline/values.yaml b/charts/outline/values.yaml new file mode 100644 index 0000000..c3e8ed5 --- /dev/null +++ b/charts/outline/values.yaml @@ -0,0 +1,89 @@ +deployment: + replicas: 1 + strategy: Recreate + image: + repository: outlinewiki/outline + tag: "0.75.2" + imagePullPolicy: IfNotPresent + resources: + requests: + memory: 256Mi + cpu: 50m + limits: + memory: 1Gi + cpu: 500m +service: + web: + port: 3000 +ingress: + enabled: true + className: traefik + annotations: + host: outline.alexlebens.net +persistence: + type: s3 + s3: + credentialsSecret: outline-s3-secret + region: us-east-1 + bucketName: outline + endpoint: + uploadMaxSize: "26214400" + forcePathStyle: false + acl: private + local: + storageClassName: default + storageSize: 50Gi + localRootDir: /var/lib/outline/data + uploadMaxSize: 26214400 +redis: + architecture: standalone + auth: + enabled: false +outline: + nodeEnv: production + url: https://outline.alexlebens.net + secretKey: + existingSecretName: outline-key-secret + existingSecretKey: secret-key + utilsSecret: + existingSecretName: outline-key-secret + existingSecretKey: utils-key + database: + passwordSecret: + existingSecretName: postgresql-outline-cluster-app + existingSecretKey: password + usernameSecret: + existingSecretName: postgresql-outline-cluster-app + existingSecretKey: username + databaseName: app + databaseHost: postgresql-outline-cluster-rw + connectionPoolMin: "" + connectionPoolMax: "20" + sslMode: disable + optional: + forceHttps: false + enableUpdates: false + webConcurrency: 1 + maximumImportSize: 5120000 + logLevel: info + defaultLanguage: en_US + rateLimiter: + enabled: false + requests: 1000 + durationWindow: 60 + developmentUnsafeInlineCsp: false + auth: + oidc: + enabled: true + clientId: + existingSecretName: outline-auth-secret + existingSecretKey: oidc-client-id + clientSecret: + existingSecretName: outline-auth-secret + existingSecretKey: oidc-client-secret + authUri: + tokenUri: + userinfoUri: + usernameClaim: + displayName: + scopes: openid profile email