blob: 6261323f257b6cdac0f87e52a06c6bf04e5ae670 [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: {
Robert Gerus1ad72122023-07-14 12:24:23 +020018 mastodon: "tootsuite/mastodon:v4.0.6@sha256:472c355da5a27b91005dc78c0b5cf75d6baaf1c561c29db1c49ce9168c5de0a9",
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 {
156 SKIP_POST_DEPLOYMENT_MIGRATIONS: "true",
157 },
158 command: [
159 "bundle", "exec",
160 "rails", "db:migrate",
161 ],
162 },
163 },
164 containers_: {
165 default: kube.Container("default") {
166 image: cfg.images.mastodon,
167 env_: app.env,
168 command: [
169 "bundle", "exec",
170 "rails", "s", "-p", "3000",
171 ],
172 ports_: {
173 web: { containerPort: 3000 },
174 },
175 readinessProbe: {
176 httpGet: {
177 path: "/health",
178 port: "web",
179 },
180 failureThreshold: 10,
181 periodSeconds: 5,
182 },
183 resources: {
184 requests: {
185 cpu: "250m",
186 memory: "1024M",
187 },
188 limits: {
189 cpu: "1",
190 memory: "1024M",
191 },
192 },
193 },
194 },
195 },
196 },
197 },
198 },
199
200 sidekiq: ns.Contain(kube.Deployment("sidekiq")) {
201 spec+: {
202 replicas: cfg.scaling.sidekiq,
203 minReadySeconds: 10,
204 template+: {
205 spec+: {
206 containers_: {
207 default: kube.Container("default") {
208 image: cfg.images.mastodon,
209 env_: app.env,
210 command: [
211 "bundle", "exec",
212 "sidekiq",
213 ],
214 resources: {
215 requests: {
216 cpu: "250m",
217 memory: "1024M",
218 },
219 limits: {
220 cpu: "1",
221 memory: "1024M",
222 },
223 },
224 },
225 },
226 },
227 },
228 },
229 },
230
231 streaming: ns.Contain(kube.Deployment("streaming")) {
232 spec+: {
233 minReadySeconds: 10,
234 template+: {
235 spec+: {
236 containers_: {
237 default: kube.Container("default") {
238 image: cfg.images.mastodon,
239 env_: app.env {
240 "STREAMING_CLUSTER_NUM": "1",
241 },
242 command: [
243 "node", "./streaming",
244 ],
245 ports_: {
246 web: { containerPort: 4000 },
247 },
248 readinessProbe: {
249 httpGet: {
250 path: "/api/v1/streaming/health",
251 port: "web",
252 },
253 failureThreshold: 1,
254 periodSeconds: 5,
255 },
256 resources: {
257 requests: {
258 cpu: "250m",
259 memory: "1024M",
260 },
261 limits: {
262 cpu: "1",
263 memory: "1024M",
264 },
265 },
266 },
267 },
268 },
269 },
270 },
271 },
272
273 svcWeb: ns.Contain(kube.Service("web")) {
274 target_pod: app.web.spec.template,
275 },
276
277 svcStreaming: ns.Contain(kube.Service("streaming")) {
278 target_pod: app.streaming.spec.template,
279 },
280
281
282 ingress: ns.Contain(kube.Ingress("mastodon")) {
283 metadata+: {
284 annotations+: {
285 "kubernetes.io/tls-acme": "true",
Piotr Dobrowolski7e841062023-04-23 11:36:15 +0200286 "cert-manager.io/cluster-issuer": "letsencrypt-prod",
Serge Bazanski16842112022-11-17 19:30:05 +0000287 "nginx.ingress.kubernetes.io/proxy-body-size": "0",
288 },
289 },
290 spec+: {
291 tls: [
292 {
293 hosts: [cfg.webDomain],
294 secretName: "mastodon-ingress-tls",
295 },
296 ],
297 rules: [
298 {
299 host: cfg.webDomain,
300 http: {
301 paths: [
302 { path: "/", backend: app.svcWeb.name_port },
303 { path: "/api/v1/streaming", backend: app.svcStreaming.name_port },
304 ],
305 },
306 },
307 ],
308 },
309 },
310
311 config: ns.Contain(kube.Secret("config")) {
312 data_: {
313 "postgres-pass": cfg.passwords.postgres,
314 "redis-pass": cfg.passwords.redis,
315
316 "secret-key-base": cfg.secrets.keyBase,
317 "otp-secret": cfg.secrets.otp,
318
319 "vapid-private": cfg.secrets.vapid.private,
320 "vapid-public": cfg.secrets.vapid.public,
321
322 "smtp-password": cfg.smtp.password,
323
324 "object-access-key-id": cfg.objectStorage.accessKeyId,
325 "object-secret-access-key": cfg.objectStorage.secretAccessKey,
326
327 "oidc-client-secret": cfg.oidc.clientSecret,
328 },
329 },
330}