Skip to content

Commit 24a5824

Browse files
committed
Clean up Kubernetes Dev Service doc and code
1 parent de51d08 commit 24a5824

File tree

6 files changed

+59
-111
lines changed

6 files changed

+59
-111
lines changed

core/deployment/src/main/java/io/quarkus/deployment/builditem/ContainerRuntimeStatusBuildItem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
public abstract class ContainerRuntimeStatusBuildItem extends SimpleBuildItem {
77
private final IsContainerRuntimeWorking isContainerRuntimeWorking;
8-
private Boolean cachedStatus;
8+
private volatile Boolean cachedStatus;
99

1010
protected ContainerRuntimeStatusBuildItem(IsContainerRuntimeWorking isContainerRuntimeWorking) {
1111
this.isContainerRuntimeWorking = isContainerRuntimeWorking;

docs/src/main/asciidoc/kubernetes-dev-services.adoc

Lines changed: 18 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -17,76 +17,33 @@ The following https://github.com/dajudge/kindcontainer?tab=readme-ov-file#contai
1717

1818
== Enabling / Disabling Dev Services for Kubernetes
1919

20-
Dev Services for Kubernetes is automatically enabled unless:
20+
To use the Kubernetes Dev Service, you simply need to add the `quarkus-kubernetes-client` extension to your project:
2121

22-
- `quarkus.kubernetes-client.devservices.enabled` is set to `false`
23-
- the `api-server-url` is configured
24-
- a valid Kube config file is found and `quarkus.kubernetes-client.devservices.override-kubeconfig` is not set to `true`
25-
- you include the `quarkus-test-kubernetes-client` dependency
22+
:add-extension-extensions: kubernetes-client
23+
include::{includes}/devtools/extension-add.adoc[]
2624

27-
NOTE: Dev Services for Kubernetes relies on a container engine: Docker or Podman to start the server.
25+
A Kubernetes API server is automatically started in dev or test modes whenever the `quarkus-kubernetes-client` extension is configured for a project. However, the dev service is disabled in some cases to prevent potential confusing situations:
26+
27+
- if the dev service is explicitly disabled by setting `quarkus.kubernetes-client.devservices.enabled` to `false`
28+
- if the client is explicitly configured to access a given API server via `quarkus.kubernetes-client.api-server-url`
29+
- if a valid Kube config file is found, in which case that configuration will be used by the client. It is, however, possible to force the dev service to start anyway by setting `quarkus.kubernetes-client.devservices.override-kubeconfig` to `true` to disregard the existing configuration
30+
- if you include the `quarkus-test-kubernetes-client` dependency as, presumably, in that case, you have tests that rely on the Fabric8 mock server and don't need to start a cluster
31+
32+
NOTE: Dev Services for Kubernetes relies on a container engine (Docker or Podman) to start the server.
2833
If your environment does not support such a container engine, you will have to start a Kubernetes cluster running in a VM, in the cloud, etc.
29-
In this case, you can configure the Kubernetes cluster access using either a Kube config file or the various properties available in the https://github.com/quarkusio/quarkus/blob/main/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesClientBuildConfig.java[KubernetesClientBuildConfig] class.
34+
In this case, you can configure the Kubernetes cluster access using either a Kube config file or the various properties available as specified in the xref:kubernetes-client.adoc[Kubernetes client configuration guide].
3035

3136
== Shared cluster
3237

33-
Most of the time you need to share the cluster between applications.
34-
Dev Services for Kubernetes implements a _service discovery_ mechanism for your multiple Quarkus applications running in dev mode to share a single cluster.
38+
Applications often need to share access to the same cluster. For that purpose, Dev Services for Kubernetes implements a _service discovery_ mechanism for multiple Quarkus applications running in dev mode to share a single cluster.
3539

36-
NOTE: Dev Services for Kubernetes starts the container with the `quarkus-dev-service-kubernetes` label which is used to identify the container.
40+
NOTE: Dev Services for Kubernetes starts the api server container with the `quarkus-dev-service-kubernetes` label which is used to identify it.
3741

38-
If you need multiple (shared) clusters, you can configure the `quarkus.kubernetes-client.devservices.service-name` configuration property and indicate the cluster name.
39-
It looks for a container with the name defined, or starts a new one if none can be found.
40-
The default service name is `kubernetes`.
42+
If you need multiple (shared) clusters, you can provide a value for the `quarkus.kubernetes-client.devservices.service-name` configuration property to specify the name of the cluster that will be shared among the selected applications. The dev service support will look for an already existing container with that specified name or starts a new one if none can be found.The default service name is `kubernetes`.
4143

4244
Sharing is enabled by default in dev mode, but disabled in test mode.
4345
You can disable the sharing with `quarkus.kubernetes-client.devservices.shared=false`.
4446

45-
== What else for the developers
46-
47-
If you would like to develop test cases running top of the kubernetes cluster (launched as test container by the Dev Service), then add the following dependencies to your pom file
48-
49-
[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"]
50-
.pom.xml
51-
----
52-
<dependency>
53-
<groupId>io.quarkus</groupId>
54-
<artifactId>quarkus-kubernetes-client</artifactId>
55-
</dependency>
56-
----
57-
58-
and set the Quarkus properties to select the flavor, or kube version.
59-
60-
Then you will be able to create a Fabric8 Kubernetes Client object able to perform many kube tasks as detailed part of this https://github.com/fabric8io/kubernetes-client/blob/main/doc/CHEATSHEET.md[cheat sheet].
61-
62-
.Simple Bean Example
63-
[source,java]
64-
----
65-
package org.acme;
66-
67-
import org.junit.jupiter.api.Test;
68-
69-
import io.fabric8.kubernetes.api.model.*;
70-
import io.fabric8.kubernetes.client.KubernetesClient;
71-
import io.quarkus.test.junit.QuarkusTest;
72-
73-
@QuarkusTest
74-
public class ArgocdExtensionDevModeTest {
75-
76-
@Inject
77-
private KubernetesClient client;
78-
79-
@Test
80-
public void testCreatePod() {
81-
client.resource(new PodBuilder()
82-
.withMetadata(<METADATA_OBJECT>)
83-
.withSpec(<SPEC_OBJECT>)
84-
.build())
85-
.inNamespace(<USER_NAMESPACE>)
86-
.create();
87-
}
88-
----
89-
9047
== Configuring the cluster
9148

9249
Dev Services for Kubernetes provides three different flavors of Kubernetes cluster. Each flavor supports different Kubernetes API versions.
@@ -98,10 +55,12 @@ quarkus.kubernetes-client.devservices.flavor=api-only # k3s or kind
9855
quarkus.kubernetes-client.devservices.api-version=1.22
9956
----
10057

101-
`api-only` only starts a Kubernetes API Server (plus the required etcd). If you need a fully-featured Kubernetes cluster that can spin up Pods, you can use `k3s` or `kind`. `k3s` requires to start the container with `privileged mode`. The `kind` test container supports now to use podman rootless or rootfull.
58+
`api-only` only starts a Kubernetes API Server (plus the required etcd). If you need a fully-featured Kubernetes cluster that can spin up Pods, you can use `k3s` or `kind`. `k3s` requires to start the container with `privileged mode`. The `kind` test container now also supports using podman's rootless mode.
10259

10360
If `api-version` is not set, the latest version for the given flavor will be used. Otherwise, the version must match a https://github.com/dajudge/kindcontainer/blob/master/k8s-versions.json[version supported by the given flavor].
10461

62+
Once the cluster is configured, you can access it easily as you normally would, for example, by injecting a client instance in your test.
63+
10564
== Configuration reference
10665

10766
include::{generated-dir}/config/quarkus-kubernetes-client_quarkus.kubernetes-client.devservices.adoc[opts=optional, leveloffset=+1]

extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/DevServicesKubernetesProcessor.java

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import com.dajudge.kindcontainer.K3sContainerVersion;
3131
import com.dajudge.kindcontainer.KindContainer;
3232
import com.dajudge.kindcontainer.KindContainerVersion;
33-
import com.dajudge.kindcontainer.KubernetesContainer;
3433
import com.dajudge.kindcontainer.KubernetesVersionEnum;
3534
import com.dajudge.kindcontainer.client.KubeConfigUtils;
3635
import com.dajudge.kindcontainer.client.config.Cluster;
@@ -77,7 +76,6 @@ public class DevServicesKubernetesProcessor {
7776
private static final String KUBERNETES_CLIENT_DEVSERVICES_OVERRIDE_KUBECONFIG = "quarkus.kubernetes-client.devservices.override-kubeconfig";
7877
private static final Logger log = Logger.getLogger(DevServicesKubernetesProcessor.class);
7978
private static final String KUBERNETES_CLIENT_MASTER_URL = "quarkus.kubernetes-client.api-server-url";
80-
private static final String KUBERNETES_CLIENT_DEVSERVICES_FLAVOR = "quarkus.kubernetes-client.devservices.flavor";
8179
private static final String DEFAULT_MASTER_URL_ENDING_WITH_SLASH = Config.DEFAULT_MASTER_URL + "/";
8280

8381
static final String DEV_SERVICE_LABEL = "quarkus-dev-service-kubernetes";
@@ -88,6 +86,7 @@ public class DevServicesKubernetesProcessor {
8886
static volatile KubernetesDevServiceCfg cfg;
8987
static volatile boolean first = true;
9088

89+
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
9190
@BuildStep
9291
public DevServicesResultBuildItem setupKubernetesDevService(
9392
DockerStatusBuildItem dockerStatusBuildItem,
@@ -172,7 +171,7 @@ private void shutdownCluster() {
172171
}
173172
}
174173

175-
@SuppressWarnings("unchecked")
174+
@SuppressWarnings({ "unchecked", "OptionalUsedAsFieldOrParameterType" })
176175
private RunningDevService startKubernetes(DockerStatusBuildItem dockerStatusBuildItem,
177176
DevServicesComposeProjectBuildItem composeProjectBuildItem,
178177
KubernetesDevServiceCfg config,
@@ -187,29 +186,27 @@ private RunningDevService startKubernetes(DockerStatusBuildItem dockerStatusBuil
187186

188187
// Check if kubernetes-client.api-server-url is set
189188
if (ConfigUtils.isPropertyNonEmpty(KUBERNETES_CLIENT_MASTER_URL)) {
190-
log.debug("Not starting Dev Services for Kubernetes, the " + KUBERNETES_CLIENT_MASTER_URL + " is configured.");
189+
log.debug("Not starting Dev Services for Kubernetes as the client has been explicitly configured via "
190+
+ KUBERNETES_CLIENT_MASTER_URL);
191191
return null;
192192
}
193193

194-
// Check if we should create a kind test container and launch it
195-
// based on the Dev services config or the KubernetesRequest of the producer
196-
boolean shouldStart = config.overrideKubeconfig
197-
|| devServiceKubeRequest.isPresent();
198-
194+
// If we have an explicit request coming from extensions, start even if there's a non-explicitly overridden kube config
195+
final boolean shouldStart = config.overrideKubeconfig || devServiceKubeRequest.isPresent();
199196
if (!shouldStart) {
200197
var autoConfigMasterUrl = Config.autoConfigure(null).getMasterUrl();
201198
if (!DEFAULT_MASTER_URL_ENDING_WITH_SLASH.equals(autoConfigMasterUrl)) {
202199
log.debug(
203-
"Not starting Dev Services for Kubernetes, the Kubernetes client is auto-configured. Set "
200+
"Not starting Dev Services for Kubernetes as a kube config file has been found. Set "
204201
+ KUBERNETES_CLIENT_DEVSERVICES_OVERRIDE_KUBECONFIG
205-
+ " to true to use Dev Services for Kubernetes.");
202+
+ " to true to disregard the config and start Dev Services for Kubernetes.");
206203
return null;
207204
}
208205
}
209206

210207
if (!dockerStatusBuildItem.isContainerRuntimeAvailable()) {
211208
log.warn(
212-
"Docker isn't working, please configure the Kubernetes client.");
209+
"A running container runtime is required for Dev Services to work. Please check if your container runtime is running.");
213210
return null;
214211
}
215212

@@ -221,35 +218,26 @@ private RunningDevService startKubernetes(DockerStatusBuildItem dockerStatusBuil
221218
KUBERNETES_PORT, launchMode.getLaunchMode(), useSharedNetwork));
222219

223220
final Supplier<RunningDevService> defaultKubernetesClusterSupplier = () -> {
224-
KubernetesContainer container;
225-
226221
Flavor clusterType = config.flavor
227222
.or(() -> devServiceKubeRequest
228223
.map(KubernetesDevServiceRequestBuildItem::getFlavor)
229224
.map(Flavor::valueOf))
230225
.orElse(api_only);
231226

232-
switch (clusterType) {
233-
case api_only:
234-
container = new ApiServerContainer(
235-
config.apiVersion
236-
.map(version -> findOrElseThrow(clusterType, version, ApiServerContainerVersion.class))
237-
.orElseGet(() -> latest(ApiServerContainerVersion.class)));
238-
break;
239-
case k3s:
240-
container = new K3sContainer(
241-
config.apiVersion.map(version -> findOrElseThrow(clusterType, version, K3sContainerVersion.class))
242-
.orElseGet(() -> latest(K3sContainerVersion.class)));
243-
break;
244-
case kind:
245-
container = new KindContainer(
246-
config.apiVersion
247-
.map(version -> findOrElseThrow(clusterType, version, KindContainerVersion.class))
248-
.orElseGet(() -> latest(KindContainerVersion.class)));
249-
break;
250-
default:
251-
throw new RuntimeException(KUBERNETES_CLIENT_DEVSERVICES_FLAVOR + " must be a valid Flavor enum value.");
252-
}
227+
@SuppressWarnings("rawtypes")
228+
final var container = switch (clusterType) {
229+
case api_only -> new ApiServerContainer(
230+
config.apiVersion
231+
.map(version -> findOrElseThrow(clusterType, version, ApiServerContainerVersion.class))
232+
.orElseGet(() -> latest(ApiServerContainerVersion.class)));
233+
case k3s -> new K3sContainer(
234+
config.apiVersion.map(version -> findOrElseThrow(clusterType, version, K3sContainerVersion.class))
235+
.orElseGet(() -> latest(K3sContainerVersion.class)));
236+
case kind -> new KindContainer(
237+
config.apiVersion
238+
.map(version -> findOrElseThrow(clusterType, version, KindContainerVersion.class))
239+
.orElseGet(() -> latest(KindContainerVersion.class)));
240+
};
253241

254242
if (useSharedNetwork) {
255243
ConfigureUtil.configureSharedNetwork(container, "quarkus-kubernetes-client");
@@ -323,6 +311,7 @@ private KubernetesDevServiceCfg getConfiguration(KubernetesClientBuildConfig cfg
323311
return new KubernetesDevServiceCfg(devServicesConfig);
324312
}
325313

314+
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
326315
private static final class KubernetesDevServiceCfg {
327316

328317
public boolean devServicesEnabled;
@@ -352,9 +341,8 @@ public int hashCode() {
352341
public boolean equals(Object obj) {
353342
if (this == obj)
354343
return true;
355-
if (!(obj instanceof KubernetesDevServiceCfg))
344+
if (!(obj instanceof KubernetesDevServiceCfg other))
356345
return false;
357-
KubernetesDevServiceCfg other = (KubernetesDevServiceCfg) obj;
358346
return devServicesEnabled == other.devServicesEnabled && flavor == other.flavor
359347
&& Objects.equals(apiVersion, other.apiVersion) && overrideKubeconfig == other.overrideKubeconfig
360348
&& shared == other.shared && Objects.equals(serviceName, other.serviceName)

extensions/kubernetes-client/deployment/src/main/java/io/quarkus/kubernetes/client/deployment/NoQuarkusTestKubernetesClient.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@
66
/**
77
* Boolean supplier that returns true if quarkus-test-kubernetes-client is not
88
* present in the application pom.xml.
9-
*
9+
* <p>
1010
* quarkus-test-kubernetes-client provide a Kubernetes client configuration to connect
1111
* to a Kubernetes mock server and will have precedence over the configuration provided by
1212
* Dev Services for Kubernetes. DevServicesKubernetesProcessor uses this BooleanSupplier
1313
* to avoid starting a Kubernetes test container in such a case.
1414
*/
1515
class NoQuarkusTestKubernetesClient implements BooleanSupplier {
1616
static final String IO_QUARKUS_TEST_KUBERNETES_CLIENT_PACKAGE = "io.quarkus.test.kubernetes.client";
17-
static final Boolean IO_QUARKUS_TEST_KUBERNETES_CLIENT_AVAILABLE = Arrays.asList(Package.getPackages())
18-
.stream()
19-
.map(p -> p.getName()).anyMatch(p -> p.startsWith(IO_QUARKUS_TEST_KUBERNETES_CLIENT_PACKAGE));
17+
static final Boolean IO_QUARKUS_TEST_KUBERNETES_CLIENT_AVAILABLE = Arrays.stream(Package.getPackages())
18+
.map(Package::getName)
19+
.anyMatch(p -> p.startsWith(IO_QUARKUS_TEST_KUBERNETES_CLIENT_PACKAGE));
2020

2121
@Override
2222
public boolean getAsBoolean() {
2323
return !IO_QUARKUS_TEST_KUBERNETES_CLIENT_AVAILABLE;
2424
}
25-
}
25+
}

extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/internal/KubernetesDevServicesBuildTimeConfig.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public interface KubernetesDevServicesBuildTimeConfig {
1010

1111
/**
1212
* If Dev Services for Kubernetes should be used. (default to true)
13-
*
13+
* <p>
1414
* If this is true and kubernetes client is not configured then a kubernetes cluster
1515
* will be started and will be used.
1616
*/
@@ -19,15 +19,16 @@ public interface KubernetesDevServicesBuildTimeConfig {
1919

2020
/**
2121
* The kubernetes api server version to use.
22-
*
23-
* If not set, Dev Services for Kubernetes will use the latest supported version of the given flavor.
24-
* see https://github.com/dajudge/kindcontainer/blob/master/k8s-versions.json
22+
* <p>
23+
* If not set, Dev Services for Kubernetes will use the
24+
* <a href="https://github.com/dajudge/kindcontainer/blob/master/k8s-versions.json">latest supported version</a> of the
25+
* given flavor.
2526
*/
2627
Optional<String> apiVersion();
2728

2829
/**
2930
* The flavor to use (kind, k3s or api-only).
30-
*
31+
* <p>
3132
* If not set, Dev Services for Kubernetes will set it to: api-only.
3233
*/
3334
Optional<Flavor> flavor();
@@ -74,16 +75,16 @@ public interface KubernetesDevServicesBuildTimeConfig {
7475

7576
enum Flavor {
7677
/**
77-
* kind (needs priviledge docker)
78+
* kind (needs privileged docker)
7879
*/
7980
kind,
8081
/**
81-
* k3s (needs priviledge docker)
82+
* k3s (needs privileged docker)
8283
*/
8384
k3s,
8485
/**
8586
* api only
8687
*/
87-
api_only;
88+
api_only
8889
}
8990
}

extensions/kubernetes-client/spi/src/main/java/io/quarkus/kubernetes/client/spi/KubernetesDevServiceRequestBuildItem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* BuildItem managing the Kubernetes DevService Request information for the extension consuming it
77
*/
88
public final class KubernetesDevServiceRequestBuildItem extends SimpleBuildItem {
9-
private String flavor;
9+
private final String flavor;
1010

1111
public KubernetesDevServiceRequestBuildItem(String flavor) {
1212
this.flavor = flavor;

0 commit comments

Comments
 (0)