104 lines
4.9 KiB
Django/Jinja
104 lines
4.9 KiB
Django/Jinja
# Managed by Ansible (roles/k3s_postgres) — do not edit on the node.
|
|
#
|
|
# Plain manifests, not a HelmChart — same pattern as
|
|
# roles/k3s_metallb/templates/metallb-config.yaml.j2: the Cluster CR below
|
|
# references a CRD (postgresql.cnpg.io) that only exists once the
|
|
# cloudnative-pg HelmChart (cnpg-operator.yaml, same manifests directory) has
|
|
# actually installed the operator, so it's applied here rather than gated
|
|
# behind a "wait for CRDs" step — k3s's deploy controller retries a manifest
|
|
# referencing not-yet-existing CRDs until they show up, instead of failing
|
|
# once and giving up. templates/postgres-superuser-secret.yaml.j2 relies on
|
|
# the Namespace created here the same way, for the same reason.
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: {{ k3s_postgres_namespace }}
|
|
---
|
|
apiVersion: postgresql.cnpg.io/v1
|
|
kind: Cluster
|
|
metadata:
|
|
name: shared-postgres
|
|
namespace: {{ k3s_postgres_namespace }}
|
|
spec:
|
|
# 1 primary + 1 replica (src/shared/postgres/ansible/kubernetes/vars.yml).
|
|
# CNPG's own default pod anti-affinity (preferred, topology key hostname)
|
|
# spreads them across distinct nodes; the nodeAffinity below narrows which
|
|
# nodes those can be.
|
|
instances: {{ pg_config.POSTGRES_INSTANCES }}
|
|
imageName: {{ k3s_postgres_image }}
|
|
|
|
# Password-based superuser login, from the Secret Ansible renders
|
|
# alongside this file. Off by default in CNPG — without this, the operator
|
|
# ignores the secret's content and sets the postgres user's password to
|
|
# NULL, disabling remote login as it.
|
|
#
|
|
# The name must stay clear of `<cluster>-superuser` (i.e.
|
|
# `shared-postgres-superuser`), which is what CNPG calls the secret it
|
|
# generates for itself when this stanza is absent. Claiming that name for
|
|
# our own object stops password changes reaching the database — see
|
|
# postgres-superuser-secret.yaml.j2 for the full symptom.
|
|
enableSuperuserAccess: true
|
|
superuserSecret:
|
|
name: shared-postgres-superuser-vault
|
|
|
|
# A LoadBalancer Service for the primary, on top of the ClusterIP -rw/-ro/-r
|
|
# Services CNPG creates for every Cluster. Declared here as a CNPG *managed
|
|
# service* rather than as a Service manifest of our own: selectorType: rw
|
|
# means the operator maintains the selector, so the LB follows a failover to
|
|
# the other instance the same way the built-in -rw Service does. A
|
|
# hand-written Service would need its selector re-pointed by hand after
|
|
# every promotion.
|
|
#
|
|
# This is what makes the cluster reachable from the Ansible controller at a
|
|
# fixed host:port, which is the thing per-app database provisioning needs —
|
|
# the community.postgresql tasks compose_stack/lxc_app use can't talk to a
|
|
# ClusterIP, and `kubectl port-forward` isn't a stable address. It does put
|
|
# the superuser on the LAN: acceptable here for the same reason the Unraid
|
|
# instance's published port is, and the LAN is the boundary either way.
|
|
managed:
|
|
services:
|
|
additional:
|
|
- selectorType: rw
|
|
serviceTemplate:
|
|
metadata:
|
|
name: shared-postgres-lb
|
|
{% if k3s_postgres_loadbalancer_ip %}
|
|
# Pinned rather than left to MetalLB's next-free pick, because
|
|
# this address ends up in config elsewhere (inventory, an app's
|
|
# vars.yml) and shouldn't move when the Service is recreated.
|
|
annotations:
|
|
metallb.universe.tf/loadBalancerIPs: "{{ k3s_postgres_loadbalancer_ip }}"
|
|
{% endif %}
|
|
spec:
|
|
type: LoadBalancer
|
|
# No ports: — the operator fills in Postgres's own (5432) from
|
|
# the same template it builds the -rw Service from; naming them
|
|
# here would only risk disagreeing with it.
|
|
|
|
# POSTGRES_PORT (common/vars.yml) is 5432, the same port CNPG always
|
|
# listens on inside the pod/Service — nothing to override here.
|
|
storage:
|
|
size: {{ pg_config.POSTGRES_STORAGE_SIZE }}
|
|
storageClass: {{ pg_config.POSTGRES_STORAGE_CLASS }}
|
|
|
|
resources:
|
|
{{ k3s_postgres_resources | to_nice_yaml(indent=2) | indent(4, first=true) }}
|
|
|
|
# Workers only — k3s-ctrl-01 stays free of app pods, same boundary the
|
|
# cluster already keeps for monitoring/MetalLB.
|
|
affinity:
|
|
nodeAffinity:
|
|
requiredDuringSchedulingIgnoredDuringExecution:
|
|
nodeSelectorTerms:
|
|
- matchExpressions:
|
|
- key: node-role.kubernetes.io/control-plane
|
|
operator: DoesNotExist
|
|
|
|
# No bootstrap: stanza — CNPG's default initdb bootstrap creates a
|
|
# `postgres` superuser (above) plus a default `app` database owned by an
|
|
# auto-generated `app` role/secret. That default app database is unused
|
|
# today: no app is deployed onto k3s yet, and real per-app database
|
|
# provisioning here is a deferred design problem (see CLAUDE.md → "Key
|
|
# decisions") — the community.postgresql approach compose_stack/lxc_app
|
|
# use needs a controller-reachable host:port, which this cluster's
|
|
# in-cluster -rw Service isn't without further work.
|