blob: cca39edc63b0dc0c9fa0e134947ba441e98bee0d [file] [log] [blame]
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +02001# Mirko, an abstraction layer for hscloud kubernetes services.
2
3local kube = import "kube.libsonnet";
4
5{
6 Environment(name): {
7 local env = self,
8 local cfg = env.cfg,
9 cfg:: {
10 name: name,
11 namespace: cfg.name,
12 },
13
14 namespace: kube.Namespace(cfg.namespace),
15
16 components: {}, // type: mirko.Component
17
18 // Currently hardcoded!
19 // This might end up being something passed part of kubecfg evaluation,
20 // when we get to supporting multiple/federated clusters.
21 // For now, this is goog enough.
22 pkiRealm:: "hswaw.net",
23 pkiClusterFQDN:: "k0.hswaw.net",
24
25 // Generate an ingress if we have any public ports.
26 publicHTTPPorts:: std.flattenArrays([
27 [
28 {
29 local component = env.components[c],
30
31 service: component.svc,
32 port: component.cfg.ports.publicHTTP[p].port,
33 dns: component.cfg.ports.publicHTTP[p].dns,
Sergiusz Bazanski91e1a8c2020-06-25 12:16:29 +020034 // Extra headers to set.
35 // BUG(q3k): these headers are applied to all components in the environment!
36 // We should be splitting up ingresses where necessary to combat this.
37 setHeaders: [],
38 // Extra paths to add to ingress. These are bare HTTPIngressPaths.
39 extraPaths: component.cfg.extraPaths,
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +020040 }
41 for p in std.objectFields(env.components[c].cfg.ports.publicHTTP)
42 ]
43 for c in std.objectFields(env.components)
44 ]),
45
46 ingress: if std.length(env.publicHTTPPorts) > 0 then kube.Ingress("mirko-public") {
47 metadata+: {
48 namespace: env.cfg.namespace,
49 labels: {
50 "app.kubernetes.io/name": cfg.name,
51 "app.kubernetes.io/managed-by": "kubecfg-mirko",
52 "app.kubernetes.io/component": cfg.name,
53 "mirko.hscloud.hackerspace.pl/environment": env.cfg.name,
54 "mirko.hscloud.hackerspace.pl/component": "mirko-public-ingress",
55 },
56 annotations+: {
57 "kubernetes.io/tls-acme": "true",
Piotr Dobrowolski7e841062023-04-23 11:36:15 +020058 "cert-manager.io/cluster-issuer": "letsencrypt-prod",
Serge Bazanski15db04c2020-08-10 18:55:22 +020059 [if env.ingressServerSnippet != null then "nginx.ingress.kubernetes.io/server-snippet"]: env.ingressServerSnippet,
Sergiusz Bazanski91e1a8c2020-06-25 12:16:29 +020060 [if std.length(env.extraHeaders) > 0 then "nginx.ingress.kubernetes.io/configuration-snippet"]:
61 std.join("\n", ["proxy_set_header %s;" % [h] for h in env.extraHeaders]),
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +020062 },
63 },
64 spec+: {
65 tls: [
66 {
67 hosts: [p.dns for p in env.publicHTTPPorts],
68 secretName: "mirko-public-tls",
69 },
70 ],
71 rules: [
72 {
73 host: p.dns,
74 http: {
75 paths: [
76 { path: "/", backend: { serviceName: p.service.metadata.name, servicePort: p.port }},
Sergiusz Bazanski91e1a8c2020-06-25 12:16:29 +020077 ] + p.extraPaths,
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +020078 },
79 }
80 for p in env.publicHTTPPorts
81 ],
82 },
Sergiusz Bazanski91e1a8c2020-06-25 12:16:29 +020083 } else {},
84
85 // Nginx Ingress Controller server configuration snippet to add.
86 ingressServerSnippet:: null,
87
88 // Extra request headers to add to ingress
89 extraHeaders:: std.flattenArrays([
90 std.flattenArrays([
91
92 local portc = env.components[c].cfg.ports.publicHTTP[p];
93 if std.objectHas(portc, "setHeaders") then portc.setHeaders else []
94 for p in std.objectFields(env.components[c].cfg.ports.publicHTTP)
95 ])
96 for c in std.objectFields(env.components)
97 ]),
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +020098 },
99
100 Component(env, name): {
101 local component = self,
102 local cfg = component.cfg,
103
104 makeName(suffix):: "%s%s%s" % [cfg.prefix, cfg.name, suffix],
Sergiusz Bazanski74818e12020-02-18 22:56:21 +0100105 makeNameGlobal(suffix):: "%s-%s" % [env.cfg.namespace, component.makeName(suffix)],
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +0200106
107 metadata:: {
108 namespace: env.cfg.namespace,
109 labels: {
110 "app.kubernetes.io/name": env.cfg.name,
111 "app.kubernetes.io/managed-by": "kubecfg-mirko",
112 "app.kubernetes.io/component": cfg.name,
113 "mirko.hscloud.hackerspace.pl/environment": env.cfg.name,
114 "mirko.hscloud.hackerspace.pl/component": cfg.name,
115 },
116 },
117
118
119 # Tunables for users.
120 cfg:: {
121 name: name,
122
123 prefix:: "",
124 image:: env.image,
125 volumes:: {},
126 containers:: {
127 main: cfg.container,
radex8b8f3872023-11-24 11:09:46 +0100128 },
Sergiusz Bazanski92b48d62020-01-08 13:59:04 +0100129 nodeSelector: null,
Sergiusz Bazanskiaa8c2b02020-02-15 12:38:39 +0100130 securityContext: {},
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +0200131 container:: error "container(s) must be set",
Serge Bazanskib7898a82020-08-23 11:05:27 +0000132 initContainer:: null,
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +0200133 ports:: {
134 publicHTTP: {}, // name -> { port: no, dns: fqdn }
135 grpc: { main: 4200 }, // name -> port no
136 },
Sergiusz Bazanski91e1a8c2020-06-25 12:16:29 +0200137 extraPaths:: [],
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +0200138 },
139
140 allPorts:: {
141 ['grpc-' + p]: cfg.ports.grpc[p]
142 for p in std.objectFields(cfg.ports.grpc)
143 } + {
144 ['pubhttp-' + p] : cfg.ports.publicHTTP[p].port
145 for p in std.objectFields(cfg.ports.publicHTTP)
146 },
147
148 Container(name):: kube.Container(component.makeName(name)) {
149 image: cfg.image,
150 volumeMounts_: {
151 pki: { mountPath: "/mnt/pki" },
152 },
153 ports_: {
154 [p]: { containerPort: component.allPorts[p] }
155 for p in std.objectFields(component.allPorts)
156 },
157 resources: {
158 requests: {
159 cpu: "25m",
160 memory: "64Mi",
161 },
162 limits: {
163 cpu: "500m",
164 memory: "128Mi",
165 },
166 },
167 },
168
169 GoContainer(name, binary):: component.Container(name) {
170 command: [
171 binary,
172 "-hspki_realm", env.pkiRealm,
173 "-hspki_cluster", env.pkiClusterFQDN,
174 "-hspki_tls_ca_path", "/mnt/pki/ca.crt",
175 "-hspki_tls_certificate_path", "/mnt/pki/tls.crt",
176 "-hspki_tls_key_path", "/mnt/pki/tls.key",
177 "-logtostderr",
178 "-listen_address", "0.0.0.0:4200",
179 ],
180 },
181
182 deployment: kube.Deployment(component.makeName("-main")) {
183 metadata+: component.metadata,
184 spec+: {
185 template+: {
186 spec+: {
187 volumes_: {
188 pki: {
189 secret: { secretName: component.pki.cert.spec.secretName },
190 },
191 } + cfg.volumes,
192 containers_: cfg.containers,
Serge Bazanskib7898a82020-08-23 11:05:27 +0000193 [if cfg.initContainer != null then "initContainers"]: [cfg.initContainer],
Sergiusz Bazanski92b48d62020-01-08 13:59:04 +0100194 nodeSelector: cfg.nodeSelector,
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +0200195
196 serviceAccountName: component.sa.metadata.name,
Sergiusz Bazanskiaa8c2b02020-02-15 12:38:39 +0100197 securityContext: cfg.securityContext,
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +0200198 },
199 },
200 },
201 },
202
203 svc: kube.Service(component.makeName("")) { // No suffix, name part of DNS entry.
204 metadata+: component.metadata,
radex8b8f3872023-11-24 11:09:46 +0100205 target:: component.deployment,
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +0200206 spec+: {
207 ports: [
208 {
209 name: p,
210 port: component.allPorts[p],
211 targetPort: component.allPorts[p],
212 }
213 for p in std.objectFields(component.allPorts)
214 ],
215 },
216 },
217
218 sa: kube.ServiceAccount(component.makeName("-main")) {
219 metadata+: component.metadata,
220 },
221
222 pki: {
223 cert: kube.Certificate(component.makeName("-cert")) {
224 metadata+: component.metadata,
radex8b8f3872023-11-24 11:09:46 +0100225
Sergiusz Bazanski6f773e02019-10-02 20:46:48 +0200226 spec: {
227 secretName: component.makeName("-cert"),
228 duration: "35040h0m0s", // 4 years
229 issuerRef: {
230 // Contract with cluster/lib/pki.libsonnet.
231 name: "pki-ca",
232 kind: "ClusterIssuer",
233 },
234 commonName: "%s.%s.svc.%s" % [component.svc.metadata.name, component.svc.metadata.namespace, env.pkiClusterFQDN ],
235 dnsNames: [
236 "%s" % [component.svc.metadata.name ],
237 "%s.%s" % [component.svc.metadata.name, component.svc.metadata.namespace ],
238 "%s.%s.svc" % [component.svc.metadata.name, component.svc.metadata.namespace ],
239 "%s.%s.svc.cluster.local" % [component.svc.metadata.name, component.svc.metadata.namespace ],
240 "%s.%s.svc.%s" % [component.svc.metadata.name, component.svc.metadata.namespace, env.pkiClusterFQDN ],
241 ],
242 },
243 },
244 },
245 },
246}