# PostgreSQL on Kubernetes. local kube = import "kube.libsonnet"; { local postgres = self, local cfg = postgres.cfg, cfg:: { namespace: error "namespace must be set", appName: error "app name must be set", storageClassName: "waw-hdd-paranoid-2", prefix: "", # if set, should be 'foo-' image: "postgres:10.4", database: error "database must be set", username: error "username must be set", # not literal, instead ref for env (like { secretKeyRef: ... }) password: error "password must be set", storageSize: "30Gi", # This option can be used to customize initial database creation. For # available options see: https://www.postgresql.org/docs/9.5/app-initdb.html # Changing this option in already existing deployments will not affect # existing database. initdbArgs: null, # Extra postgres configuration options passed on startup. Accepts only # string values. # Example: { max_connections: "300" } opts: {}, }, makeName(suffix):: cfg.prefix + suffix, metadata:: { namespace: cfg.namespace, labels: { "app.kubernetes.io/name": cfg.appName, "app.kubernetes.io/managed-by": "kubecfg", "app.kubernetes.io/component": "postgres", }, }, volumeClaim: kube.PersistentVolumeClaim(postgres.makeName("postgres")) { metadata+: postgres.metadata, spec+: { storageClassName: cfg.storageClassName, accessModes: [ "ReadWriteOnce" ], resources: { requests: { storage: cfg.storageSize, }, }, }, }, deployment: kube.Deployment(postgres.makeName("postgres")) { metadata+: postgres.metadata, spec+: { replicas: 1, template+: { spec+: { volumes_: { data: kube.PersistentVolumeClaimVolume(postgres.volumeClaim), }, containers_: { postgres: kube.Container(postgres.makeName("postgres")) { image: cfg.image, ports_: { client: { containerPort: 5432 }, }, env_: { POSTGRES_DB: cfg.database, POSTGRES_USER: cfg.username, POSTGRES_PASSWORD: cfg.password, PGDATA: "/var/lib/postgresql/data/pgdata", } + if cfg.initdbArgs != null then { POSTGRES_INITDB_ARGS: cfg.initdbArgs, } else {}, args: std.flatMap( function(k) ["-c", "%s=%s" % [k, cfg.opts[k]]], std.objectFields(cfg.opts), ), volumeMounts_: { data: { mountPath: "/var/lib/postgresql/data" }, }, }, }, securityContext: { runAsUser: 999, }, }, }, }, }, svc: kube.Service(postgres.makeName("postgres")) { metadata+: postgres.metadata, target_pod:: postgres.deployment.spec.template, spec+: { ports: [ { name: "client", port: 5432, targetPort: 5432, protocol: "TCP" }, ], type: "ClusterIP", }, }, bouncer: { deployment: kube.Deployment(postgres.makeName("bouncer")) { metadata+: postgres.metadata { labels+: { "app.kubernetes.io/component": "bouncer", } }, spec+: { replicas: 1, template+: { spec+: { containers_: { bouncer: kube.Container(postgres.makeName("bouncer")) { image: "edoburu/pgbouncer:1.11.0", ports_: { client: { containerPort: 5432 }, }, env: [ { name: "POSTGRES_PASSWORD", valueFrom: cfg.password }, { name: "DATABASE_URL", value: "postgres://%s:$(POSTGRES_PASSWORD)@%s/%s" % [cfg.username, postgres.svc.host, cfg.database] }, ], }, }, }, }, }, }, svc: kube.Service(postgres.makeName("bouncer")) { metadata+: postgres.metadata { labels+: { "app.kubernetes.io/component": "bouncer", } }, target_pod:: postgres.bouncer.deployment.spec.template, spec+: { ports: [ { name: "client", port: 5432, targetPort: 5432, protocol: "TCP" }, ], type: "ClusterIP", }, }, }, }