feat: auto-generate readiness probes from http-proxy routes
Lint Checks / Run linter (push) Failing after 0s
Details
Publish / Build and publish (push) Failing after 0s
Details
Deploy Test / Run deploy test suite (push) Failing after 0s
Details
Webapp Test / Run webapp test suite (push) Failing after 0s
Details
Smoke Test / Run basic test suite (push) Failing after 0s
Details
Lint Checks / Run linter (push) Failing after 0s
Details
Publish / Build and publish (push) Failing after 0s
Details
Deploy Test / Run deploy test suite (push) Failing after 0s
Details
Webapp Test / Run webapp test suite (push) Failing after 0s
Details
Smoke Test / Run basic test suite (push) Failing after 0s
Details
Containers referenced in spec.yml http-proxy routes now get TCP readiness probes on the proxied port. This tells k8s when a container is actually ready to serve traffic. Without readiness probes, k8s considers pods ready immediately after start, which means: - Rolling updates cut over before the app is listening - Broken containers look "ready" and receive traffic (502s) - kubectl rollout undo has nothing to roll back to The probes use TCP socket checks (not HTTP) to work with any protocol. Initial delay 5s, check every 10s, fail after 3 consecutive failures. Closes so-l2l part C. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>afd-dumpster-local-testing
parent
2d11ca7bb0
commit
dc15c0f4a5
|
|
@ -237,6 +237,28 @@ class ClusterInfo:
|
||||||
)
|
)
|
||||||
return ingress
|
return ingress
|
||||||
|
|
||||||
|
def _get_readiness_probe_ports(self) -> dict:
|
||||||
|
"""Map container names to TCP readiness probe ports.
|
||||||
|
|
||||||
|
Derives probe ports from http-proxy routes in the spec. If a container
|
||||||
|
has an http-proxy route (proxy-to: container:port), we probe that port.
|
||||||
|
This tells k8s when the container is ready to serve traffic, which is
|
||||||
|
required for safe rolling updates.
|
||||||
|
"""
|
||||||
|
probe_ports: dict = {}
|
||||||
|
http_proxy_list = self.spec.get_http_proxy()
|
||||||
|
if http_proxy_list:
|
||||||
|
for http_proxy in http_proxy_list:
|
||||||
|
for route in http_proxy.get("routes", []):
|
||||||
|
proxy_to = route.get("proxy-to", "")
|
||||||
|
if ":" in proxy_to:
|
||||||
|
container, port_str = proxy_to.rsplit(":", 1)
|
||||||
|
port = int(port_str)
|
||||||
|
# Use the first route's port for each container
|
||||||
|
if container not in probe_ports:
|
||||||
|
probe_ports[container] = port
|
||||||
|
return probe_ports
|
||||||
|
|
||||||
# TODO: suppoprt multiple services
|
# TODO: suppoprt multiple services
|
||||||
def get_service(self):
|
def get_service(self):
|
||||||
# Collect all ports from http-proxy routes
|
# Collect all ports from http-proxy routes
|
||||||
|
|
@ -471,6 +493,7 @@ class ClusterInfo:
|
||||||
containers = []
|
containers = []
|
||||||
init_containers = []
|
init_containers = []
|
||||||
services = {}
|
services = {}
|
||||||
|
readiness_probe_ports = self._get_readiness_probe_ports()
|
||||||
global_resources = self.spec.get_container_resources()
|
global_resources = self.spec.get_container_resources()
|
||||||
if not global_resources:
|
if not global_resources:
|
||||||
global_resources = DEFAULT_CONTAINER_RESOURCES
|
global_resources = DEFAULT_CONTAINER_RESOURCES
|
||||||
|
|
@ -569,6 +592,16 @@ class ClusterInfo:
|
||||||
container_resources = self._resolve_container_resources(
|
container_resources = self._resolve_container_resources(
|
||||||
container_name, service_info, global_resources
|
container_name, service_info, global_resources
|
||||||
)
|
)
|
||||||
|
# Readiness probe from http-proxy routes
|
||||||
|
readiness_probe = None
|
||||||
|
probe_port = readiness_probe_ports.get(container_name)
|
||||||
|
if probe_port:
|
||||||
|
readiness_probe = client.V1Probe(
|
||||||
|
tcp_socket=client.V1TCPSocketAction(port=probe_port),
|
||||||
|
initial_delay_seconds=5,
|
||||||
|
period_seconds=10,
|
||||||
|
failure_threshold=3,
|
||||||
|
)
|
||||||
container = client.V1Container(
|
container = client.V1Container(
|
||||||
name=container_name,
|
name=container_name,
|
||||||
image=image_to_use,
|
image=image_to_use,
|
||||||
|
|
@ -579,6 +612,7 @@ class ClusterInfo:
|
||||||
env_from=env_from,
|
env_from=env_from,
|
||||||
ports=container_ports if container_ports else None,
|
ports=container_ports if container_ports else None,
|
||||||
volume_mounts=volume_mounts,
|
volume_mounts=volume_mounts,
|
||||||
|
readiness_probe=readiness_probe,
|
||||||
security_context=client.V1SecurityContext(
|
security_context=client.V1SecurityContext(
|
||||||
privileged=self.spec.get_privileged(),
|
privileged=self.spec.get_privileged(),
|
||||||
run_as_user=int(service_info["user"]) if "user" in service_info else None,
|
run_as_user=int(service_info["user"]) if "user" in service_info else None,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue