Compare commits
1
Commits
507b2225b1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e91586b968
|
@@ -6,12 +6,13 @@ SIGNUP_URL = "https://www.eom.dev/members"
|
|||||||
|
|
||||||
# OIDC is the only login method left, so with auth_immediately the
|
# OIDC is the only login method left, so with auth_immediately the
|
||||||
# Log In button redirects straight to Dex. Accounts link by email.
|
# Log In button redirects straight to Dex. Accounts link by email.
|
||||||
SiteSetting.ldap_enabled = false
|
|
||||||
SiteSetting.enable_local_logins = false
|
SiteSetting.enable_local_logins = false
|
||||||
SiteSetting.auth_immediately = true
|
SiteSetting.auth_immediately = true
|
||||||
# New members sign up at www.eom.dev; Discourse must still create their
|
# New members sign up at www.eom.dev; Discourse must still create their
|
||||||
# account on first Dex login.
|
# account on first Dex login.
|
||||||
SiteSetting.allow_new_registrations = true
|
SiteSetting.allow_new_registrations = true
|
||||||
|
# Chat is bundled in core and on by default; this forum does not use it.
|
||||||
|
SiteSetting.chat_enabled = false
|
||||||
|
|
||||||
head_tag = <<~HTML
|
head_tag = <<~HTML
|
||||||
<script>
|
<script>
|
||||||
@@ -40,5 +41,5 @@ Theme.where(component: false).find_each do |theme|
|
|||||||
theme.add_relative_theme!(:child, component)
|
theme.add_relative_theme!(:child, component)
|
||||||
end
|
end
|
||||||
|
|
||||||
puts "ldap_enabled=#{SiteSetting.ldap_enabled} component=#{component.id} " \
|
puts "enable_local_logins=#{SiteSetting.enable_local_logins} component=#{component.id} " \
|
||||||
"parents=#{component.parent_themes.pluck(:name).join(', ')}"
|
"parents=#{component.parent_themes.pluck(:name).join(', ')}"
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
# Discourse v2026.10.0, built with the official launcher (see web_only.yml).
|
||||||
|
# Reuses the existing Bitnami-era uploads volume, Redis and Kubernetes secrets.
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: discourse-web
|
||||||
|
namespace: discourse
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: discourse-web
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: discourse-web
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: discourse-web
|
||||||
|
spec:
|
||||||
|
# The image is 3.77 GB and most nodes have only 3-8 GB free; pulling it
|
||||||
|
# elsewhere risks DiskPressure and evicting the MetalLB speakers.
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: alpha-worker-0
|
||||||
|
initContainers:
|
||||||
|
# The launcher image runs Discourse as uid 1000; Bitnami used 999.
|
||||||
|
- name: fix-ownership
|
||||||
|
image: gitea.eom.dev/devops/discourse-web:v2026.10.0
|
||||||
|
command: ["sh", "-c", "chown -R 1000:1000 /shared/uploads /shared/backups"]
|
||||||
|
volumeMounts:
|
||||||
|
- name: discourse-data
|
||||||
|
mountPath: /shared/uploads
|
||||||
|
subPath: discourse/public/uploads
|
||||||
|
- name: discourse-data
|
||||||
|
mountPath: /shared/backups
|
||||||
|
subPath: discourse/public/backups
|
||||||
|
containers:
|
||||||
|
- name: discourse
|
||||||
|
image: gitea.eom.dev/devops/discourse-web:v2026.10.0
|
||||||
|
command: ["/sbin/boot"]
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 80
|
||||||
|
env:
|
||||||
|
- { name: RAILS_ENV, value: production }
|
||||||
|
- { name: LANG, value: en_US.UTF-8 }
|
||||||
|
- { name: LC_ALL, value: en_US.UTF-8 }
|
||||||
|
- { name: MIGRATE_ON_BOOT, value: "1" }
|
||||||
|
- { name: PRECOMPILE_ON_BOOT, value: "1" }
|
||||||
|
- { name: CREATE_DB_ON_BOOT, value: "0" }
|
||||||
|
- { name: UNICORN_WORKERS, value: "2" }
|
||||||
|
- { name: UNICORN_SIDEKIQS, value: "1" }
|
||||||
|
- { name: DISCOURSE_HOSTNAME, value: discourse.eom.dev }
|
||||||
|
- { name: DISCOURSE_DB_SOCKET, value: "" }
|
||||||
|
- { name: DISCOURSE_DB_HOST, value: discourse-postgres18 }
|
||||||
|
- { name: DISCOURSE_DB_NAME, value: bitnami_application }
|
||||||
|
- { name: DISCOURSE_DB_USERNAME, value: bn_discourse }
|
||||||
|
- name: DISCOURSE_DB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef: { name: discourse-postgresql, key: password }
|
||||||
|
- { name: DISCOURSE_REDIS_HOST, value: discourse-redis-master }
|
||||||
|
- name: DISCOURSE_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef: { name: discourse-redis, key: redis-password }
|
||||||
|
- { name: DISCOURSE_SMTP_ADDRESS, value: postfix.eom.dev }
|
||||||
|
- { name: DISCOURSE_SMTP_PORT, value: "587" }
|
||||||
|
- { name: DISCOURSE_SMTP_USER_NAME, value: discourse }
|
||||||
|
- name: DISCOURSE_SMTP_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef: { name: discourse-discourse, key: smtp-password }
|
||||||
|
startupProbe:
|
||||||
|
httpGet: &status
|
||||||
|
path: /srv/status
|
||||||
|
port: http
|
||||||
|
httpHeaders:
|
||||||
|
- { name: Host, value: discourse.eom.dev }
|
||||||
|
- { name: X-Forwarded-Proto, value: https }
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 180
|
||||||
|
readinessProbe:
|
||||||
|
httpGet: *status
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 6
|
||||||
|
livenessProbe:
|
||||||
|
httpGet: *status
|
||||||
|
periodSeconds: 20
|
||||||
|
failureThreshold: 6
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 1Gi
|
||||||
|
volumeMounts:
|
||||||
|
- name: shared
|
||||||
|
mountPath: /shared
|
||||||
|
- name: discourse-data
|
||||||
|
mountPath: /shared/uploads
|
||||||
|
subPath: discourse/public/uploads
|
||||||
|
- name: discourse-data
|
||||||
|
mountPath: /shared/backups
|
||||||
|
subPath: discourse/public/backups
|
||||||
|
volumes:
|
||||||
|
- name: shared
|
||||||
|
emptyDir: {}
|
||||||
|
- name: discourse-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: discourse
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
# PostgreSQL 18 with pgvector for Discourse. Runs alongside the old Bitnami
|
||||||
|
# PostgreSQL 17 StatefulSet, whose volume stays untouched for rollback.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: discourse-postgres18
|
||||||
|
namespace: discourse
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: discourse-postgres18
|
||||||
|
spec:
|
||||||
|
clusterIP: None
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: discourse-postgres18
|
||||||
|
ports:
|
||||||
|
- name: postgresql
|
||||||
|
port: 5432
|
||||||
|
targetPort: postgresql
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: discourse-postgres18
|
||||||
|
namespace: discourse
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: discourse-postgres18
|
||||||
|
spec:
|
||||||
|
serviceName: discourse-postgres18
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: discourse-postgres18
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: discourse-postgres18
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: postgresql
|
||||||
|
image: pgvector/pgvector:pg18
|
||||||
|
ports:
|
||||||
|
- name: postgresql
|
||||||
|
containerPort: 5432
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
value: postgres
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: discourse-postgresql
|
||||||
|
key: postgres-password
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["pg_isready", "-U", "postgres", "-h", "127.0.0.1"]
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 6
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["pg_isready", "-U", "postgres", "-h", "127.0.0.1"]
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 6
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/lib/postgresql
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
storageClassName: nfs-client
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Ti
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Build-only config for the eom.dev Discourse image. No secrets belong here:
|
||||||
|
# database, Redis and SMTP credentials are supplied at runtime by Kubernetes.
|
||||||
|
templates:
|
||||||
|
- "templates/web.template.yml"
|
||||||
|
- "templates/web.ratelimited.template.yml"
|
||||||
|
|
||||||
|
params:
|
||||||
|
version: v2026.10.0
|
||||||
|
|
||||||
|
env:
|
||||||
|
LC_ALL: en_US.UTF-8
|
||||||
|
LANG: en_US.UTF-8
|
||||||
|
LANGUAGE: en_US.UTF-8
|
||||||
|
DISCOURSE_HOSTNAME: discourse.eom.dev
|
||||||
|
DISABLE_LETSENCRYPT: 1
|
||||||
|
|
||||||
|
# Everything else the forum uses (openid-connect, reactions, math, post-voting,
|
||||||
|
# adplugin, subscriptions, chat) is bundled in core at this version.
|
||||||
|
hooks:
|
||||||
|
after_code:
|
||||||
|
- exec:
|
||||||
|
cd: $home/plugins
|
||||||
|
cmd:
|
||||||
|
- git clone https://github.com/discourse/discourse-activity-pub.git
|
||||||
|
- git clone https://github.com/discourse/discourse-prometheus.git
|
||||||
|
|
||||||
|
run:
|
||||||
|
# ingress-nginx terminates TLS, so trust its X-Forwarded-For only from the pod
|
||||||
|
# network. Without this every visitor shares the ingress IP and hits rate limits.
|
||||||
|
- file:
|
||||||
|
path: /etc/nginx/conf.d/outlets/server/real-ip.conf
|
||||||
|
chmod: 644
|
||||||
|
contents: |
|
||||||
|
set_real_ip_from 10.244.0.0/16;
|
||||||
|
real_ip_header X-Forwarded-For;
|
||||||
|
real_ip_recursive on;
|
||||||
+47
-81
@@ -1,90 +1,57 @@
|
|||||||
---
|
---
|
||||||
# tasks file for discourse
|
# tasks file for discourse
|
||||||
|
#
|
||||||
|
# Discourse runs from an image built with the official launcher; the Bitnami
|
||||||
|
# chart stops at 3.5.0. To upgrade, change params.version in
|
||||||
|
# files/discourse/web_only.yml, then from a discourse_docker checkout:
|
||||||
|
# cp <role>/files/discourse/web_only.yml containers/web_only.yml
|
||||||
|
# launcher build --set base_image=<base_image from templates/web.template.yml>-web-only \
|
||||||
|
# --tag gitea.eom.dev/devops/discourse-web:<version> web_only --output=type=docker
|
||||||
|
# Push it, update the image tag in files/discourse/discourse-web.yaml, and re-run.
|
||||||
|
#
|
||||||
|
# Pushing through the gitea ingress needs proxy-body-size raised and
|
||||||
|
# proxy-request-buffering "off" for the push, then restored. With buffering on,
|
||||||
|
# ingress-nginx writes layers to its node's small disk; on 2026-11-08 that caused
|
||||||
|
# DiskPressure, evicted the MetalLB speaker, and took the public sites down.
|
||||||
|
#
|
||||||
|
# Redis, the secrets, the uploads PVC, the Service and the Ingress still come from
|
||||||
|
# the original Helm release, which must stay installed but is no longer upgraded.
|
||||||
|
- name: Deploy PostgreSQL 18 for Discourse
|
||||||
|
kubernetes.core.k8s:
|
||||||
|
state: present
|
||||||
|
src: "{{ role_path }}/files/discourse/postgres18.yaml"
|
||||||
|
|
||||||
- name: Deploy Discourse
|
- name: Deploy Discourse
|
||||||
kubernetes.core.helm:
|
kubernetes.core.k8s:
|
||||||
name: discourse
|
state: present
|
||||||
chart_ref: bitnami/discourse
|
src: "{{ role_path }}/files/discourse/discourse-web.yaml"
|
||||||
release_namespace: discourse
|
wait: true
|
||||||
create_namespace: true
|
wait_condition:
|
||||||
values:
|
type: Available
|
||||||
auth:
|
status: "True"
|
||||||
email: discourse@eom.dev
|
wait_timeout: 1800
|
||||||
username: discourse_admin
|
|
||||||
password: "{{ discourse_admin_password }}"
|
- name: Point the Discourse Service at the launcher-built pods
|
||||||
host: "https://discourse.eom.dev"
|
kubernetes.core.k8s:
|
||||||
siteName: 'Discourse'
|
state: present
|
||||||
smtp:
|
merge_type: merge
|
||||||
enabled: true
|
definition:
|
||||||
host: "postfix.eom.dev"
|
apiVersion: v1
|
||||||
port: "587"
|
kind: Service
|
||||||
protocol: "tls"
|
metadata:
|
||||||
user: "discourse"
|
name: discourse
|
||||||
password: "{{ discourse_admin_password }}"
|
namespace: discourse
|
||||||
image:
|
spec:
|
||||||
debug: false
|
selector:
|
||||||
repository: bitnamilegacy/discourse
|
app.kubernetes.io/name: discourse-web
|
||||||
tag: 3.4.7-debian-12-r0
|
app.kubernetes.io/instance: null
|
||||||
service:
|
|
||||||
externalTrafficPolicy: Local
|
|
||||||
discourse:
|
|
||||||
skipInstall: false
|
|
||||||
plugins:
|
|
||||||
- https://github.com/discourse/discourse-adplugin
|
|
||||||
- https://github.com/discourse/discourse-subscriptions
|
|
||||||
- https://github.com/discourse/discourse-activity-pub
|
|
||||||
- https://github.com/discourse/discourse-openid-connect
|
|
||||||
# discourse-ldap-auth removed: its login cannot be disabled by setting,
|
|
||||||
# and sign-in goes through Dex (discourse-openid-connect) only.
|
|
||||||
- https://github.com/discourse/discourse-math
|
|
||||||
- https://github.com/discourse/discourse-post-voting
|
|
||||||
- https://github.com/discourse/discourse-prometheus
|
|
||||||
- https://github.com/discourse/discourse-reactions
|
|
||||||
command:
|
|
||||||
- /bin/bash
|
|
||||||
args:
|
|
||||||
- -c
|
|
||||||
- |
|
|
||||||
rm -r /opt/bitnami/discourse/plugins/chat
|
|
||||||
chown -R discourse:root /opt/bitnami/discourse/plugins
|
|
||||||
/opt/bitnami/scripts/discourse/entrypoint.sh /opt/bitnami/scripts/discourse/run.sh
|
|
||||||
persistPlugins: false
|
|
||||||
compatiblePlugins: true
|
|
||||||
resourcesPreset: none
|
|
||||||
persistence:
|
|
||||||
size: 2Ti
|
|
||||||
ingress:
|
|
||||||
enabled: true
|
|
||||||
ingressClassName: "nginx"
|
|
||||||
hostname: discourse.eom.dev
|
|
||||||
annotations:
|
|
||||||
cert-manager.io/cluster-issuer: ca-issuer
|
|
||||||
nginx.ingress.kubernetes.io/proxy-set-header: "X-Forwarded-Proto $scheme"
|
|
||||||
tls: true
|
|
||||||
postgresql:
|
|
||||||
enabled: true
|
|
||||||
image:
|
|
||||||
repository: bitnamilegacy/postgresql
|
|
||||||
auth:
|
|
||||||
enablePostgresUser: true
|
|
||||||
postgresPassword: "{{ discourse_admin_password }}"
|
|
||||||
password: "{{ discourse_admin_password }}"
|
|
||||||
primary:
|
|
||||||
persistence:
|
|
||||||
size: 2Ti
|
|
||||||
redis:
|
|
||||||
enabled: true
|
|
||||||
image:
|
|
||||||
repository: bitnamilegacy/redis
|
|
||||||
auth:
|
|
||||||
password: "{{ discourse_admin_password }}"
|
|
||||||
|
|
||||||
- name: Find the Discourse pod
|
- name: Find the Discourse pod
|
||||||
kubernetes.core.k8s_info:
|
kubernetes.core.k8s_info:
|
||||||
kind: Pod
|
kind: Pod
|
||||||
namespace: discourse
|
namespace: discourse
|
||||||
label_selectors:
|
label_selectors:
|
||||||
- app.kubernetes.io/instance=discourse
|
- app.kubernetes.io/name=discourse-web
|
||||||
- app.kubernetes.io/name=discourse
|
|
||||||
field_selectors:
|
field_selectors:
|
||||||
- status.phase=Running
|
- status.phase=Running
|
||||||
register: discourse_pods
|
register: discourse_pods
|
||||||
@@ -103,8 +70,7 @@
|
|||||||
pod: "{{ discourse_pods.resources[0].metadata.name }}"
|
pod: "{{ discourse_pods.resources[0].metadata.name }}"
|
||||||
container: discourse
|
container: discourse
|
||||||
command: >-
|
command: >-
|
||||||
bash -c 'cd /opt/bitnami/discourse && PATH=/opt/bitnami/ruby/bin:$PATH
|
bash -c 'cd /var/www/discourse && su discourse -c
|
||||||
RAILS_ENV=production bundle exec ruby -e
|
"RAILS_ENV=production bundle exec rails runner /tmp/discourse-sso.rb"'
|
||||||
"require \"/opt/bitnami/discourse/config/environment\"; load \"/tmp/discourse-sso.rb\""'
|
|
||||||
register: discourse_sso
|
register: discourse_sso
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|||||||
Reference in New Issue
Block a user