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.
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.
= 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]
====
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>

View file

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

View file

@ -208,7 +208,9 @@ public class KeycloakDeploymentDependentResource extends CRUDKubernetesDependent
if (Optional.ofNullable(containerBuilder.getArgs()).orElse(List.of()).isEmpty()) {
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(0, getJGroupsParameter(keycloakCR));

View file

@ -16,24 +16,24 @@
*/
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.model.annotation.SpecReplicas;
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.HostnameSpec;
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.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.List;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class KeycloakSpec {
@ -44,6 +44,9 @@ public class KeycloakSpec {
@JsonPropertyDescription("Custom Keycloak image to be used.")
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.")
private List<LocalObjectReference> imagePullSecrets;
@ -171,4 +174,12 @@ public class KeycloakSpec {
public void setAdditionalOptions(List<ValueOrSecret> 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.keycloak.image=${RELATED_IMAGE_KEYCLOAK:quay.io/keycloak/keycloak:nightly}
operator.keycloak.image-pull-policy=Always
operator.keycloak.start-optimized=false
# https://quarkus.io/guides/deploying-to-kubernetes#environment-variables-from-keyvalue-pairs
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();
// 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));
}
}