Skip to content

Add a shard

Adding capacity is a reviewed change in the landscape repository; there is no code change and no API call. The provider needs, per shard: a Percona PG cluster, a provisioner role, and a Shard object.

1. Prepare the Percona PG cluster

  • Create the cluster with your usual Percona PG definition, with a pgBouncer behind the private load balancer consumers connect to.
  • Declare a role named provisioner with the attributes LOGIN CREATEDB CREATEROLE and no superuser (in PerconaPGCluster.spec.users, with the same options the other shards use). Tenant roles and databases are created by the provider itself and are deliberately not declared in spec.users.
  • Make the provisioner credential available as a Secret with the keys user and password (other key names can be configured with secretRef.userKey / passwordKey), in the release namespace or listed by name in the chart value shardSecrets (add {namespace, names} and upgrade the release before creating the Shard: the chart grants get on exactly these Secrets, never list/watch on the namespace, which also holds replication certificates and backup keys). Unlisted, the Shard reports AdminSecretInvalid.
  • Recommended hardening (shard bootstrap): PostgreSQL grants CONNECT and TEMP on every database to PUBLIC. The provider revokes this on each tenant database it creates, but not on databases it does not own. Run once per shard as a superuser:

    REVOKE CONNECT ON DATABASE postgres FROM PUBLIC;
    REVOKE CONNECT ON DATABASE template1 FROM PUBLIC;
    

    Otherwise every tenant role can log in to postgres. Verify that your own monitoring and Percona's system users still connect afterwards (they connect as roles with their own grants).

2. Create the Shard

apiVersion: db.bnerd.com/v1alpha1
kind: Shard
metadata:
  name: shard02
spec:
  accepting: false          # start closed until the checks below pass
  maxDatabases: 200
  perconaCluster: {namespace: databases, name: pg-shard02}
  admin:
    serviceName: pg-shard02-primary
    secretRef: {namespace: databases, name: pg-shard02-pguser-provisioner}
  client: {host: 192.0.2.201, port: 5432, sslmode: require}

(Field reference and the admin versus client endpoint distinction: Configure shards and consumers.)

3. Check

kubectl get shard shard02
kubectl get shard shard02 -o jsonpath='{range .status.conditions[*]}{.type}={.status} {.reason}{"\n"}{end}'

Expect Ready=True Ok. Otherwise: AdminSecretInvalid (Secret or keys), AdminAuthFailed (wrong password or the role is not allowed to log in via the primary Service), Unreachable (Service name, port, TLS sslmode, the chart's NetworkPolicy: add the shard's namespace to networkPolicy.shardNamespaces and its admin port to networkPolicy.shardPorts).

4. Open it

Set accepting: true. New databases are placed on the accepting, ready shard with the fewest databases (so a fresh shard receives new placements until it catches up); existing databases are never moved.

Retiring a shard

Set accepting: false, wait until its databases are deleted (kubectl get shard shows Databases going to 0), then remove the Shard object, and its admin Secret entry from shardSecrets. Do not remove a Shard that still has databases: they would report ShardNotFound and could not be disabled or dropped. With deletionProtection.enabled (default) the admission policy refuses that delete while status.databaseCount > 0.