blob: 383c3ae2145534daddeb1e84ac1ce18860598c5e [file] [log] [blame]
Serge Bazanski16842112022-11-17 19:30:05 +00001local kube = import "../../../kube/kube.libsonnet";
2local postgres = import "../../../kube/postgres.libsonnet";
3local 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: {
18 mastodon: "tootsuite/mastodon:v4.0.2@sha256:21c20181a5d44ff553e9e8f7d8d2e53b2551cc8c7ac900760e056445b88e7438",
19 },
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
119 postgres: postgres {
120 cfg+: {
121 namespace: cfg.namespace,
122 appName: "mastodon",
123 database: "mastodon",
124 username: "mastodon",
125 prefix: "waw3-",
126 password: kube.SecretKeyRef(app.config, "postgres-pass"),
127 storageClassName: "waw-hdd-redundant-3",
128 storageSize: "100Gi",
129 },
130 },
131
132 redis: redis {
133 cfg+: {
134 namespace: cfg.namespace,
135 appName: "mastodon",
136 storageClassName: "waw-hdd-redundant-3",
137 prefix: "waw3-",
138 password: kube.SecretKeyRef(app.config, "redis-pass"),
139 },
140 },
141
142 web: ns.Contain(kube.Deployment("web")) {
143 spec+: {
144 minReadySeconds: 10,
145 replicas: cfg.scaling.web,
146 template+: {
147 spec+: {
148 initContainers_: {
149 migrate: kube.Container("migrate") {
150 image: cfg.images.mastodon,
151 env_: app.env {
152 SKIP_POST_DEPLOYMENT_MIGRATIONS: "true",
153 },
154 command: [
155 "bundle", "exec",
156 "rails", "db:migrate",
157 ],
158 },
159 },
160 containers_: {
161 default: kube.Container("default") {
162 image: cfg.images.mastodon,
163 env_: app.env,
164 command: [
165 "bundle", "exec",
166 "rails", "s", "-p", "3000",
167 ],
168 ports_: {
169 web: { containerPort: 3000 },
170 },
171 readinessProbe: {
172 httpGet: {
173 path: "/health",
174 port: "web",
175 },
176 failureThreshold: 10,
177 periodSeconds: 5,
178 },
179 resources: {
180 requests: {
181 cpu: "250m",
182 memory: "1024M",
183 },
184 limits: {
185 cpu: "1",
186 memory: "1024M",
187 },
188 },
189 },
190 },
191 },
192 },
193 },
194 },
195
196 sidekiq: ns.Contain(kube.Deployment("sidekiq")) {
197 spec+: {
198 replicas: cfg.scaling.sidekiq,
199 minReadySeconds: 10,
200 template+: {
201 spec+: {
202 containers_: {
203 default: kube.Container("default") {
204 image: cfg.images.mastodon,
205 env_: app.env,
206 command: [
207 "bundle", "exec",
208 "sidekiq",
209 ],
210 resources: {
211 requests: {
212 cpu: "250m",
213 memory: "1024M",
214 },
215 limits: {
216 cpu: "1",
217 memory: "1024M",
218 },
219 },
220 },
221 },
222 },
223 },
224 },
225 },
226
227 streaming: ns.Contain(kube.Deployment("streaming")) {
228 spec+: {
229 minReadySeconds: 10,
230 template+: {
231 spec+: {
232 containers_: {
233 default: kube.Container("default") {
234 image: cfg.images.mastodon,
235 env_: app.env {
236 "STREAMING_CLUSTER_NUM": "1",
237 },
238 command: [
239 "node", "./streaming",
240 ],
241 ports_: {
242 web: { containerPort: 4000 },
243 },
244 readinessProbe: {
245 httpGet: {
246 path: "/api/v1/streaming/health",
247 port: "web",
248 },
249 failureThreshold: 1,
250 periodSeconds: 5,
251 },
252 resources: {
253 requests: {
254 cpu: "250m",
255 memory: "1024M",
256 },
257 limits: {
258 cpu: "1",
259 memory: "1024M",
260 },
261 },
262 },
263 },
264 },
265 },
266 },
267 },
268
269 svcWeb: ns.Contain(kube.Service("web")) {
270 target_pod: app.web.spec.template,
271 },
272
273 svcStreaming: ns.Contain(kube.Service("streaming")) {
274 target_pod: app.streaming.spec.template,
275 },
276
277
278 ingress: ns.Contain(kube.Ingress("mastodon")) {
279 metadata+: {
280 annotations+: {
281 "kubernetes.io/tls-acme": "true",
282 "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod",
283 "nginx.ingress.kubernetes.io/proxy-body-size": "0",
284 },
285 },
286 spec+: {
287 tls: [
288 {
289 hosts: [cfg.webDomain],
290 secretName: "mastodon-ingress-tls",
291 },
292 ],
293 rules: [
294 {
295 host: cfg.webDomain,
296 http: {
297 paths: [
298 { path: "/", backend: app.svcWeb.name_port },
299 { path: "/api/v1/streaming", backend: app.svcStreaming.name_port },
300 ],
301 },
302 },
303 ],
304 },
305 },
306
307 config: ns.Contain(kube.Secret("config")) {
308 data_: {
309 "postgres-pass": cfg.passwords.postgres,
310 "redis-pass": cfg.passwords.redis,
311
312 "secret-key-base": cfg.secrets.keyBase,
313 "otp-secret": cfg.secrets.otp,
314
315 "vapid-private": cfg.secrets.vapid.private,
316 "vapid-public": cfg.secrets.vapid.public,
317
318 "smtp-password": cfg.smtp.password,
319
320 "object-access-key-id": cfg.objectStorage.accessKeyId,
321 "object-secret-access-key": cfg.objectStorage.secretAccessKey,
322
323 "oidc-client-secret": cfg.oidc.clientSecret,
324 },
325 },
326}