blob: edb1cae39ec74e7d7b989ae9fc256d0820f8535f [file] [log] [blame]
Sergiusz Bazanski5f2dc852019-04-02 02:36:22 +02001# PostgreSQL on Kubernetes.
2
3local kube = import "kube.libsonnet";
4
5{
6 local postgres = self,
7 local cfg = postgres.cfg,
8 cfg:: {
9 namespace: error "namespace must be set",
10 appName: error "app name must be set",
Sergiusz Bazanskid07861b2019-08-08 17:48:25 +020011 storageClassName: "waw-hdd-paranoid-2",
Sergiusz Bazanski5f2dc852019-04-02 02:36:22 +020012 prefix: "", # if set, should be 'foo-'
13
14 image: "postgres:10.4",
15 database: error "database must be set",
16 username: error "username must be set",
17 # not literal, instead ref for env (like { secretKeyRef: ... })
18 password: error "password must be set",
Serge Bazanskic0c037a2020-08-23 01:24:03 +000019
20 storageSize: "30Gi",
Piotr Dobrowolski1816f582021-01-30 11:53:38 +010021
22 # This option can be used to customize initial database creation. For
23 # available options see: https://www.postgresql.org/docs/9.5/app-initdb.html
24 # Changing this option in already existing deployments will not affect
25 # existing database.
26 initdbArgs: null,
Piotr Dobrowolski3b8f6672021-02-08 22:44:56 +010027
28 # Extra postgres configuration options passed on startup. Accepts only
29 # string values.
30 # Example: { max_connections: "300" }
31 opts: {},
Sergiusz Bazanski5f2dc852019-04-02 02:36:22 +020032 },
33
34 makeName(suffix):: cfg.prefix + suffix,
35
36 metadata:: {
37 namespace: cfg.namespace,
38 labels: {
39 "app.kubernetes.io/name": cfg.appName,
40 "app.kubernetes.io/managed-by": "kubecfg",
41 "app.kubernetes.io/component": "postgres",
42 },
43 },
44
45 volumeClaim: kube.PersistentVolumeClaim(postgres.makeName("postgres")) {
46 metadata+: postgres.metadata,
47 spec+: {
48 storageClassName: cfg.storageClassName,
49 accessModes: [ "ReadWriteOnce" ],
50 resources: {
51 requests: {
Serge Bazanskic0c037a2020-08-23 01:24:03 +000052 storage: cfg.storageSize,
Sergiusz Bazanski5f2dc852019-04-02 02:36:22 +020053 },
54 },
55 },
56 },
57 deployment: kube.Deployment(postgres.makeName("postgres")) {
58 metadata+: postgres.metadata,
59 spec+: {
60 replicas: 1,
61 template+: {
62 spec+: {
63 volumes_: {
64 data: kube.PersistentVolumeClaimVolume(postgres.volumeClaim),
65 },
66 containers_: {
67 postgres: kube.Container(postgres.makeName("postgres")) {
68 image: cfg.image,
69 ports_: {
70 client: { containerPort: 5432 },
71 },
72 env_: {
73 POSTGRES_DB: cfg.database,
74 POSTGRES_USER: cfg.username,
75 POSTGRES_PASSWORD: cfg.password,
76 PGDATA: "/var/lib/postgresql/data/pgdata",
Piotr Dobrowolski1816f582021-01-30 11:53:38 +010077 } + if cfg.initdbArgs != null then {
78 POSTGRES_INITDB_ARGS: cfg.initdbArgs,
79 } else {},
Piotr Dobrowolski3b8f6672021-02-08 22:44:56 +010080
81 args: std.flatMap(
82 function(k) ["-c", "%s=%s" % [k, cfg.opts[k]]],
83 std.objectFields(cfg.opts),
84 ),
85
Sergiusz Bazanski5f2dc852019-04-02 02:36:22 +020086 volumeMounts_: {
87 data: { mountPath: "/var/lib/postgresql/data" },
88 },
89 },
90 },
Sergiusz Bazanskia2ee8652020-01-22 21:48:48 +010091 securityContext: {
92 runAsUser: 999,
93 },
Sergiusz Bazanski5f2dc852019-04-02 02:36:22 +020094 },
95 },
96 },
97 },
Serge Bazanskic0c037a2020-08-23 01:24:03 +000098
Sergiusz Bazanski5f2dc852019-04-02 02:36:22 +020099 svc: kube.Service(postgres.makeName("postgres")) {
100 metadata+: postgres.metadata,
101 target_pod:: postgres.deployment.spec.template,
102 spec+: {
103 ports: [
104 { name: "client", port: 5432, targetPort: 5432, protocol: "TCP" },
105 ],
106 type: "ClusterIP",
107 },
108 },
Sergiusz Bazanskic622a192020-02-15 12:39:14 +0100109
110 bouncer: {
111 deployment: kube.Deployment(postgres.makeName("bouncer")) {
112 metadata+: postgres.metadata {
113 labels+: {
114 "app.kubernetes.io/component": "bouncer",
115 }
116 },
117 spec+: {
118 replicas: 1,
119 template+: {
120 spec+: {
121 containers_: {
122 bouncer: kube.Container(postgres.makeName("bouncer")) {
123 image: "edoburu/pgbouncer:1.11.0",
124 ports_: {
125 client: { containerPort: 5432 },
126 },
127 env: [
128 { name: "POSTGRES_PASSWORD", valueFrom: cfg.password },
129 { name: "DATABASE_URL", value: "postgres://%s:$(POSTGRES_PASSWORD)@%s/%s" % [cfg.username, postgres.svc.host, cfg.database] },
130 ],
131 },
132 },
133 },
134 },
135 },
136 },
137 svc: kube.Service(postgres.makeName("bouncer")) {
138 metadata+: postgres.metadata {
139 labels+: {
140 "app.kubernetes.io/component": "bouncer",
141 }
142 },
143 target_pod:: postgres.bouncer.deployment.spec.template,
144 spec+: {
145 ports: [
146 { name: "client", port: 5432, targetPort: 5432, protocol: "TCP" },
147 ],
148 type: "ClusterIP",
149 },
150 },
151 },
Sergiusz Bazanski5f2dc852019-04-02 02:36:22 +0200152}