forked from quarkusio/quarkus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve usability of gRPC probes in Kubernetes
Plus, I'm adding a new guide about the usage of gRPC services in Kubernetes. Relates to quarkusio#33219 (comment)
- Loading branch information
Showing
9 changed files
with
183 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
//// | ||
This guide is maintained in the main Quarkus repository | ||
and pull requests should be submitted there: | ||
https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc | ||
//// | ||
= Deploying your gRPC Service in Kubernetes | ||
include::_attributes.adoc[] | ||
:categories: serialization | ||
:summary: This guide explains how to deploy your gRPC services in Quarkus to Kubernetes. | ||
|
||
This page explains how to deploy your gRPC service in Quarkus in Kubernetes. | ||
We'll continue with the example from xref:grpc-getting-started.adoc[the Getting Started gRPC guide]. | ||
|
||
== Configuring your project to use the Quarkus Kubernetes extension | ||
|
||
Edit the `pom.xml` file to add the Quarkus Kubernetes extension dependency (just under `<dependencies>`): | ||
|
||
[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] | ||
.pom.xml | ||
---- | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-kubernetes</artifactId> | ||
</dependency> | ||
---- | ||
|
||
Next, we want to expose our application using the Kubernetes Ingress resource: | ||
|
||
[source,properties] | ||
---- | ||
quarkus.kubernetes.ingress.expose=true | ||
---- | ||
|
||
By default, the Quarkus Kubernetes will expose the HTTP port with name `http` which is bound to the Quarkus HTTP server, not the gRPC service. To expose the gRPC server instead, set the `quarkus.kubernetes.ingress.target-port=grpc` property in your application.properties: | ||
|
||
[source,properties] | ||
---- | ||
quarkus.kubernetes.ingress.target-port=grpc | ||
---- | ||
|
||
Finally, we need to generate the Kubernetes manifests by running the Maven command in a terminal: | ||
|
||
[source,shell] | ||
---- | ||
$ mvn clean package | ||
---- | ||
|
||
Once generated, you can look at the `target/kubernetes` directory: | ||
|
||
[source,txt] | ||
---- | ||
target/kubernetes | ||
└── kubernetes.json | ||
└── kubernetes.yml | ||
---- | ||
|
||
You can find more information about how to deploy the application in Kubernetes in the xref:deploying-to-kubernetes.adoc#deployment[the Kubernetes guide]. | ||
|
||
== Using gRPC Health probes | ||
|
||
By default, the Kubernetes resources do not contain readiness and liveness probes. To add them, edit the `pom.xml` to add the Smallrye Health extension: | ||
|
||
[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] | ||
.pom.xml | ||
---- | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-smallrye-health</artifactId> | ||
</dependency> | ||
---- | ||
|
||
TIP: More information about the health extension can be found in xref:microprofile-health.adoc[the Microprofile Health guide]. | ||
|
||
By the default, this extension will configure the probes to use the HTTP server (which is provided by some extensions like the Quarkus RESTEasy reactive extension). Internally, this probe will also use xref:grpc-service-implementation.adoc#health[the generated gRPC Health services]. | ||
|
||
If your application does not use any Quarkus extension that exposes an HTTP server, you can still configure the probes to directly use the gRPC Health service by adding the property `quarkus.kubernetes.readiness-probe.grpc-action-enabled=true` into your configuration: | ||
|
||
[source,properties] | ||
---- | ||
quarkus.kubernetes.readiness-probe.grpc-action-enabled=true | ||
---- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 16 additions & 4 deletions
20
...tes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/ProbeConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,38 @@ | ||
|
||
package io.quarkus.kubernetes.deployment; | ||
|
||
import org.eclipse.microprofile.config.ConfigProvider; | ||
|
||
import io.dekorate.kubernetes.config.Probe; | ||
import io.dekorate.kubernetes.config.ProbeBuilder; | ||
|
||
public class ProbeConverter { | ||
|
||
public static Probe convert(ProbeConfig probe) { | ||
return builder(probe).build(); | ||
public static Probe convert(String name, ProbeConfig probe) { | ||
return builder(name, probe).build(); | ||
} | ||
|
||
public static ProbeBuilder builder(ProbeConfig probe) { | ||
public static ProbeBuilder builder(String name, ProbeConfig probe) { | ||
ProbeBuilder b = new ProbeBuilder(); | ||
probe.httpActionPath.ifPresent(b::withHttpActionPath); | ||
probe.execAction.ifPresent(b::withExecAction); | ||
probe.tcpSocketAction.ifPresent(b::withTcpSocketAction); | ||
probe.grpcAction.ifPresent(b::withGrpcAction); | ||
if (probe.grpcAction.isPresent()) { | ||
b.withGrpcAction(probe.grpcAction.get()); | ||
} else if (probe.grpcActionEnabled) { | ||
b.withGrpcAction(getQuarkusGrpcPort() + ":" + name); | ||
} | ||
|
||
b.withInitialDelaySeconds((int) probe.initialDelay.getSeconds()); | ||
b.withPeriodSeconds((int) probe.period.getSeconds()); | ||
b.withTimeoutSeconds((int) probe.timeout.getSeconds()); | ||
b.withSuccessThreshold(probe.successThreshold); | ||
b.withFailureThreshold(probe.failureThreshold); | ||
return b; | ||
} | ||
|
||
private static int getQuarkusGrpcPort() { | ||
return ConfigProvider.getConfig().getOptionalValue("quarkus.grpc.server.port", Integer.class) | ||
.orElse(9000); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
...andard-way/src/test/java/io/quarkus/it/kubernetes/KubernetesWithGrpcProbeEnabledTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package io.quarkus.it.kubernetes; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.Path; | ||
import java.util.List; | ||
|
||
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.apps.Deployment; | ||
import io.quarkus.builder.Version; | ||
import io.quarkus.maven.dependency.Dependency; | ||
import io.quarkus.test.ProdBuildResults; | ||
import io.quarkus.test.ProdModeTestResults; | ||
import io.quarkus.test.QuarkusProdModeTest; | ||
|
||
public class KubernetesWithGrpcProbeEnabledTest { | ||
|
||
private static final String APP_NAME = "kubernetes-with-grpc-probe"; | ||
|
||
@RegisterExtension | ||
static final QuarkusProdModeTest config = new QuarkusProdModeTest() | ||
.withApplicationRoot((jar) -> jar.addClasses(GreetingResource.class)) | ||
.setApplicationName(APP_NAME) | ||
.setApplicationVersion("0.1-SNAPSHOT") | ||
.overrideConfigKey("quarkus.kubernetes.readiness-probe.grpc-action-enabled", "true") | ||
.setLogFileName("k8s.log") | ||
.setForcedDependencies(List.of( | ||
Dependency.of("io.quarkus", "quarkus-kubernetes", Version.getVersion()), | ||
Dependency.of("io.quarkus", "quarkus-smallrye-health", Version.getVersion()))); | ||
|
||
@ProdBuildResults | ||
private ProdModeTestResults prodModeTestResults; | ||
|
||
@Test | ||
public void assertGeneratedResources() throws IOException { | ||
|
||
final Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); | ||
assertThat(kubernetesDir) | ||
.isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json")) | ||
.isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml")); | ||
List<HasMetadata> kubernetesList = DeserializationUtil | ||
.deserializeAsList(kubernetesDir.resolve("kubernetes.yml")); | ||
assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> { | ||
assertThat(d.getMetadata()).satisfies(m -> { | ||
assertThat(m.getName()).isEqualTo(APP_NAME); | ||
}); | ||
|
||
assertThat(d.getSpec()).satisfies(deploymentSpec -> { | ||
assertThat(deploymentSpec.getTemplate()).satisfies(t -> { | ||
assertThat(t.getSpec()).satisfies(podSpec -> { | ||
assertThat(podSpec.getContainers()).singleElement() | ||
.satisfies(container -> { | ||
assertThat(container.getReadinessProbe()).isNotNull().satisfies(p -> { | ||
assertEquals(p.getGrpc().getPort().intValue(), 9000); | ||
assertEquals(p.getGrpc().getService(), APP_NAME); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
} | ||
} |