|
| 1 | +--- |
| 2 | +title: "CNPG Recipe 20 – Finer Control of Postgres Clusters with Readiness Probes" |
| 3 | +date: 2025-06-25T08:04:00+02:00 |
| 4 | +description: "how CloudNativePG leverages Kubernetes readiness probes to give users more reliable and configurable control over PostgreSQL in high-availability clusters" |
| 5 | +tags: ["postgresql", "postgres", "kubernetes", "k8s", "cloudnativepg", "cnpg", "postgresql", "postgres", "dok", "data on kubernetes", "probes", "cncf", "startup", "pg_isready", "readiness", "streaming", "maximumLag"] |
| 6 | +cover: cover.jpg |
| 7 | +thumb: thumb.jpg |
| 8 | +draft: false |
| 9 | +--- |
| 10 | + |
| 11 | +_Explore the new readiness probe introduced in CloudNativePG 1.26, which |
| 12 | +advances Kubernetes-native lifecycle management for PostgreSQL. Building on the |
| 13 | +improved probing infrastructure discussed in my previous article, this piece |
| 14 | +focuses on how readiness probes ensure that only fully synchronised and healthy |
| 15 | +instances—particularly replicas—are eligible to serve traffic or be promoted to |
| 16 | +primary. Special emphasis is placed on the `streaming` probe type and its |
| 17 | +integration with synchronous replication, giving administrators |
| 18 | +fine-grained control over failover behaviour and data consistency._ |
| 19 | + |
| 20 | +<!--more--> |
| 21 | + |
| 22 | +--- |
| 23 | + |
| 24 | +In the previous article — |
| 25 | +[CNPG Recipe 19 - Finer Control Over Postgres Startup with Probes]({{< relref "../20250617-startup-probes/index.md" >}}) |
| 26 | +— I covered the first set of enhancements to the |
| 27 | +[probing infrastructure in CloudNativePG 1.26](https://github.com/cloudnative-pg/cloudnative-pg/pull/6623), |
| 28 | +focusing on the startup process of a Postgres instance. |
| 29 | + |
| 30 | +In this follow-up, I’ll continue the discussion with a closer look at |
| 31 | +CloudNativePG’s brand-new **readiness probe**. |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## Understanding Readiness Probes |
| 36 | + |
| 37 | +[Readiness probes](https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/#readiness-probe) |
| 38 | +have been part of Kubernetes since the beginning. Their purpose is to determine |
| 39 | +whether a running container is *ready* to accept traffic—for example, whether |
| 40 | +it should be included in a `Service`’s endpoints. |
| 41 | + |
| 42 | +Unlike the startup probe, which runs only once at container start, the |
| 43 | +readiness probe kicks in *after* the startup probe succeeds and continues |
| 44 | +running for the entire lifetime of the container. |
| 45 | + |
| 46 | +As mentioned in the previous article, readiness probes share the same |
| 47 | +configuration parameters as startup and liveness probes: |
| 48 | + |
| 49 | +- `failureThreshold` |
| 50 | +- `periodSeconds` |
| 51 | +- `successThreshold` |
| 52 | +- `timeoutSeconds` |
| 53 | + |
| 54 | +--- |
| 55 | + |
| 56 | +## Why Readiness Probes Matter for Postgres |
| 57 | + |
| 58 | +Readiness probes play a critical role in ensuring that only Postgres instances |
| 59 | +fully prepared to handle client connections are exposed through Kubernetes |
| 60 | +Services. |
| 61 | +They prevent traffic from being routed to pods that may be technically running |
| 62 | +but are still recovering, replaying WAL files, or catching up as replicas. |
| 63 | + |
| 64 | +Beyond traffic management, the concept of readiness can also be extended to |
| 65 | +evaluate a replica’s eligibility for promotion—a direction we’ve taken in |
| 66 | +CloudNativePG, as I’ll explain later in this article. |
| 67 | + |
| 68 | +## How CloudNativePG Implements Readiness Probes |
| 69 | + |
| 70 | +Unlike startup probes, CloudNativePG ships with a fixed default configuration |
| 71 | +for readiness probes: |
| 72 | + |
| 73 | +```yaml |
| 74 | +failureThreshold: 3 |
| 75 | +periodSeconds: 10 |
| 76 | +successThreshold: 1 |
| 77 | +timeoutSeconds: 5 |
| 78 | +``` |
| 79 | +
|
| 80 | +By default, the probe uses the `pg_isready` utility to determine whether the |
| 81 | +Postgres instance is ready—just like the startup probe; if `pg_isready` fails |
| 82 | +three consecutive times, with a 10-second interval between attempts, the |
| 83 | +`postgres` container is marked as *not ready*. |
| 84 | + |
| 85 | +However, you can fully customise the readiness probe by defining the |
| 86 | +`.spec.probes.readiness` stanza in your cluster configuration—just like the |
| 87 | +[*Advanced mode* described in the startup probe article]({{< relref "../20250617-startup-probes/index.md#advanced-mode-full-probe-customisation" >}}). |
| 88 | + |
| 89 | +## Full Probe Customisation |
| 90 | + |
| 91 | +For scenarios that require finer control, CloudNativePG allows you to customise |
| 92 | +the readiness probe through the `.spec.probes.readiness` stanza. This lets you |
| 93 | +explicitly define the probe parameters introduced earlier in this article. |
| 94 | + |
| 95 | +The following example configures Kubernetes to: |
| 96 | + |
| 97 | +- Probe the container every 10 seconds (`periodSeconds`) |
| 98 | +- Tolerate up to 6 consecutive failures (`failureThreshold`)—equivalent to one |
| 99 | + minute—before marking the container as *not ready* |
| 100 | + |
| 101 | +```yaml |
| 102 | +{{< include "yaml/freddie-custom.yaml" >}} |
| 103 | +``` |
| 104 | + |
| 105 | +This approach is particularly useful when the default settings don’t match your |
| 106 | +workload’s characteristics—especially when fine-tuning `failureThreshold`. |
| 107 | + |
| 108 | +As you may have noticed, these settings apply uniformly to all PostgreSQL |
| 109 | +instance pods, regardless of whether they are primaries or standbys. |
| 110 | + |
| 111 | +Now, let’s explore the rest of the capabilities—starting with my favourite: |
| 112 | +replica-specific configuration. |
| 113 | + |
| 114 | +## Probe Strategies |
| 115 | + |
| 116 | +Readiness probe strategies in CloudNativePG work just like those for startup |
| 117 | +probes, with the key difference being when they are executed and the parameter |
| 118 | +used: `.spec.probes.readiness.type`. For a detailed explanation of the |
| 119 | +different strategies, please refer to the previous article. |
| 120 | + |
| 121 | +To summarise, the default type is `pg_isready`, but you can also choose from |
| 122 | +`query` and `streaming`. |
| 123 | + |
| 124 | +For example, the following cluster configuration uses a `query`-based strategy |
| 125 | +for both the startup and readiness probes: |
| 126 | + |
| 127 | +```yaml |
| 128 | +{{< include "yaml/freddie-query.yaml" >}} |
| 129 | +``` |
| 130 | + |
| 131 | +The rest of this article focuses on the `streaming` strategy and its impact on |
| 132 | +replicas within a CloudNativePG high-availability (HA) cluster. |
| 133 | + |
| 134 | +## Readiness Probes on Replicas |
| 135 | + |
| 136 | +While configuring a readiness probe on a primary is relatively |
| 137 | +straightforward—mostly a matter of tuning the right parameters and letting |
| 138 | +`pg_isready` do its job—it’s on replicas that CloudNativePG’s Kubernetes-native |
| 139 | +approach truly shines. |
| 140 | + |
| 141 | +The key idea we’ve adopted is to extend the concept of *readiness* to also |
| 142 | +influence automated promotion decisions. In certain scenarios, you may want the |
| 143 | +cluster to remain without a leader temporarily, to preserve data integrity and |
| 144 | +prevent a lagging replica from being promoted prematurely. |
| 145 | + |
| 146 | +By setting the probe `type` to `streaming`, a replica is considered *ready* |
| 147 | +only if it is actively streaming from the primary. This ensures that only |
| 148 | +healthy, up-to-date replicas are eligible for client traffic—and potentially |
| 149 | +for promotion. |
| 150 | + |
| 151 | +In more advanced setups, you can further tighten promotion criteria by ensuring |
| 152 | +that any replica with non-zero lag—based on the most recent readiness probe—is |
| 153 | +excluded from promotion. This behaviour requires synchronous replication to be |
| 154 | +enabled. The following manifest demonstrates this configuration: |
| 155 | + |
| 156 | +```yaml |
| 157 | +{{< include "yaml/freddie-streaming.yaml" >}} |
| 158 | +``` |
| 159 | + |
| 160 | +In this example, the readiness probe checks every 10 seconds and allows up to 6 |
| 161 | +consecutive failures before marking the replica as *not ready*. The |
| 162 | +`maximumLag: 0` setting ensures that any replica consistently showing even |
| 163 | +minimal lag is excluded from being considered ready. |
| 164 | + |
| 165 | +With synchronous replication enabled as shown above, PostgreSQL requires that |
| 166 | +each transaction be acknowledged by at least one standby before a successful |
| 167 | +`COMMIT` is returned to the application. Because PostgreSQL treats all eligible |
| 168 | +replicas equally when forming the synchronous quorum, even minimal replication |
| 169 | +lag can cause readiness probes to *flap*—frequently switching between ready and |
| 170 | +not ready states. |
| 171 | + |
| 172 | +For instance, if a replica is located in an availability zone with slightly |
| 173 | +higher network latency, it may consistently fall just behind the primary enough |
| 174 | +to be marked as *not ready* by the probe. |
| 175 | + |
| 176 | +This can lead to the replica being temporarily removed from read services and |
| 177 | +disqualified from promotion. While this behaviour might be acceptable or even |
| 178 | +desirable in some cases, it’s important to fully understand and account for the |
| 179 | +operational consequences. In any case, be sure to tune these probe settings |
| 180 | +carefully according to the specifics of your environment and your tolerance for |
| 181 | +lag before you use this setup in production. |
| 182 | + |
| 183 | +## Key Takeaways |
| 184 | + |
| 185 | +By default, readiness probes in CloudNativePG help ensure that PostgreSQL |
| 186 | +instances are functioning correctly and ready to serve traffic—writes for |
| 187 | +primaries, reads for Hot Standby replicas. |
| 188 | + |
| 189 | +While the default `pg_isready`-based readiness probe is usually sufficient for |
| 190 | +primaries, replicas often benefit from stricter checks. As you've seen in this |
| 191 | +article, the `streaming` probe type—especially when combined with the |
| 192 | +`maximumLag` setting and synchronous replication— provides a powerful mechanism |
| 193 | +to enforce tighter consistency guarantees and to prevent *non-ready* replicas |
| 194 | +from being promoted. (And yes, I do recommend enabling synchronous replication |
| 195 | +in production, even if it comes with a slight performance cost.) |
| 196 | + |
| 197 | +Now, if you're wondering, *“What’s the recommended setup for me?”*—the honest |
| 198 | +answer is: *It depends*. I know that’s not the clear-cut advice you might have |
| 199 | +hoped for, but there’s no one-size-fits-all solution. The goal of this article |
| 200 | +is to equip you with the knowledge and tools to make an informed choice that |
| 201 | +best suits your environment and requirements. |
| 202 | + |
| 203 | +At the very least, you now have a rich set of options in CloudNativePG to |
| 204 | +design your PostgreSQL cluster’s readiness strategy with precision. |
| 205 | + |
| 206 | +--- |
| 207 | + |
| 208 | +Stay tuned for the upcoming recipes! For the latest updates, consider |
| 209 | +subscribing to my [LinkedIn](https://www.linkedin.com/in/gbartolini/) and |
| 210 | +[Twitter](https://twitter.com/_GBartolini_) channels. |
| 211 | + |
| 212 | +If you found this article informative, feel free to share it within your |
| 213 | +network on social media using the provided links below. Your support is |
| 214 | +immensely appreciated! |
| 215 | + |
| 216 | +_Cover Picture: [“Tanzanian Elephant“](https://commons.wikimedia.org/wiki/File:Tanzanian_Elephant.jpg)._ |
| 217 | + |
0 commit comments