|
39 | 39 | # ] |
40 | 40 | # |
41 | 41 | # Services with the same canonical `port` collapse onto one backend |
42 | | -# (one sidecar_port, one Envoy). `registers_parent=false` means the |
43 | | -# workload auto-registers its parent service under its own scope; the |
44 | | -# platform only registers a standalone connect-proxy pointing at it, |
45 | | -# and the workload owns any role-tag mutation on the sidecar via the |
46 | | -# Consul agent HTTP API. |
| 42 | +# (one sidecar_port, one Envoy). For `registers_parent=false`, the |
| 43 | +# workload owns the *authoritative* parent service registration |
| 44 | +# (tags, health check) under its own `scope` — e.g. Patroni's native |
| 45 | +# Consul integration registers `${scope}/${peer}` with role tags and a |
| 46 | +# REST-API health check. To avoid the chicken-and-egg where the |
| 47 | +# workload can't run (no consumer-side Envoy listener yet) before it |
| 48 | +# has registered (Patroni only registers after pg_basebackup, which |
| 49 | +# needs the listener), the platform pre-registers a *stub* parent |
| 50 | +# service at the same service_id so Consul's proxycfg can populate |
| 51 | +# the connect-proxy's state immediately. The workload's later PUT |
| 52 | +# overwrites the stub in place (same service_id ⇒ idempotent), adding |
| 53 | +# its check and role tags. |
47 | 54 | # |
48 | 55 | # Supervision policy: any one inner process dying takes the whole |
49 | 56 | # container down. Compose `restart: on-failure` brings it back in |
@@ -240,78 +247,76 @@ if [ "$ROLE" = "worker" ]; then |
240 | 247 | SPEC_FILE="/tmp/sidecar-${PARENT}.json" |
241 | 248 | ENVOY_BOOT="/tmp/envoy-${PARENT}.json" |
242 | 249 |
|
| 250 | + # Both patterns use a single registration with inline SidecarService: |
| 251 | + # that's the shape Consul recognises as a Connect-aware service + |
| 252 | + # its proxy. A bare `Kind: connect-proxy` plus a separate parent |
| 253 | + # without `Connect.SidecarService` is not enough — Consul won't |
| 254 | + # return the proxy as a Connect endpoint for the parent, so the |
| 255 | + # discovery chain resolves to zero hosts and consumer Envoys close |
| 256 | + # incoming connections immediately. |
| 257 | + # |
| 258 | + # The two patterns differ only in service_id and what overwrites |
| 259 | + # the registration over time: |
| 260 | + # |
| 261 | + # pattern A (webdemo): platform-only. Parent ID is |
| 262 | + # "${parent}-${peer}", tagged "peer=${peer}". Nothing else |
| 263 | + # touches this registration. |
| 264 | + # |
| 265 | + # pattern B (Patroni): platform pre-registers a "stub" with no |
| 266 | + # role tags. Patroni's entrypoint role-watcher re-PUTs the |
| 267 | + # same service_id with tags ["master"] / ["replica"] tracked |
| 268 | + # from Patroni REST. We keep `register_service: false` in |
| 269 | + # patroni.yml so Patroni's own integration stays out of the |
| 270 | + # service catalog (it only uses Consul as DCS); see |
| 271 | + # patroni/entrypoint.sh for the role-watcher. |
| 272 | + # Service ID format is `${parent}-${peer}` for both patterns so it |
| 273 | + # never contains a slash. Slashes in service IDs trip up |
| 274 | + # `consul connect envoy -sidecar-for` URL handling. |
| 275 | + PARENT_ID="${PARENT}-${PEER_ID}" |
243 | 276 | if [ "$REGISTERS_PARENT" = "true" ]; then |
244 | | - # Pattern A: platform owns the parent service AND its sidecar. |
245 | | - # TCP check on the canonical port — generic across HTTP/non-HTTP |
246 | | - # workloads; passes once the app's listener is up. SidecarService |
247 | | - # inline means a single PUT registers both records. |
248 | | - jq -n \ |
249 | | - --arg name "$PARENT" \ |
250 | | - --arg id "${PARENT}-${PEER_ID}" \ |
251 | | - --arg peer "$PEER_ID" \ |
252 | | - --argjson port "$LOCAL_PORT" \ |
253 | | - --arg vip "$SELF_VIP" \ |
254 | | - --argjson sport "$SIDECAR_PORT" \ |
255 | | - --argjson upstreams "$UPSTREAMS" '{ |
256 | | - Name: $name, |
257 | | - ID: $id, |
258 | | - Address: "127.0.0.1", |
259 | | - Port: $port, |
260 | | - Tags: ["peer=" + $peer], |
261 | | - Check: { |
262 | | - TCP: ("127.0.0.1:" + ($port|tostring)), |
263 | | - Interval: "10s", |
264 | | - Timeout: "2s", |
265 | | - DeregisterCriticalServiceAfter: "1m" |
266 | | - }, |
267 | | - Connect: { |
268 | | - SidecarService: { |
269 | | - Address: ("127.50.0." + $vip), |
270 | | - Port: $sport, |
271 | | - Proxy: { |
272 | | - LocalServiceAddress: "127.0.0.1", |
273 | | - LocalServicePort: $port, |
274 | | - Upstreams: $upstreams |
275 | | - } |
276 | | - } |
277 | | - } |
278 | | - }' > "$SPEC_FILE" |
279 | | - ENVOY_ARGS=(-sidecar-for="${PARENT}-${PEER_ID}") |
| 277 | + TAGS_JSON='["peer='"$PEER_ID"'"]' |
280 | 278 | else |
281 | | - # Pattern B: workload auto-registers the parent under its |
282 | | - # `scope`; platform registers a standalone connect-proxy pointing |
283 | | - # at it. Role/state tags on the sidecar (e.g. master/replica) are |
284 | | - # managed by the workload itself via the Consul agent HTTP API; |
285 | | - # the subset resolvers below filter on those tags. |
286 | | - jq -n \ |
287 | | - --arg id "$SIDECAR_ID" \ |
288 | | - --arg name "${PARENT}-sidecar-proxy" \ |
289 | | - --arg parent "$PARENT" \ |
290 | | - --arg vip "$SELF_VIP" \ |
291 | | - --argjson port "$LOCAL_PORT" \ |
292 | | - --argjson sport "$SIDECAR_PORT" \ |
293 | | - --argjson upstreams "$UPSTREAMS" '{ |
294 | | - Kind: "connect-proxy", |
295 | | - ID: $id, |
296 | | - Name: $name, |
297 | | - Address: ("127.50.0." + $vip), |
298 | | - Port: $sport, |
299 | | - Tags: [], |
300 | | - Proxy: { |
301 | | - DestinationServiceName: $parent, |
302 | | - LocalServiceAddress: "127.0.0.1", |
303 | | - LocalServicePort: $port, |
304 | | - Upstreams: $upstreams |
305 | | - } |
306 | | - }' > "$SPEC_FILE" |
307 | | - ENVOY_ARGS=(-proxy-id="$SIDECAR_ID") |
| 279 | + TAGS_JSON='[]' |
308 | 280 | fi |
309 | 281 |
|
| 282 | + jq -n \ |
| 283 | + --arg name "$PARENT" \ |
| 284 | + --arg id "$PARENT_ID" \ |
| 285 | + --argjson port "$LOCAL_PORT" \ |
| 286 | + --arg vip "$SELF_VIP" \ |
| 287 | + --argjson sport "$SIDECAR_PORT" \ |
| 288 | + --argjson tags "$TAGS_JSON" \ |
| 289 | + --argjson upstreams "$UPSTREAMS" '{ |
| 290 | + Name: $name, |
| 291 | + ID: $id, |
| 292 | + Address: "127.0.0.1", |
| 293 | + Port: $port, |
| 294 | + Tags: $tags, |
| 295 | + Check: { |
| 296 | + TCP: ("127.0.0.1:" + ($port|tostring)), |
| 297 | + Interval: "10s", |
| 298 | + Timeout: "2s", |
| 299 | + DeregisterCriticalServiceAfter: "1m" |
| 300 | + }, |
| 301 | + Connect: { |
| 302 | + SidecarService: { |
| 303 | + Address: ("127.50.0." + $vip), |
| 304 | + Port: $sport, |
| 305 | + Proxy: { |
| 306 | + LocalServiceAddress: "127.0.0.1", |
| 307 | + LocalServicePort: $port, |
| 308 | + Upstreams: $upstreams |
| 309 | + } |
| 310 | + } |
| 311 | + } |
| 312 | + }' > "$SPEC_FILE" |
| 313 | + ENVOY_ARGS=(-sidecar-for="$PARENT_ID") |
| 314 | + |
310 | 315 | # Re-register on every boot via the agent HTTP API (PUT-idempotent). |
311 | | - log "registering ${PARENT} sidecar (port=${SIDECAR_PORT}, base-id=${BASE_ID})" |
| 316 | + log "registering ${PARENT} (id=${PARENT_ID}) + sidecar (port=${SIDECAR_PORT}, base-id=${BASE_ID})" |
312 | 317 | until curl -fsS -X PUT --data-binary @"$SPEC_FILE" \ |
313 | 318 | http://127.0.0.1:8500/v1/agent/service/register; do |
314 | | - log "${PARENT} sidecar register failed; retrying" |
| 319 | + log "${PARENT} register failed; retrying" |
315 | 320 | sleep 2 |
316 | 321 | done |
317 | 322 |
|
|
0 commit comments