blob: b3aed8a8eb968f01d725e8386b9be7d4996bfe93 [file] [log] [blame]
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +02001# Deploy a 3-node CockroachDB cluster in secure mode.
2
Sergiusz Bazanski224a50b2019-06-20 16:41:54 +02003local kube = import "../../../kube/kube.libsonnet";
4local cm = import "cert-manager.libsonnet";
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +02005
6{
7 local cockroachdb = self,
8 local crdb = cockroachdb,
9 local cfg = crdb.cfg,
10
11 cfg:: {
12 namespace: error "namespace must be set",
13 appName: error "app name must be set",
14 prefix: "", # if set, should be 'foo-',
15
16 image: "cockroachdb/cockroach:v19.1.0",
17 database: error "database name must be set",
18 username: error "username must be set",
19 password: error "password must be set",
20 },
21
22 makeName(suffix):: cfg.prefix + suffix,
23
24 metadata:: {
25 namespace: cfg.namespace,
26 labels: {
27 "app.kubernetes.io/name": cfg.appName,
28 "app.kubernetes.io/managed-by": "kubecfg",
29 "app.kubernetes.io/component": "cockroachdb",
30 },
31 },
32
33 pki: {
34 selfSignedIssuer: cm.Issuer("cockroachdb-selfsigned-issuer") {
35 metadata+: crdb.metadata,
36 spec: {
37 selfSigned: {},
38 },
39 },
40
41 selfSignedKeypair: cm.Certificate("cockroachdb-cluster-ca-keypair") {
42 metadata+: crdb.metadata,
43 spec: {
44 secretName: "cockroachdb-cluster-ca-keypair",
45 duration: "43800h0m0s", // 5 years
46 isCA: true,
47 issuerRef: {
48 name: crdb.pki.selfSignedIssuer.metadata.name,
49 },
50 commonName: "cockroachdb-cluster-ca",
51 },
52 },
53
54 clusterIssuer: cm.Issuer("cockroachdb-cluster-ca") {
55 metadata+: crdb.metadata,
56 spec: {
57 ca: {
58 secretName: crdb.pki.selfSignedKeypair.metadata.name,
59 },
60 },
61 },
62
63 nodeCertificate: cm.Certificate("cockroachdb-node-cert") {
64 metadata+: crdb.metadata,
65 spec: {
66 secretName: "cockroachdb-node-cert",
67 duration: "43800h0m0s", // 5 years
68 issuerRef: {
69 name: crdb.pki.clusterIssuer.metadata.name,
70 },
71 commonName: "node",
72 dnsNames: [
73 "localhost",
74 "127.0.0.1",
75 crdb.publicService.metadata.name,
76 std.join(".", [crdb.publicService.metadata.name, cfg.namespace ]),
77 std.join(".", [crdb.publicService.host, "cluster.local" ]),
78 std.join(".", [ "*", crdb.internalService.metadata.name ]),
79 std.join(".", [ "*", crdb.internalService.metadata.name, cfg.namespace ]),
80 std.join(".", [ "*", crdb.internalService.host, "cluster.local" ]),
81 ],
82 },
83 },
84
85 clientCertificate: cm.Certificate("cockroachdb-client-cert") {
86 metadata+: crdb.metadata,
87 spec: {
88 secretName: "cockroachdb-client-cert",
89 duration: "43800h0m0s", // 5 years
90 issuerRef: {
91 name: crdb.pki.clusterIssuer.metadata.name,
92 },
93 commonName: "root",
94 },
95 },
96 },
97
98 serviceAccount: kube.ServiceAccount("cockroachdb") {
99 metadata+: crdb.metadata,
100 },
101
102 role: kube.Role("cockroachdb") {
103 metadata+: crdb.metadata,
104 rules: [
105 {
106 apiGroups: [ "" ],
107 resources: [ "secrets" ],
108 verbs: [ "get" ],
109 },
110 ],
111 },
112
113 roleBinding: kube.RoleBinding("cockroachdb") {
114 metadata+: crdb.metadata,
115 roleRef: {
116 apiGroup: "rbac.authorization.k8s.io",
117 kind: "Role",
118 name: "cockroachdb",
119 },
120 subjects: [
121 {
122 kind: "ServiceAccount",
123 name: crdb.serviceAccount.metadata.name,
124 namespace: cfg.namespace,
125 },
126 ],
127 },
128
129 publicService: kube.Service(crdb.makeName("cockroachdb-public")) {
130 metadata+: crdb.metadata,
131 target_pod:: crdb.statefulSet.spec.template,
132 spec+: {
133 ports: [
134 { name: "grpc", port: 26257, targetPort: 26257 },
135 { name: "http", port: 8080, targetPort: 8080 },
136 ],
137 },
138 },
139
140 internalService: kube.Service(crdb.makeName("cockroachdb")) {
141 metadata+: crdb.metadata + {
142 annotations+: {
143 "service.alpha.kubernetes.io/tolerate-unready-endpoints": "true",
144 "prometheus.io/scrape": "true",
145 "prometheus.io/path": "_status/vars",
146 "prometheus.io/port": "8080",
147 },
148 },
149 target_pod:: crdb.statefulSet.spec.template,
150 spec+: {
151 ports: [
152 { name: "grpc", port: 26257, targetPort: 26257 },
153 { name: "http", port: 8080, targetPort: 8080 },
154 ],
155 publishNotReadyAddresses: true,
156 clusterIP: "None",
157 },
158 },
159
160 podDisruptionBudget: kube.PodDisruptionBudget(crdb.makeName("cockroachdb-budget")) {
161 metadata+: crdb.metadata,
162 spec: {
163 selector: {
164 matchLabels: {
165 "app.kubernetes.io/component": "cockroachdb",
166 },
167 },
168 maxUnavailable: 1,
169 },
170 },
171
172 statefulSet: kube.StatefulSet(crdb.makeName("cockroachdb")) {
173 metadata+: crdb.metadata,
174 spec+: {
175 serviceName: crdb.internalService.metadata.name,
176 replicas: 3,
177 template: {
178 metadata+: crdb.metadata,
179 spec+: {
180 dnsPolicy: "ClusterFirst",
181 serviceAccountName: crdb.serviceAccount.metadata.name,
182 affinity: {
183 podAntiAffinity: {
184 preferredDuringSchedulingIgnoredDuringExecution: [
185 {
186 weight: 100,
187 podAffinityTerm: {
188 labelSelector: {
189 matchExpressions: [
190 {
191 key: "app.kubernetes.io/component",
192 operator: "In",
193 values: [ "cockroachdb" ],
194 },
195 ],
196 },
197 topologyKey: "kubernetes.io/hostname",
198 },
199 },
200 ],
201 },
202 },
203 containers: [
204 kube.Container("cockroachdb") {
205 image: cfg.image,
206 imagePullPolicy: "IfNotPresent",
207 resources: {
208 requests: {
209 cpu: "2",
210 memory: "6Gi",
211 },
212 limits: {
213 memory: "6Gi",
214 },
215 },
216 ports_: {
217 "grpc": { containerPort: 26257 },
218 "http": { containerPort: 8080 },
219 },
220 livenessProbe: {
221 httpGet: {
222 path: "/health",
223 port: "http",
224 },
225 initialDelaySeconds: 30,
226 periodSeconds: 5,
227 },
228 readinessProbe: {
229 httpGet: {
230 path: "/health?ready=1",
231 port: "http",
232 },
233 initialDelaySeconds: 10,
234 periodSeconds: 5,
235 failureThreshold: 2,
236 },
237 volumeMounts: [
238 {
239 name: "datadir",
240 mountPath: "/cockroach/cockroach-data",
241 },
242 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200243 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200244 mountPath: "/cockroach/cockroach-certs/node.crt",
245 subPath: "tls.crt",
246 },
247 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200248 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200249 mountPath: "/cockroach/cockroach-certs/node.key",
250 subPath: "tls.key",
251 },
252 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200253 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200254 mountPath: "/cockroach/cockroach-certs/ca.crt",
255 subPath: "ca.crt",
256 },
257 ],
258 env_: {
259 "COCKROACH_CERTS_DIR": "/cockroach/cockroach-certs",
260 },
261 command: [
262 "/bin/bash",
263 "-ecx",
264 "exec /cockroach/cockroach start --logtostderr --certs-dir /cockroach/cockroach-certs --advertise-host $(hostname -f) --http-addr 0.0.0.0 --join cockroachdb-0.cockroachdb,cockroachdb-1.cockroachdb,cockroachdb-2.cockroachdb --cache 25% --max-sql-memory 25%",
265 ],
266 },
267 ],
268 terminationGracePeriodSeconds: 60,
269 volumes: [
270 {
271 name: "datadir",
272 emptyDir: {},
273 },
274 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200275 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200276 secret: {
277 secretName: crdb.pki.nodeCertificate.spec.secretName,
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200278 defaultMode: kube.parseOctal("400"),
279 },
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200280 },
281 ],
282 },
283 },
284 podManagementPolicy: "Parallel",
285 updateStrategy: {
286 type: "RollingUpdate",
287 },
288 },
289 },
290
291 initJob: kube.Job(crdb.makeName("cockroachdb-init")) {
292 metadata+: crdb.metadata,
293 spec: {
294 template: {
295 metadata+: crdb.metadata,
296 spec+: {
297 serviceAccountName: crdb.serviceAccount.metadata.name,
298 initContainers: [
299 kube.Container("cluster-init") {
300 image: cfg.image,
301 imagePullPolicy: "IfNotPresent",
302 env_: {
303 "COCKROACH_CERTS_DIR": "/cockroach/cockroach-certs",
304 },
305 command: [
306 "/bin/bash",
307 "-ecx",
308 "/cockroach/cockroach init --host=cockroachdb-0.cockroachdb",
309 ],
310 volumeMounts: [
311 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200312 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200313 mountPath: "/cockroach/cockroach-certs/ca.crt",
314 subPath: "ca.crt",
315 },
316 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200317 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200318 mountPath: "/cockroach/cockroach-certs/client.root.crt",
319 subPath: "tls.crt",
320 },
321 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200322 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200323 mountPath: "/cockroach/cockroach-certs/client.root.key",
324 subPath: "tls.key",
325 },
326 ],
327 },
328 ],
329 containers: [
330 kube.Container("db-init") {
331 image: cfg.image,
332 imagePullPolicy: "IfNotPresent",
333 env_: {
334 "COCKROACH_CERTS_DIR": "/cockroach/cockroach-certs",
335 "DB_NAME": cfg.database,
336 "DB_USERNAME": cfg.username,
337 "DB_PASSWORD": cfg.password,
338 },
339 command: [
340 "/bin/bash",
341 "-ec",
342 "/cockroach/cockroach sql -e \"CREATE DATABASE ${DB_NAME}; CREATE USER ${DB_USERNAME} PASSWORD '${DB_PASSWORD}'; GRANT ALL ON DATABASE ${DB_NAME} TO ${DB_USERNAME};\" --host=cockroachdb-0.cockroachdb",
343 ],
344 volumeMounts: [
345 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200346 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200347 mountPath: "/cockroach/cockroach-certs/ca.crt",
348 subPath: "ca.crt",
349 },
350 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200351 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200352 mountPath: "/cockroach/cockroach-certs/client.root.crt",
353 subPath: "tls.crt",
354 },
355 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200356 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200357 mountPath: "/cockroach/cockroach-certs/client.root.key",
358 subPath: "tls.key",
359 },
360 ],
361 },
362 ],
363 restartPolicy: "OnFailure",
364 volumes: [
365 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200366 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200367 secret: {
368 secretName: crdb.pki.clientCertificate.spec.secretName,
369 defaultMode: kube.parseOctal("400")
370 }
371 },
372 ],
373 },
374 },
375 },
376 },
377
378 clientPod: kube.Pod(crdb.makeName("cockroachdb-client")) {
379 metadata+: crdb.metadata,
380 spec: {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200381 terminationGracePeriodSeconds: 5,
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200382 containers: [
383 kube.Container("cockroachdb-client") {
384 image: cfg.image,
385 env_: {
386 "COCKROACH_CERTS_DIR": "/cockroach/cockroach-certs",
387 },
388 command: ["sleep", "2147483648"], //(FIXME) keep the client pod running indefinitely
389 volumeMounts: [
390 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200391 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200392 mountPath: "/cockroach/cockroach-certs/ca.crt",
393 subPath: "ca.crt",
394 },
395 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200396 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200397 mountPath: "/cockroach/cockroach-certs/client.root.crt",
398 subPath: "tls.crt",
399 },
400 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200401 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200402 mountPath: "/cockroach/cockroach-certs/client.root.key",
403 subPath: "tls.key",
404 },
405 ],
406 },
407 ],
408 volumes: [
409 {
Patryk Jakuszewfae3a9d2019-05-24 01:59:44 +0200410 name: "certs",
Patryk Jakuszew5dfd4cc2019-05-22 23:54:02 +0200411 secret: {
412 secretName: crdb.pki.clientCertificate.spec.secretName,
413 defaultMode: kube.parseOctal("400")
414 }
415 },
416 ],
417 },
418 },
Sergiusz Bazanski224a50b2019-06-20 16:41:54 +0200419}