Detailed description
Right now a probe can only say how to check (httpGet or exec), not when or how often. The containerProbe definition has no timing fields at all:
containers:
main:
image: my-slow-app
livenessProbe:
httpGet:
path: /healthz
port: 8080
For anything that takes more than a second or two to start (a JVM service, Rails, something loading a model or warming a cache), this is a real problem. With no way to set an initial delay, the implementation falls back to its default, and on Kubernetes that means the liveness probe starts hitting /healthz almost immediately, fails, and the container gets killed and restarted before it ever finishes booting. The workload crash-loops, and there's nothing in the Score file you can do about it.
The only workaround today is to drop into patch-templates and hand-write the probe, which is exactly the platform-specific detail Score is supposed to keep me away from.
I'd like to add the standard probe timing and threshold fields to containerProbe, so they apply to both livenessProbe and readinessProbe:
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
All optional, all with the usual defaults, so existing files don't change.
Context
This is the missing half of a feature the spec already has. Probes have been in for a while, and exec was added recently in #114, but without timing they only really work for apps that start instantly. Most real workloads don't.
I think these fields belong in the spec rather than in each implementation, for the same reason that came up in #124: if a setting is required for the workload to actually run, it can't be left to the implementation to guess. An app that needs a 30 second start-up grace will crash-loop without it, whichever implementation runs it. That's a property of the workload, not the platform.
And unlike some platform-specific settings, these map cleanly everywhere. Both reference implementations already support all of them natively:
| Score |
Kubernetes |
Docker Compose healthcheck |
initialDelaySeconds |
initialDelaySeconds |
start_period |
periodSeconds |
periodSeconds |
interval |
timeoutSeconds |
timeoutSeconds |
timeout |
failureThreshold |
failureThreshold |
retries |
So there's no new platform surface to invent here. It's wiring up fields that both targets already have.
Possible implementation
Add the fields to the shared containerProbe definition, so both livenessProbe and readinessProbe pick them up. They sit next to httpGet/exec, which is where Kubernetes keeps them too.
"containerProbe": {
"type": "object",
"description": "The probe definition. At least one of 'httpGet' or 'exec' must be specified. The execProbe should be preferred if the Score implementation supports both types.",
"additionalProperties": false,
"properties": {
"httpGet": { "$ref": "#/$defs/httpProbe" },
"exec": { "$ref": "#/$defs/execProbe" },
"initialDelaySeconds": {
"description": "Number of seconds after the container has started before the probe is first initiated. Defaults to 0.",
"type": "integer",
"minimum": 0
},
"periodSeconds": {
"description": "How often, in seconds, to run the probe. Defaults to 10.",
"type": "integer",
"minimum": 1
},
"timeoutSeconds": {
"description": "Number of seconds after which the probe times out. Defaults to 1.",
"type": "integer",
"minimum": 1
},
"failureThreshold": {
"description": "Number of consecutive failures before the probe is considered failed. Defaults to 3.",
"type": "integer",
"minimum": 1
}
},
"anyOf": [
{ "required": ["httpGet"] },
{ "required": ["exec"] }
]
}
The defaults match the common Kubernetes ones, so files that don't set them keep working exactly as they do today. Rollout is the usual path:
Additional information
One field I left out of the set above on purpose: successThreshold. Kubernetes has it, but Docker Compose healthchecks don't, and Kubernetes forces it to 1 for liveness probes anyway. So it's the one field that wouldn't map everywhere. I'm fine either way: leave it out to keep the set fully portable, or add it and document that it's readiness-only and ignored where there's no equivalent.
Two smaller calls I'm happy to follow your lead on:
- Whether to put upper bounds on any of these (say a sane cap on
timeoutSeconds) or just keep minimum and leave the rest to the implementation.
- Whether the defaults live in the field descriptions or are left for each implementation to document.
This is backward compatible, so like the ports/resources one I think it can stay in v1b1. Happy to bring it to the next community meeting first if you'd rather talk it through before any PR.
Detailed description
Right now a probe can only say how to check (
httpGetorexec), not when or how often. ThecontainerProbedefinition has no timing fields at all:For anything that takes more than a second or two to start (a JVM service, Rails, something loading a model or warming a cache), this is a real problem. With no way to set an initial delay, the implementation falls back to its default, and on Kubernetes that means the liveness probe starts hitting
/healthzalmost immediately, fails, and the container gets killed and restarted before it ever finishes booting. The workload crash-loops, and there's nothing in the Score file you can do about it.The only workaround today is to drop into patch-templates and hand-write the probe, which is exactly the platform-specific detail Score is supposed to keep me away from.
I'd like to add the standard probe timing and threshold fields to
containerProbe, so they apply to bothlivenessProbeandreadinessProbe:All optional, all with the usual defaults, so existing files don't change.
Context
This is the missing half of a feature the spec already has. Probes have been in for a while, and
execwas added recently in #114, but without timing they only really work for apps that start instantly. Most real workloads don't.I think these fields belong in the spec rather than in each implementation, for the same reason that came up in #124: if a setting is required for the workload to actually run, it can't be left to the implementation to guess. An app that needs a 30 second start-up grace will crash-loop without it, whichever implementation runs it. That's a property of the workload, not the platform.
And unlike some platform-specific settings, these map cleanly everywhere. Both reference implementations already support all of them natively:
initialDelaySecondsinitialDelaySecondsstart_periodperiodSecondsperiodSecondsintervaltimeoutSecondstimeoutSecondstimeoutfailureThresholdfailureThresholdretriesSo there's no new platform surface to invent here. It's wiring up fields that both targets already have.
Possible implementation
Add the fields to the shared
containerProbedefinition, so bothlivenessProbeandreadinessProbepick them up. They sit next tohttpGet/exec, which is where Kubernetes keeps them too.The defaults match the common Kubernetes ones, so files that don't set them keep working exactly as they do today. Rollout is the usual path:
containerProbe, plus an example insamples/score-full.yamlscore-gostruct and parsingscore-composemaps them to the healthcheck block (start_period,interval,timeout,retries)score-k8smaps them straight onto the probe fieldsAdditional information
One field I left out of the set above on purpose:
successThreshold. Kubernetes has it, but Docker Compose healthchecks don't, and Kubernetes forces it to 1 for liveness probes anyway. So it's the one field that wouldn't map everywhere. I'm fine either way: leave it out to keep the set fully portable, or add it and document that it's readiness-only and ignored where there's no equivalent.Two smaller calls I'm happy to follow your lead on:
timeoutSeconds) or just keepminimumand leave the rest to the implementation.This is backward compatible, so like the ports/resources one I think it can stay in v1b1. Happy to bring it to the next community meeting first if you'd rather talk it through before any PR.