mirror of
https://github.com/keycloak/keycloak.git
synced 2026-06-08 16:42:13 -04:00
support setting periodSeconds and failureThreashold in the Keyclock CR (#40117)
* add probe spec Signed-off-by: AvivGuiser <avivguiser@gmail.com> * make default for probes if not configured, add skeleton test files Signed-off-by: AvivGuiser <avivguiser@gmail.com> * fix tests Signed-off-by: AvivGuiser <avivguiser@gmail.com> * fix tests Signed-off-by: AvivGuiser <avivguiser@gmail.com> * add docs Signed-off-by: AvivGuiser <avivguiser@gmail.com> * move test to unittest and apiserver test Signed-off-by: AvivGuiser <avivguiser@gmail.com> * adding asserts to check new fields Signed-off-by: AvivGuiser <avivguiser@gmail.com> * fix test Signed-off-by: AvivGuiser <aviv.guiser@placer.ai> * update docs Signed-off-by: AvivGuiser <aviv.guiser@placer.ai> --------- Signed-off-by: AvivGuiser <avivguiser@gmail.com> Signed-off-by: AvivGuiser <aviv.guiser@placer.ai>
This commit is contained in:
parent
76bc9fadcb
commit
7736ca20e9
8 changed files with 125 additions and 28 deletions
|
|
@ -149,15 +149,9 @@ spec:
|
|||
secretName: keycloak-additional-secret
|
||||
----
|
||||
|
||||
===== Probe Timeouts
|
||||
===== Probe Configuration
|
||||
|
||||
The unsupported podTemplate may be used to override the default probes.
|
||||
|
||||
In particular the default startup probe timeout of 10 minutes may be too short in scenarios where there is a long-running migration.
|
||||
|
||||
If your instances encounter this startup failure or if you wish to proactively prevent such a startup failure from occurring, then the startup probe timeout should be increased.
|
||||
|
||||
With otherwise default settings, something like the following increases the timeout to 20 minutes:
|
||||
The Keycloak CR exposes options to set periodSeconds and failureThreshold on each of the three probes (readiness, liveness and startup)
|
||||
|
||||
[source,yaml]
|
||||
----
|
||||
|
|
@ -166,22 +160,17 @@ kind: Keycloak
|
|||
metadata:
|
||||
name: example-kc
|
||||
spec:
|
||||
...
|
||||
unsupported:
|
||||
podTemplate:
|
||||
spec:
|
||||
containers:
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: "/health/started"
|
||||
port: 9000
|
||||
scheme: "HTTPS"
|
||||
failureThreshold: 1200
|
||||
periodSeconds: 1
|
||||
readinessProbe:
|
||||
periodSeconds: 20
|
||||
failureThreshold: 5
|
||||
livenessProbe:
|
||||
periodSeconds: 20
|
||||
failureThreshold: 5
|
||||
startupProbe:
|
||||
periodSeconds: 20
|
||||
failureThreshold: 5
|
||||
----
|
||||
|
||||
Note that the usage of a relative HTTP path, or an alternative management port, requires changes to the probe configuration.
|
||||
|
||||
=== Disabling required options
|
||||
|
||||
{project_name} and the {project_name} Operator provide the best production-ready experience with security in mind.
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakSpec;
|
|||
import org.keycloak.operator.crds.v2alpha1.deployment.ValueOrSecret;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.CacheSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HttpManagementSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.ProbeSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.SchedulingSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.Truststore;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.TruststoreSource;
|
||||
|
|
@ -327,6 +328,9 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
|
|||
// probes
|
||||
var protocol = isTlsConfigured(keycloakCR) ? "HTTPS" : "HTTP";
|
||||
var port = HttpManagementSpec.managementPort(keycloakCR);
|
||||
var readinessOptionalSpec = Optional.ofNullable(keycloakCR.getSpec().getReadinessProbeSpec());
|
||||
var livenessOptionalSpec = Optional.ofNullable(keycloakCR.getSpec().getLivenessProbeSpec());
|
||||
var startupOptionalSpec = Optional.ofNullable(keycloakCR.getSpec().getStartupProbeSpec());
|
||||
var relativePath = readConfigurationValue(Constants.KEYCLOAK_HTTP_MANAGEMENT_RELATIVE_PATH_KEY, keycloakCR, context)
|
||||
.or(() -> readConfigurationValue(Constants.KEYCLOAK_HTTP_RELATIVE_PATH_KEY, keycloakCR, context))
|
||||
.map(path -> !path.endsWith("/") ? path + "/" : path)
|
||||
|
|
@ -334,8 +338,8 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
|
|||
|
||||
if (!containerBuilder.hasReadinessProbe()) {
|
||||
containerBuilder.withNewReadinessProbe()
|
||||
.withPeriodSeconds(10)
|
||||
.withFailureThreshold(3)
|
||||
.withPeriodSeconds(readinessOptionalSpec.map(ProbeSpec::getProbePeriodSeconds).orElse(10))
|
||||
.withFailureThreshold(readinessOptionalSpec.map(ProbeSpec::getProbeFailureThreshold).orElse(3))
|
||||
.withNewHttpGet()
|
||||
.withScheme(protocol)
|
||||
.withNewPort(port)
|
||||
|
|
@ -345,8 +349,8 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
|
|||
}
|
||||
if (!containerBuilder.hasLivenessProbe()) {
|
||||
containerBuilder.withNewLivenessProbe()
|
||||
.withPeriodSeconds(10)
|
||||
.withFailureThreshold(3)
|
||||
.withPeriodSeconds(livenessOptionalSpec.map(ProbeSpec::getProbePeriodSeconds).orElse(10))
|
||||
.withFailureThreshold(livenessOptionalSpec.map(ProbeSpec::getProbeFailureThreshold).orElse(3))
|
||||
.withNewHttpGet()
|
||||
.withScheme(protocol)
|
||||
.withNewPort(port)
|
||||
|
|
@ -356,8 +360,8 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
|
|||
}
|
||||
if (!containerBuilder.hasStartupProbe()) {
|
||||
containerBuilder.withNewStartupProbe()
|
||||
.withPeriodSeconds(1)
|
||||
.withFailureThreshold(600)
|
||||
.withPeriodSeconds(startupOptionalSpec.map(ProbeSpec::getProbePeriodSeconds).orElse(1))
|
||||
.withFailureThreshold(startupOptionalSpec.map(ProbeSpec::getProbeFailureThreshold).orElse(600))
|
||||
.withNewHttpGet()
|
||||
.withScheme(protocol)
|
||||
.withNewPort(port)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.keycloak.operator.crds.v2alpha1.deployment.spec.HttpManagementSpec;
|
|||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HttpSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.NetworkPolicySpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.ProbeSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.ProxySpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.SchedulingSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.TracingSpec;
|
||||
|
|
@ -135,6 +136,20 @@ public class KeycloakSpec {
|
|||
@JsonPropertyDescription("Configuration related to Keycloak deployment updates.")
|
||||
private UpdateSpec updateSpec;
|
||||
|
||||
@JsonProperty("readinessProbe")
|
||||
@JsonPropertyDescription("Configuration for readiness probe, by default it is 10 for periodSeconds and 3 for failureThreshold")
|
||||
private ProbeSpec readinessProbeSpec;
|
||||
|
||||
|
||||
@JsonProperty("livenessProbe")
|
||||
@JsonPropertyDescription("Configuration for liveness probe, by default it is 10 for periodSeconds and 3 for failureThreshold")
|
||||
private ProbeSpec livenessProbeSpec;
|
||||
|
||||
@JsonProperty("startupProbe")
|
||||
@JsonPropertyDescription("Configuration for startup probe, by default it is 1 for periodSeconds and 600 for failureThreshold")
|
||||
private ProbeSpec startupProbeSpec;
|
||||
|
||||
|
||||
public HttpSpec getHttpSpec() {
|
||||
return httpSpec;
|
||||
}
|
||||
|
|
@ -316,4 +331,22 @@ public class KeycloakSpec {
|
|||
public void setUpdateSpec(UpdateSpec updateSpec) {
|
||||
this.updateSpec = updateSpec;
|
||||
}
|
||||
|
||||
public ProbeSpec getLivenessProbeSpec() {return livenessProbeSpec;}
|
||||
|
||||
public void setLivenessProbeSpec(ProbeSpec livenessProbeSpec) {
|
||||
this.livenessProbeSpec = livenessProbeSpec;
|
||||
}
|
||||
|
||||
public ProbeSpec getReadinessProbeSpec() {return readinessProbeSpec;}
|
||||
|
||||
public void setReadinessProbeSpec(ProbeSpec readinessProbeSpec) {
|
||||
this.readinessProbeSpec = readinessProbeSpec;
|
||||
}
|
||||
|
||||
public ProbeSpec getStartupProbeSpec() {return startupProbeSpec;}
|
||||
|
||||
public void setStartupProbeSpec(ProbeSpec startupProbeSpec) {
|
||||
this.startupProbeSpec = startupProbeSpec;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package org.keycloak.operator.crds.v2alpha1.deployment.spec;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.sundr.builder.annotations.Buildable;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@Buildable(editableEnabled = false, builderPackage = "io.fabric8.kubernetes.api.builder")
|
||||
public class ProbeSpec {
|
||||
|
||||
@JsonProperty("periodSeconds")
|
||||
private int probePeriodSeconds;
|
||||
|
||||
@JsonProperty("failureThreshold")
|
||||
private int probeFailureThreshold;
|
||||
|
||||
public int getProbeFailureThreshold() {return probeFailureThreshold;}
|
||||
public void setProbeFailureThreshold(int probeFailureThreshold) {this.probeFailureThreshold = probeFailureThreshold;}
|
||||
public int getProbePeriodSeconds() {return probePeriodSeconds;}
|
||||
public void setProbePeriodSeconds(int probePeriodSeconds) {this.probePeriodSeconds = probePeriodSeconds;}
|
||||
}
|
||||
|
|
@ -47,6 +47,7 @@ import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition;
|
|||
import org.keycloak.operator.crds.v2alpha1.deployment.ValueOrSecret;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.BootstrapAdminSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HostnameSpecBuilder;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.ProbeSpec;
|
||||
import org.keycloak.operator.testsuite.apiserver.DisabledIfApiServerTest;
|
||||
import org.keycloak.operator.testsuite.unit.WatchedResourcesTest;
|
||||
import org.keycloak.operator.testsuite.utils.CRAssert;
|
||||
|
|
|
|||
|
|
@ -102,6 +102,14 @@ public class CRSerializationTest {
|
|||
HttpManagementSpec managementSpec = keycloak.getSpec().getHttpManagementSpec();
|
||||
assertNotNull(managementSpec);
|
||||
assertEquals(9003, managementSpec.getPort());
|
||||
|
||||
assertEquals(50,keycloak.getSpec().getReadinessProbeSpec().getProbePeriodSeconds());
|
||||
assertEquals(3,keycloak.getSpec().getReadinessProbeSpec().getProbeFailureThreshold());
|
||||
assertEquals(60,keycloak.getSpec().getLivenessProbeSpec().getProbePeriodSeconds());
|
||||
assertEquals(1,keycloak.getSpec().getLivenessProbeSpec().getProbeFailureThreshold());
|
||||
assertEquals(40,keycloak.getSpec().getStartupProbeSpec().getProbePeriodSeconds());
|
||||
assertEquals(2,keycloak.getSpec().getStartupProbeSpec().getProbeFailureThreshold());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -676,6 +676,37 @@ public class PodTemplateTest {
|
|||
assertThat(podTemplate.getSpec().getAffinity()).isNotEqualTo(affinity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProbe(){
|
||||
PodTemplateSpec additionalPodTemplate = null;
|
||||
var readinessProbe = new ProbeBuilder().withFailureThreshold(1).withPeriodSeconds(2).build();
|
||||
var livenessProbe = new ProbeBuilder().withFailureThreshold(3).withPeriodSeconds(4).build();
|
||||
var startupProbe = new ProbeBuilder().withFailureThreshold(5).withPeriodSeconds(6).build();
|
||||
var readinessPodTemplate = getDeployment(additionalPodTemplate, null,
|
||||
s-> s.withNewReadinessProbeSpec()
|
||||
.withProbeFailureThreshold(1)
|
||||
.withProbePeriodSeconds(2)
|
||||
.endReadinessProbeSpec()).getSpec().getTemplate();
|
||||
assertThat(readinessPodTemplate.getSpec().getContainers().get(0).getReadinessProbe().getPeriodSeconds()).isEqualTo(readinessProbe.getPeriodSeconds());
|
||||
assertThat(readinessPodTemplate.getSpec().getContainers().get(0).getReadinessProbe().getFailureThreshold()).isEqualTo(readinessProbe.getFailureThreshold());
|
||||
|
||||
var livenessPodTemplate = getDeployment(additionalPodTemplate, null,
|
||||
s-> s.withNewLivenessProbeSpec()
|
||||
.withProbeFailureThreshold(3)
|
||||
.withProbePeriodSeconds(4)
|
||||
.endLivenessProbeSpec()).getSpec().getTemplate();
|
||||
assertThat(livenessPodTemplate.getSpec().getContainers().get(0).getLivenessProbe().getPeriodSeconds()).isEqualTo(livenessProbe.getPeriodSeconds());
|
||||
assertThat(livenessPodTemplate.getSpec().getContainers().get(0).getLivenessProbe().getFailureThreshold()).isEqualTo(livenessProbe.getFailureThreshold());
|
||||
|
||||
var startupPodTemplate = getDeployment(additionalPodTemplate, null,
|
||||
s-> s.withNewStartupProbeSpec()
|
||||
.withProbeFailureThreshold(5)
|
||||
.withProbePeriodSeconds(6)
|
||||
.endStartupProbeSpec()).getSpec().getTemplate();
|
||||
assertThat(startupPodTemplate.getSpec().getContainers().get(0).getStartupProbe().getPeriodSeconds()).isEqualTo(startupProbe.getPeriodSeconds());
|
||||
assertThat(startupPodTemplate.getSpec().getContainers().get(0).getStartupProbe().getFailureThreshold()).isEqualTo(startupProbe.getFailureThreshold());
|
||||
}
|
||||
|
||||
private Job getUpdateJob(Consumer<KeycloakSpecBuilder> newSpec, Consumer<KeycloakSpecBuilder> oldSpec, Consumer<StatefulSetBuilder> existingModifier) {
|
||||
// create an existing from the old spec and modifier
|
||||
StatefulSetBuilder existingBuilder = getDeployment(null, null, oldSpec).toBuilder();
|
||||
|
|
|
|||
|
|
@ -32,6 +32,15 @@ spec:
|
|||
annotations:
|
||||
myAnnotation: myValue
|
||||
anotherAnnotation: anotherValue
|
||||
readinessProbe:
|
||||
periodSeconds: 50
|
||||
failureThreshold: 3
|
||||
livenessProbe:
|
||||
periodSeconds: 60
|
||||
failureThreshold: 1
|
||||
startupProbe:
|
||||
periodSeconds: 40
|
||||
failureThreshold: 2
|
||||
networkPolicy:
|
||||
enabled: true
|
||||
http:
|
||||
|
|
|
|||
Loading…
Reference in a new issue