Skip to content

Commit

Permalink
DeploymentConfig deprecated
Browse files Browse the repository at this point in the history
  • Loading branch information
edeandrea committed Nov 28, 2023
1 parent 6c11d36 commit dbeacf6
Show file tree
Hide file tree
Showing 47 changed files with 1,204 additions and 66 deletions.
34 changes: 14 additions & 20 deletions docs/src/main/asciidoc/deploying-to-openshift.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,19 @@ TIP: If you want to test your application immediately then set the `quarkus.open
NOTE: When using `DeploymentConfig` and xref:deploying-to-kubernetes.adoc#service_binding[Service Binding], re-deploying might remove the configuration added by OpenShift to allow service discovery. A new container image build will trigger a refresh of the Quarkus app in OpenShift: `-Dquarkus.container-image.build=true` which might be enough in most situations. If you need to update the OpenShift resources, you need to delete the binding first to create it again after new deployment.

This command will build your application locally, then trigger a container image build and finally apply the generated OpenShift resources automatically.
The generated resources use OpenShift's `DeploymentConfig` that is configured to automatically trigger a redeployment when a change in the `ImageStream` is noticed.
In other words, any container image build after the initial deployment will automatically trigger redeployment, without the need to delete, update or re-apply the generated resources.
The generated resources use a Kubernetes `Deployment`, but still make use of OpenShift specific resources like `Route`, `BuildConfig` etc.

IMPORTANT: As of OpenShift 4.14, the https://access.redhat.com/articles/7041372[`DeploymentConfig` object has been deprecated].

Since `Deployment` is a Kubernetes resource and not OpenShift specific, it can't possibly leverage `ImageStream` resources, as is the case with `DeploymentConfig`. This means that the image references need to include the container image registry that hosts the image.
When the image is built, using OpenShift builds (s2i binary and docker strategy) the OpenShift internal image registry `image-registry.openshift-image-registry.svc:5000` will be used, unless another registry has been explicitly specified by the user. Please note, that in the internal registry the project/namespace name is added as part of the image repository: `image-registry.openshift-image-registry.svc:5000/<project name>/<name>:<tag>`, so users will need to make sure that the target project/namespace name is aligned with the `quarkus.container-image.group`.

The https://access.redhat.com/articles/7041372[deprecation document] contains additional information about how to set up/use automatic rollbacks, triggers, lifecycle hooks, and custom strategies.

[source,properties]
----
quarkus.container-image.group=<project/namespace name>
----

You can use the OpenShift web console to verify that the above command has created an image stream, a service resource and has deployed the application.
Alternatively, you can run the following OpenShift CLI commands:
Expand Down Expand Up @@ -384,30 +395,13 @@ quarkus.openshift.env.fields.foo=metadata.name

==== Changing the generated deployment resource

Beside generating a `DeploymentConfig` resource, you can also choose to get either a `Deployment`, `StatefulSet`, or a `Job`, or a `CronJob` resource instead via `application.properties`:
Beside generating a `Deployment` resource, you can also choose to get either a `DeploymentConfig`, `StatefulSet`, `Job`, or a `CronJob` resource instead via `application.properties`:

[source,properties]
----
quarkus.openshift.deployment-kind=StatefulSet
----

===== Using Deployment instead of DeploymentConfig
Out of the box the extension will generate a `DeploymentConfig` resource. Often users, prefer to use `Deployment` as the main deployment resource, but still make use of OpenShift specific resources like `Route`, `BuildConfig` etc.
This feature is enabled by setting `quarkus.openshift.deployment-kind` to `Deployment`.

[source,properties]
----
quarkus.openshift.deployment-kind=Deployment
----

Since `Deployment` is a Kubernetes resource and not OpenShift specific, it can't possibly leverage `ImageStream` resources, as is the case with `DeploymentConfig`. This means that the image references need to include the container image registry that hosts the image.
When the image is built, using OpenShift builds (s2i binary and docker strategy) the OpenShift internal image registry `image-registry.openshift-image-registry.svc:5000` will be used, unless another registry has been explicitly specified by the user. Please note, that in the internal registry the project/namespace name is added as part of the image repository: `image-registry.openshift-image-registry.svc:5000/<project name>/<name>:<tag>`, so users will need to make sure that the target project/namespace name is aligned with the `quarkus.container-image.group`.

[source,properties]
----
quarkus.container-image.group=<project/namespace name>
----

===== Generating Job resources

If you want to generate a Job resource, you need to add the following property via the `application.properties`:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public static enum OpenshiftFlavor {

public static enum DeploymentResourceKind {
Deployment(DEPLOYMENT, DEPLOYMENT_GROUP, DEPLOYMENT_VERSION),
@Deprecated(since = "OpenShift 4.14")
DeploymentConfig(DEPLOYMENT_CONFIG, DEPLOYMENT_CONFIG_GROUP, DEPLOYMENT_CONFIG_VERSION),
StatefulSet(STATEFULSET, DEPLOYMENT_GROUP, DEPLOYMENT_VERSION),
Job(JOB, BATCH_GROUP, BATCH_VERSION),
Expand All @@ -67,7 +68,9 @@ public static enum DeploymentResourceKind {

/**
* The kind of the deployment resource to use.
* Supported values are 'Deployment', 'StatefulSet', 'Job', 'CronJob' and 'DeploymentConfig' defaulting to the latter.
* Supported values are 'Deployment', 'StatefulSet', 'Job', 'CronJob' and 'DeploymentConfig'. Defaults to 'DeploymentConfig'
* if {@code flavor == v3}, or 'Deployment' otherwise.
* DeploymentConfig is deprecated as of OpenShift 4.14. See https://access.redhat.com/articles/7041372 for details.
*/
@ConfigItem
Optional<DeploymentResourceKind> deploymentKind;
Expand Down Expand Up @@ -654,6 +657,6 @@ public DeploymentResourceKind getDeploymentResourceKind(Capabilities capabilitie
return DeploymentResourceKind.Job;
}

return DeploymentResourceKind.DeploymentConfig;
return (flavor == OpenshiftFlavor.v3) ? DeploymentResourceKind.DeploymentConfig : DeploymentResourceKind.Deployment;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# invoker.goals=clean package -Dquarkus.container.build=true -Dquarkus.package.type=native
# ensure that an attempt to deploy is made, but that the attempt fails (as we don't want to deploy this test application to a cluster that the runner of test may have configured)
invoker.goals=clean package -Dquarkus.kubernetes.deploy=true ${kubernetes-client-api-server-url}
# expect a failure since there is no Kubernetes cluster to deploy to
invoker.buildResult = ${build-result}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.acme</groupId>
<artifactId>openshift-docker-build-and-deploy-deploymentconfig</artifactId>
<version>0.1-SNAPSHOT</version>
<properties>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<surefire-plugin.version>3.1.2</surefire-plugin.version>
<maven.compiler.source>11</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bom</artifactId>
<version>@project.version@</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-openshift</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-docker</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>${native.surefire.skip}</skipTests>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
#
# Before building the container image run:
#
# ./mvnw package
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/rest-client-quickstart-jvm .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/rest-client-quickstart-jvm
#
# If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050
#
# Then run the container using :
#
# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/rest-client-quickstart-jvm
#
###
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8

ARG JAVA_PACKAGE=java-11-openjdk-headless
ARG RUN_JAVA_VERSION=1.3.8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
# Install java and the run-java script
# Also set up permissions for user `1001`
RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
&& microdnf update \
&& microdnf clean all \
&& mkdir /deployments \
&& chown 1001 /deployments \
&& chmod "g+rwX" /deployments \
&& chown 1001:root /deployments \
&& curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
&& chown 1001 /deployments/run-java.sh \
&& chmod 540 /deployments/run-java.sh \
&& echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security

# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=1001 target/quarkus-app/*.jar /deployments/
COPY --chown=1001 target/quarkus-app/app/ /deployments/app/
COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/

EXPOSE 8080
USER 1001

ENTRYPOINT [ "/deployments/run-java.sh" ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.acme;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
public class Hello {

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Configuration file
# key = value

quarkus.kubernetes.deployment-target=openshift
quarkus.kubernetes-client.trust-certs=true
quarkus.container-image.builder=docker
quarkus.container-image.group=test
quarkus.openshift.deployment-kind=deployment-config
# To try it locally (outside of Openshift) just provide registry details
#quarkus.container-image.registry=docker.io
#quarkus.container-image.group=<<username>>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import io.dekorate.utils.Serialization
import io.fabric8.kubernetes.api.model.KubernetesList
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.openshift.api.model.*

//Check that file exits
String base = basedir
File openshiftYml = new File(base, "target/kubernetes/openshift.yml")
assert openshiftYml.exists()
openshiftYml.withInputStream { stream ->
//Check that its parse-able
KubernetesList list = Serialization.unmarshalAsList(stream)
assert list != null

ImageStream imageStream = list.items.find{r -> r.kind == "ImageStream"}
assert imageStream != null
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ openshiftYml.withInputStream { stream ->
assert list != null

ImageStream imageStream = list.items.find{r -> r.kind == "ImageStream"}
assert imageStream != null
assert imageStream == null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.quarkus.it.kubernetes.kafka;

import static org.assertj.core.api.Assertions.*;

import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;

import org.assertj.core.api.AbstractObjectAssert;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.PodTemplateSpec;
import io.quarkus.test.ProdBuildResults;
import io.quarkus.test.ProdModeTestResults;
import io.quarkus.test.QuarkusProdModeTest;

public class BasicOpenshiftDeploymentConfigTest {

@RegisterExtension
static final QuarkusProdModeTest config = new QuarkusProdModeTest()
.withApplicationRoot((jar) -> jar.addClasses(DummyProcessor.class))
.setApplicationName("basic-openshift")
.setApplicationVersion("0.1-SNAPSHOT")
.withConfigurationResource("basic-openshift.properties")
.overrideConfigKey("quarkus.openshift.deployment-kind", "deployment-config");

@ProdBuildResults
private ProdModeTestResults prodModeTestResults;

@SuppressWarnings("unchecked")
@Test
public void assertGeneratedResources() throws IOException {
Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes");
assertThat(kubernetesDir)
.isDirectoryContaining(p -> p.getFileName().endsWith("openshift.json"))
.isDirectoryContaining(p -> p.getFileName().endsWith("openshift.yml"))
.satisfies(p -> assertThat(p.toFile().listFiles()).hasSize(2));
List<HasMetadata> openshiftList = DeserializationUtil
.deserializeAsList(kubernetesDir.resolve("openshift.yml"));

assertThat(openshiftList).filteredOn(h -> "DeploymentConfig".equals(h.getKind())).singleElement().satisfies(h -> {
assertThat(h.getMetadata()).satisfies(m -> {
assertThat(m.getName()).isEqualTo("basic-openshift");
assertThat(m.getLabels().get("app.openshift.io/runtime")).isEqualTo("quarkus");
assertThat(m.getNamespace()).isNull();
});
AbstractObjectAssert<?, ?> specAssert = assertThat(h).extracting("spec");
specAssert.extracting("replicas").isEqualTo(1);
specAssert.extracting("selector").isInstanceOfSatisfying(Map.class, selectorsMap -> {
assertThat(selectorsMap).containsOnly(entry("app.kubernetes.io/name", "basic-openshift"),
entry("app.kubernetes.io/version", "0.1-SNAPSHOT"));
});
specAssert.extracting("template").isInstanceOfSatisfying(PodTemplateSpec.class, templateMap -> {
assertThat(templateMap.getSpec()).satisfies(podSpec -> {
assertThat(podSpec.getContainers()).singleElement().satisfies(container -> {
assertThat(container.getPorts()).isNullOrEmpty();
});
});
});
});
}
}
Loading

0 comments on commit dbeacf6

Please sign in to comment.