blob: 025eef8a3a997df34fb902d4cdf859576e3b3876 [file] [log] [blame]
Serge Bazanski16842112022-11-17 19:30:05 +00001local kube = import "../../../kube/kube.libsonnet";
Bartosz Stebele3dd96a2022-11-18 23:55:02 +01002local postgres = import "../../../kube/postgres_v.libsonnet";
Serge Bazanski16842112022-11-17 19:30:05 +00003local redis = import "../../../kube/redis.libsonnet";
4
5{
6 local app = self,
7 local cfg = app.cfg,
8
9 cfg:: {
10 namespace: error "cfg.namespace must be set",
11 # Domain as seen in the fediverse.
12 localDomain: error "cfg.localDomain must be set",
13 # Domain where the web interface is running. If different,
14 # localDomain's real server must be configured to forward
15 # /.well-known/webfinger to webDomain.
16 webDomain: cfg.localDomain,
17 images: {
Bartosz Stebel4703e552023-10-09 00:57:10 +020018 mastodon: "tootsuite/mastodon:v4.1.9@sha256:525032827b5438c47670f44194e4adaed9f2c46f39c28cb37e9feb54b93b9ebf",
Serge Bazanski16842112022-11-17 19:30:05 +000019 },
20 passwords: {
21 # generate however you like
22 postgres: error "cfg.secrets.postgres must be set",
23 # generate however you like
24 redis: error "cfg.secrets.redis must be set",
25 },
26 smtp: {
27 user: "mastodon",
28 from: "mastodon-noreply@hackerspace.pl",
29 # from mail server
30 password: error "cfg.smtp.password must be set",
31 },
32 secrets: {
33 # generate with podman run --rm -it tootsuite/mastodon:v4.0.2 bundle exec rake secret
34 keyBase: error "cfg.secrets.keyBase must be set",
35 # generate with podman run --rm -it tootsuite/mastodon:v4.0.2 bundle exec rake secret
36 otp: error "cfg.secrets.otp must be set",
37 # generate with podman run --rm -it tootsuite/mastodon:v4.0.2 bundle exec rake mastodon:webpush:generate_vapid_key
38 vapid: {
39 private: error "cfg.secrets.vapid.private must be set",
40 public: error "cfg.secrets.vapid.public must be set",
41 }
42 },
43 oidc: {
44 clientID: error "cfg.oidc.clientID must be set",
45 clientSecret: error "cfg.oidc.clientSecret must be set",
46 },
47 objectStorage: {
48 bucket: error "cfg.objectStorage.bucket must be set",
49 accessKeyId: error "cfg.objectStorage.accessKeyId must be set",
50 secretAccessKey: error "cfg.objectStorage.secretAccessKey must be set",
51 },
52
53 scaling: {
54 web: 1,
55 sidekiq: 1,
56 },
57 },
58
59 // Unified env var based config used for {web, streaming, sidekiq}.
60 // Sample available in https://github.com/mastodon/mastodon/blob/main/.env.production.sample
61 env:: {
62 LOCAL_DOMAIN: cfg.localDomain,
63 WEB_DOMAIN: cfg.webDomain,
64
65 // REDIS_PASS is not used directly by the apps, it's just used to embed
66 // a secret fragment into REDIS_URL.
67 REDIS_PASS: kube.SecretKeyRef(app.config, "redis-pass"),
68 REDIS_URL: "redis://:$(REDIS_PASS)@%s" % [app.redis.svc.host_colon_port],
69
70 DB_HOST: app.postgres.svc.host,
71 DB_USER: "mastodon",
72 DB_NAME: "mastodon",
73 DB_PASS: kube.SecretKeyRef(app.config, "postgres-pass"),
74 DB_PORT: "5432",
75
76 ES_ENABLED: "false",
77
78 SECRET_KEY_BASE: kube.SecretKeyRef(app.config, "secret-key-base"),
79 OTP_SECRET: kube.SecretKeyRef(app.config, "otp-secret"),
80
81 VAPID_PRIVATE_KEY: kube.SecretKeyRef(app.config, "vapid-private"),
82 VAPID_PUBLIC_KEY: kube.SecretKeyRef(app.config, "vapid-public"),
83
84 SMTP_SERVER: "mail.hackerspace.pl",
85 SMTP_PORT: "587",
86 SMTP_LOGIN: "mastodon",
87 SMTP_PASSWORD: kube.SecretKeyRef(app.config, "smtp-password"),
88 SMTP_FROM_ADDRESS: "mastodon-noreply@hackerspace.pl",
89
90 S3_ENABLED: "true",
91 S3_BUCKET: cfg.objectStorage.bucket,
92 AWS_ACCESS_KEY_ID: kube.SecretKeyRef(app.config, "object-access-key-id"),
93 AWS_SECRET_ACCESS_KEY: kube.SecretKeyRef(app.config, "object-secret-access-key"),
94 S3_HOSTNAME: "object.ceph-waw3.hswaw.net",
95 S3_ENDPOINT: "https://object.ceph-waw3.hswaw.net",
96
97 IP_RETENTION_PERIOD: "31556952",
98 SESSION_RETENTION_PERIOD: "31556952",
99
100 OIDC_ENABLED: "true",
101 OIDC_DISPLAY_NAME: "Use Warsaw Hackerspace SSO",
102 OIDC_ISSUER: "https://sso.hackerspace.pl",
103 OIDC_DISCOVERY: "false",
104 OIDC_SCOPE: "openid,profile:read",
105 OIDC_UID_FIELD: "uid",
106 OIDC_CLIENT_ID: cfg.oidc.clientId,
107 OIDC_REDIRECT_URI: "https://%s/auth/auth/openid_connect/callback" % [cfg.webDomain],
108 OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED: "true",
109 OIDC_CLIENT_SECRET: kube.SecretKeyRef(app.config, "oidc-client-secret"),
110 OIDC_AUTH_ENDPOINT: "https://sso.hackerspace.pl/oauth/authorize",
111 OIDC_TOKEN_ENDPOINT: "https://sso.hackerspace.pl/oauth/token",
112 OIDC_USER_INFO_ENDPOINT: "https://sso.hackerspace.pl/api/1/userinfo",
113 OIDC_JWKS_URI: "https://sso.hackerspace.pl/.well-known/jwks.json",
114 },
115
116 namespace: kube.Namespace(cfg.namespace),
117 local ns = self.namespace,
118
Bartosz Stebele3dd96a2022-11-18 23:55:02 +0100119 # there used to be a nonversioned postgres (10.4) here
120 # at time of writing it exists in prod, scaled down to 0, to preserve the PVC
Serge Bazanski16842112022-11-17 19:30:05 +0000121 postgres: postgres {
122 cfg+: {
Bartosz Stebel65b30af2022-11-18 14:45:55 +0100123 version: "13.9",
124 namespace: cfg.namespace,
125 appName: "mastodon",
126 database: "mastodon",
127 username: "mastodon",
128 prefix: "waw3-",
129 password: kube.SecretKeyRef(app.config, "postgres-pass"),
130 storageClassName: "waw-hdd-redundant-3",
131 storageSize: "100Gi",
132 opts: { wal_level: "logical" },
Serge Bazanski16842112022-11-17 19:30:05 +0000133 },
134 },
135
136 redis: redis {
137 cfg+: {
138 namespace: cfg.namespace,
139 appName: "mastodon",
140 storageClassName: "waw-hdd-redundant-3",
141 prefix: "waw3-",
142 password: kube.SecretKeyRef(app.config, "redis-pass"),
143 },
144 },
145
146 web: ns.Contain(kube.Deployment("web")) {
147 spec+: {
148 minReadySeconds: 10,
149 replicas: cfg.scaling.web,
150 template+: {
151 spec+: {
152 initContainers_: {
153 migrate: kube.Container("migrate") {
154 image: cfg.images.mastodon,
155 env_: app.env {
Bartosz Stebel4703e552023-10-09 00:57:10 +0200156 //That's confusing one - all the random "how to mastodon in docker" tutorials
157 //say you need to set it. However, with this set, the web dashboard was sad
158 //about unfinished migrations.
159 //I can't obviously tell if we'd ever want this to be enabled though.
160 //Leaving it commented out here for now.
161 //SKIP_POST_DEPLOYMENT_MIGRATIONS: "true",
Serge Bazanski16842112022-11-17 19:30:05 +0000162 },
163 command: [
164 "bundle", "exec",
165 "rails", "db:migrate",
166 ],
167 },
168 },
169 containers_: {
170 default: kube.Container("default") {
171 image: cfg.images.mastodon,
172 env_: app.env,
173 command: [
174 "bundle", "exec",
175 "rails", "s", "-p", "3000",
176 ],
177 ports_: {
178 web: { containerPort: 3000 },
179 },
180 readinessProbe: {
181 httpGet: {
182 path: "/health",
183 port: "web",
184 },
185 failureThreshold: 10,
186 periodSeconds: 5,
187 },
188 resources: {
189 requests: {
190 cpu: "250m",
191 memory: "1024M",
192 },
193 limits: {
194 cpu: "1",
195 memory: "1024M",
196 },
197 },
198 },
199 },
200 },
201 },
202 },
203 },
204
205 sidekiq: ns.Contain(kube.Deployment("sidekiq")) {
206 spec+: {
207 replicas: cfg.scaling.sidekiq,
208 minReadySeconds: 10,
209 template+: {
210 spec+: {
211 containers_: {
212 default: kube.Container("default") {
213 image: cfg.images.mastodon,
214 env_: app.env,
215 command: [
216 "bundle", "exec",
217 "sidekiq",
218 ],
219 resources: {
220 requests: {
221 cpu: "250m",
222 memory: "1024M",
223 },
224 limits: {
225 cpu: "1",
226 memory: "1024M",
227 },
228 },
229 },
230 },
231 },
232 },
233 },
234 },
235
236 streaming: ns.Contain(kube.Deployment("streaming")) {
237 spec+: {
238 minReadySeconds: 10,
239 template+: {
240 spec+: {
241 containers_: {
242 default: kube.Container("default") {
243 image: cfg.images.mastodon,
244 env_: app.env {
245 "STREAMING_CLUSTER_NUM": "1",
246 },
247 command: [
248 "node", "./streaming",
249 ],
250 ports_: {
251 web: { containerPort: 4000 },
252 },
253 readinessProbe: {
254 httpGet: {
255 path: "/api/v1/streaming/health",
256 port: "web",
257 },
258 failureThreshold: 1,
259 periodSeconds: 5,
260 },
261 resources: {
262 requests: {
263 cpu: "250m",
264 memory: "1024M",
265 },
266 limits: {
267 cpu: "1",
268 memory: "1024M",
269 },
270 },
271 },
272 },
273 },
274 },
275 },
276 },
277
278 svcWeb: ns.Contain(kube.Service("web")) {
radex8b8f3872023-11-24 11:09:46 +0100279 target:: app.web,
Serge Bazanski16842112022-11-17 19:30:05 +0000280 },
281
282 svcStreaming: ns.Contain(kube.Service("streaming")) {
radex8b8f3872023-11-24 11:09:46 +0100283 target:: app.streaming,
Serge Bazanski16842112022-11-17 19:30:05 +0000284 },
285
286
287 ingress: ns.Contain(kube.Ingress("mastodon")) {
Bartosz Stebel4703e552023-10-09 00:57:10 +0200288 // TODO(https://issues.hackerspace.pl/issues/74): mastodon's docs say we should enable CSP. Figure it out.
Serge Bazanski16842112022-11-17 19:30:05 +0000289 metadata+: {
290 annotations+: {
291 "kubernetes.io/tls-acme": "true",
Piotr Dobrowolski7e841062023-04-23 11:36:15 +0200292 "cert-manager.io/cluster-issuer": "letsencrypt-prod",
Serge Bazanski16842112022-11-17 19:30:05 +0000293 "nginx.ingress.kubernetes.io/proxy-body-size": "0",
294 },
295 },
296 spec+: {
297 tls: [
298 {
299 hosts: [cfg.webDomain],
300 secretName: "mastodon-ingress-tls",
301 },
302 ],
303 rules: [
304 {
305 host: cfg.webDomain,
306 http: {
307 paths: [
308 { path: "/", backend: app.svcWeb.name_port },
309 { path: "/api/v1/streaming", backend: app.svcStreaming.name_port },
310 ],
311 },
312 },
313 ],
314 },
315 },
316
317 config: ns.Contain(kube.Secret("config")) {
318 data_: {
319 "postgres-pass": cfg.passwords.postgres,
320 "redis-pass": cfg.passwords.redis,
321
322 "secret-key-base": cfg.secrets.keyBase,
323 "otp-secret": cfg.secrets.otp,
324
325 "vapid-private": cfg.secrets.vapid.private,
326 "vapid-public": cfg.secrets.vapid.public,
327
328 "smtp-password": cfg.smtp.password,
329
330 "object-access-key-id": cfg.objectStorage.accessKeyId,
331 "object-secret-access-key": cfg.objectStorage.secretAccessKey,
332
333 "oidc-client-secret": cfg.oidc.clientSecret,
334 },
335 },
336}