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