enhance: adding a start optimized flag (#25216)

closes: #25015



Update docs/guides/operator/customizing-keycloak.adoc
Update docs/documentation/release_notes/topics/24_0_0.adoc
Update operator/src/main/java/org/keycloak/operator/crds/v2alpha1/deployment/KeycloakSpec.java

Signed-off-by: Václav Muzikář <vmuzikar@redhat.com>
Co-authored-by: Václav Muzikář <vaclav@muzikari.cz>
This commit is contained in:
Steven Hawkins 2023-12-11 11:15:16 -05:00 committed by GitHub
parent 0f5bbae75c
commit 4db4982e9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 10 deletions

View file

@ -23,3 +23,9 @@ The endpoint is currently checking availability of the embedded and external Inf
This endpoint is not available by default. This endpoint is not available by default.
To enable it, run Keycloak with feature `multi-site`. To enable it, run Keycloak with feature `multi-site`.
Proceed to https://www.keycloak.org/server/features[Enabling and disabling features] guide for more details. Proceed to https://www.keycloak.org/server/features[Enabling and disabling features] guide for more details.
= Keycloak CR Optimized Field
The Keycloak CR now includes an `startOptimized` field, which may be used to override the default assumption about whether to use the `--optimized` flag for the start command.
As a result, you can use the CR to configure build time options also when a custom Keycloak image is used.

View file

@ -45,7 +45,29 @@ spec:
[NOTE] [NOTE]
==== ====
With custom images, every build time option is passed either through a dedicated field or the `additionalOptions` is ignored. With custom images, every build time option passed either through a dedicated field or the `additionalOptions` is ignored.
==== ====
=== Non-optimized custom image
While it is considered a best practice use a pre-augmented image, if you want to use a non-optimized custom image or build time properties with an augmented image that is still possible. You just need set the `startOptimzed` field to `false` as shown in this example:
[source,yaml]
----
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
name: example-kc
spec:
instances: 1
image: quay.io/my-company/my-keycloak:latest
startOptimized: false
http:
tlsSecret: example-tls-secret
hostname:
hostname: test.keycloak.org
----
Keep in mind this will incur the re-augmentation cost on every start.
</@tmpl.guide> </@tmpl.guide>

View file

@ -31,6 +31,7 @@ public interface Config {
interface Keycloak { interface Keycloak {
String image(); String image();
String imagePullPolicy(); String imagePullPolicy();
boolean startOptimized();
Map<String, String> podLabels(); Map<String, String> podLabels();
} }

View file

@ -208,7 +208,9 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
if (Optional.ofNullable(containerBuilder.getArgs()).orElse(List.of()).isEmpty()) { if (Optional.ofNullable(containerBuilder.getArgs()).orElse(List.of()).isEmpty()) {
containerBuilder.withArgs("--verbose", "start"); containerBuilder.withArgs("--verbose", "start");
} }
if (customImage.isPresent()) { if (Boolean.TRUE.equals(keycloakCR.getSpec().getStartOptimized())
|| keycloakCR.getSpec().getStartOptimized() == null
&& (customImage.isPresent() || operatorConfig.keycloak().startOptimized())) {
containerBuilder.addToArgs(OPTIMIZED_ARG); containerBuilder.addToArgs(OPTIMIZED_ARG);
} }
containerBuilder.addToArgs(0, getJGroupsParameter(keycloakCR)); containerBuilder.addToArgs(0, getJGroupsParameter(keycloakCR));

View file

@ -16,24 +16,24 @@
*/ */
package org.keycloak.operator.crds.v2alpha1.deployment; package org.keycloak.operator.crds.v2alpha1.deployment;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import io.fabric8.kubernetes.api.model.LocalObjectReference; import io.fabric8.kubernetes.api.model.LocalObjectReference;
import io.fabric8.kubernetes.model.annotation.SpecReplicas; import io.fabric8.kubernetes.model.annotation.SpecReplicas;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.DatabaseSpec; import org.keycloak.operator.crds.v2alpha1.deployment.spec.DatabaseSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.FeatureSpec; import org.keycloak.operator.crds.v2alpha1.deployment.spec.FeatureSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HostnameSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HttpSpec; import org.keycloak.operator.crds.v2alpha1.deployment.spec.HttpSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.UnsupportedSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec; import org.keycloak.operator.crds.v2alpha1.deployment.spec.IngressSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.TransactionsSpec; import org.keycloak.operator.crds.v2alpha1.deployment.spec.TransactionsSpec;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HostnameSpec; import org.keycloak.operator.crds.v2alpha1.deployment.spec.UnsupportedSpec;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class KeycloakSpec { public class KeycloakSpec {
@ -44,6 +44,9 @@ public class KeycloakSpec {
@JsonPropertyDescription("Custom Keycloak image to be used.") @JsonPropertyDescription("Custom Keycloak image to be used.")
private String image; private String image;
@JsonPropertyDescription("Set to force the behavior of the --optimized flag for the start command. If left unspecified the operator will assume custom images have already been augmented.")
private Boolean startOptimized;
@JsonPropertyDescription("Secret(s) that might be used when pulling an image from a private container image registry or repository.") @JsonPropertyDescription("Secret(s) that might be used when pulling an image from a private container image registry or repository.")
private List<LocalObjectReference> imagePullSecrets; private List<LocalObjectReference> imagePullSecrets;
@ -171,4 +174,12 @@ public class KeycloakSpec {
public void setAdditionalOptions(List<ValueOrSecret> additionalOptions) { public void setAdditionalOptions(List<ValueOrSecret> additionalOptions) {
this.additionalOptions = additionalOptions; this.additionalOptions = additionalOptions;
} }
public Boolean getStartOptimized() {
return startOptimized;
}
public void setStartOptimized(Boolean optimized) {
this.startOptimized = optimized;
}
} }

View file

@ -7,6 +7,7 @@ quarkus.banner.enabled=false
# Operator config # Operator config
operator.keycloak.image=${RELATED_IMAGE_KEYCLOAK:quay.io/keycloak/keycloak:nightly} operator.keycloak.image=${RELATED_IMAGE_KEYCLOAK:quay.io/keycloak/keycloak:nightly}
operator.keycloak.image-pull-policy=Always operator.keycloak.image-pull-policy=Always
operator.keycloak.start-optimized=false
# https://quarkus.io/guides/deploying-to-kubernetes#environment-variables-from-keyvalue-pairs # https://quarkus.io/guides/deploying-to-kubernetes#environment-variables-from-keyvalue-pairs
quarkus.kubernetes.env.vars.related-image-keycloak=${operator.keycloak.image} quarkus.kubernetes.env.vars.related-image-keycloak=${operator.keycloak.image}

View file

@ -371,6 +371,35 @@ public class PodTemplateTest {
var podTemplate = getDeployment(additionalPodTemplate).getSpec().getTemplate(); var podTemplate = getDeployment(additionalPodTemplate).getSpec().getTemplate();
// Assert // Assert
assertThat(podTemplate.getSpec().getContainers().get(0).getArgs()).doesNotContain("--optimized"); assertThat(podTemplate.getSpec().getContainers().get(0).getArgs()).doesNotContain(KeycloakDeploymentDependentResource.OPTIMIZED_ARG);
} }
@Test
public void testImageNotOptimized() {
// Arrange
PodTemplateSpec additionalPodTemplate = null;
// Act
var podTemplate = getDeployment(additionalPodTemplate, null,
s -> s.withImage("some-image").withStartOptimized(false))
.getSpec().getTemplate();
// Assert
assertThat(podTemplate.getSpec().getContainers().get(0).getArgs()).doesNotContain(KeycloakDeploymentDependentResource.OPTIMIZED_ARG);
}
@Test
public void testImageForceOptimized() {
// Arrange
PodTemplateSpec additionalPodTemplate = null;
// Act
var podTemplate = getDeployment(additionalPodTemplate, null,
s -> s.withStartOptimized(true))
.getSpec().getTemplate();
// Assert
assertThat(podTemplate.getSpec().getContainers().get(0).getCommand().contains(KeycloakDeploymentDependentResource.OPTIMIZED_ARG));
}
} }