Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 1fv5

Quarkus – Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort

In my previous article, I shared with you the steps I took, to secure a local private registry in my demo environment and using it with Quarkus and K3s (a lightweight certified Kubernetes distribution).
I used the registry Docker Official Image, a Distribution implementation for storing and distributing of container images and artifacts.
[https://technology.amis.nl/software-development/java/quarkus-supersonic-subatomic-java-trying-out-quarkus-guide-quarkus-kubernetes-extension-reinvestigated-part-2-setting-up-a-local-private-registry-and-using-it-with-qua/]

Some years ago, I also wrote articles about the Quarkus Kubernetes Extension.

In this article, you can read more about the steps I took to further automate setting up my demo environment (including the shell script local-registry.sh, I mentioned in my previous article).

You can also read about some extra changes I made to the Quarkus quickstart application. I wanted to use a custom namespace instead of the default namespace that was used so far. Also I wanted to be able to call the Quarkus kubernetes-quickstart application (running in a VM) from my Windows laptop, so from outside the Kubernetes cluster. For this to work, I had to change the service type. I opted for using service type NodePort (including using my own port number). And finally, I wanted to change the number of desired pods to 3.

In a next article, you can read more about the steps I took to use a Service with service type LoadBalancer.

To further automate all the manual steps mentioned in my previous article, in the
env/scripts directory on my Windows laptop, I created the file local-registry.sh with the following content:
[https://technology.amis.nl/software-development/java/quarkus-supersonic-subatomic-java-trying-out-quarkus-guide-quarkus-kubernetes-extension-reinvestigated-part-3-using-a-local-private-registry-with-quarkus-and-k3s/]

#!/bin/bash
echo "**** Begin installing local private registry"

#docker container stop local-registry
#docker container remove local-registry

cd /mnt/mysharedfolder/
mkdir -p registry
cd registry
mkdir -p certs
mkdir -p auth

#Generate a new private key
echo "****** Generate a new private key"
cd /mnt/mysharedfolder/registry/certs
openssl genrsa 2048 > domain.key
chmod 400 domain.key

ls -latr

#Check the new private key
echo "****** Check the new private key"
cd /mnt/mysharedfolder/registry/certs
openssl rsa -in domain.key -check

#Generate a self-signed certificate for an existing private key
echo "****** Generate a self-signed certificate for an existing private key"
cd /mnt/mysharedfolder/registry/certs
openssl req -new -x509 -nodes -sha256 -days 365 -key domain.key -out domain.crt -subj "/C=NL/ST=Utrecht/L=Nieuwegein/O=AMIS Conclusion/OU=AMIS Technology Blog/CN=localhost" -addext "subjectAltName = DNS:localhost"

ls -latr

#Check the certificate
echo "****** Check the certificate"
cd /mnt/mysharedfolder/registry/certs
openssl x509 -in domain.crt -text -noout

#Create a password file with one entry for the user mylocregusername, with password mylocregpassword
echo "****** Create a password file with one entry for the user mylocregusername, with password mylocregpassword"
cd /mnt/mysharedfolder/registry/auth
docker run --rm --entrypoint htpasswd httpd:2.4 -Bbn mylocregusername mylocregpassword > htpasswd

ls -latr

echo "****** Check the password file"
cd /mnt/mysharedfolder/registry/auth
cat htpasswd

#Start the local private registry with basic authentication
echo "****** Start the local private registry with basic authentication"
cd /mnt/mysharedfolder/registry
docker run -d \
  --restart=always \
  --name local-registry \
  -v "$(pwd)"/auth:/auth \
  -e "REGISTRY_AUTH=htpasswd" \
  -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
  -v "$(pwd)"/certs:/certs \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  -p 8443:443 \
  registry:3

#List the running docker containers
echo "****** List the running docker containers"
docker container ls

echo "****** Copying the nginx:latest image from Docker Hub to my secured local private registry"
#Copying an image from Docker Hub to my local Docker Host
docker pull nginx:latest

#Create an additional tag for the existing image
docker tag nginx:latest localhost:8443/nginx:latest

#Login
#docker login --username mylocregusername --password mylocregpassword https://localhost:8443
echo "mylocregpassword" | docker login --username mylocregusername --password-stdin https://localhost:8443

#Push the image to my secured local private registry
docker push localhost:8443/nginx:latest

#Logout
docker logout https://localhost:8443

#List docker images
echo "****** List docker images"
docker image ls

echo "****** Prepare curl to connect to my secured local private registry"

#Create the certificate in PEM format
cd /mnt/mysharedfolder
openssl x509 -in registry/certs/domain.crt -out local-registry.pem -outform PEM

echo "****** List of all the docker images inside my secured local private registry"
#Get a list of all the docker images inside my secured local private registry
cd /mnt/mysharedfolder

#curl --cacert local-registry.pem --user mylocregusername https://localhost:8443/v2/_catalog
curl --cacert local-registry.pem https://localhost:8443/v2/_catalog -K- <<< "--user mylocregusername:mylocregpassword"

echo "****** List of all the tags of docker image nginx inside my secured local private registry"
#Get a list of all the tags of docker image nginx inside my secured local private registry
cd /mnt/mysharedfolder

#curl --cacert local-registry.pem --user mylocregusername https://localhost:8443/v2/nginx/tags/list
curl --cacert local-registry.pem https://localhost:8443/v2/nginx/tags/list -K- <<< "--user mylocregusername:mylocregpassword"

echo "****** Prepare K3s to connect to my secured local private registry"

#Create the K3s Registries Configuration File (registries.yaml)
cd /etc/rancher/k3s

sudo printf "mirrors:
  localhost:8443:
    endpoint:
      - "https://localhost:8443"
configs:
  localhost:8443:
    auth:
      username: mylocregusername
      password: mylocregpassword
    tls:
      insecure_skip_verify: false
      ca_file: /mnt/mysharedfolder/local-registry.pem\n" > registries.yaml

echo "******** Output from: cat registries.yaml"
cat registries.yaml

echo "******** Restart K3s because of configuration change"
#Restart K3s because of configuration change
sudo systemctl stop k3s
sudo systemctl start k3s

echo "******** Check if the configuration change is implemented"
#Check if the configuration change is implemented
sudo cat /var/lib/rancher/k3s/agent/etc/containerd/certs.d/localhost:8443/hosts.toml

echo "**** End installing local private registry"

So, this script will install a secured local private registry in my demo environment which then can be used with Quarkus and K3s (a lightweight certified Kubernetes distribution).
As I mentioned earlier, I used the registry Docker Official Image, a Distribution implementation for storing and distributing of container images and artifacts.

Next, in my Vagrantfile, I added a Vagrant Shell provisioner to upload and execute my external script within the guest machine:

      args = []
      config.vm.provision "local-registry shell script", type: "shell",
          path: "scripts/local-registry.sh",
          args: args

To further automate all the manual steps mentioned in my previous article, with regard to actually using the secured local private registry from Quarkus, in the env/scripts directory on my Windows laptop, I created the file quarkus-kubernetes-quickstart.sh with the following content:
[https://technology.amis.nl/software-development/java/quarkus-supersonic-subatomic-java-trying-out-quarkus-guide-quarkus-kubernetes-extension-reinvestigated-part-3-using-a-local-private-registry-with-quarkus-and-k3s/]

#!/bin/bash
echo "**** Begin installing Quarkus kubernetes-quickstart"

rm -rf /mnt/mysharedfolder/kubernetes-quickstart

echo "****** Create Quarkus kubernetes-quickstart"
# Create Quarkus kubernetes-quickstart
cd /mnt/mysharedfolder/
mvn io.quarkus.platform:quarkus-maven-plugin:3.21.2:create -DprojectGroupId=org.acme -DprojectArtifactId=kubernetes-quickstart -Dextensions='rest,kubernetes,jib'

#Create file application.properties
cd /mnt/mysharedfolder/kubernetes-quickstart/src/main/resources
sudo printf "quarkus.container-image.registry=localhost:8443
quarkus.container-image.username=mylocregusername
quarkus.container-image.password=mylocregpassword
quarkus.container-image.group=quarkus\n" > application.properties

echo "****** Output from: cat application.properties"
cat application.properties

echo "****** Add self-signed certificate (local-registry.pem) into file cacerts, the default Java truststore, in an entry with an alias of mylocregcert"
#Import the "Server"s self-signed certificate (local-registry.pem) into file cacerts, the default Java truststore, in an entry with an alias of mylocregcert
cd /mnt/mysharedfolder
sudo "$JAVA_HOME/bin/keytool" -noprompt -keystore "$JAVA_HOME/lib/security/cacerts" -importcert -alias mylocregcert -file local-registry.pem

#Print the contents of the truststore entry identified by alias mylocregcert
keytool -list -keystore "$JAVA_HOME/lib/security/cacerts" -alias mylocregcert


echo "****** Generate Kubernetes manifest (kubernetes.yml)"
cd /mnt/mysharedfolder/kubernetes-quickstart
mvn clean install -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true

echo "****** List of all the docker images inside my secured local private registry"
#Get a list of all the docker images inside my secured local private registry
cd /mnt/mysharedfolder

#curl --cacert local-registry.pem --user mylocregusername https://localhost:8443/v2/_catalog
curl --cacert local-registry.pem https://localhost:8443/v2/_catalog -K- <<< "--user mylocregusername:mylocregpassword"

echo "****** List of all the tags of docker image nginx inside my secured local private registry"
#Get a list of all the tags of docker image nginx inside my secured local private registry
cd /mnt/mysharedfolder

#curl --cacert local-registry.pem --user mylocregusername https://localhost:8443/v2/quarkus/kubernetes-quickstart/tags/list
curl --cacert local-registry.pem https://localhost:8443/v2/nginx/tags/list -K- <<< "--user mylocregusername:mylocregpassword"

echo "****** List of all the tags of docker image quarkus/kubernetes-quickstart inside my secured local private registry"
#Get a list of all the tags of docker image quarkus/kubernetes-quickstart inside my secured local private registry
cd /mnt/mysharedfolder

#curl --cacert local-registry.pem --user mylocregusername https://localhost:8443/v2/quarkus/kubernetes-quickstart/tags/list
curl --cacert local-registry.pem https://localhost:8443/v2/quarkus/kubernetes-quickstart/tags/list -K- <<< "--user mylocregusername:mylocregpassword"

#Apply the generated manifest kubernetes.yml to the Kubernetes cluster from the project root
cd /mnt/mysharedfolder/kubernetes-quickstart

kubectl apply -f target/kubernetes/kubernetes.yml

# Wait 30 seconds
echo "****** Waiting 30 seconds ..."
sleep 30

echo "****** List Replica Sets (in the default namespace)"
kubectl get replicasets

echo "****** List Pods (in the default namespace)"
kubectl get pods

echo "**** End installing Quarkus kubernetes-quickstart"

Next, in my Vagrantfile, I added a Vagrant Shell provisioner to upload and execute my external script within the guest machine:

      args = []
      config.vm.provision "quarkus-kubernetes-quickstart shell script", type: "shell",
          path: "scripts/quarkus-kubernetes-quickstart.sh",
          args: args

For the demo environment to start, from the directory named env on my Windows laptop, I opened a Windows Command Prompt (cmd) and typed: vagrant up. Once the VM was running, for executing later manual steps, I used vagrant ssh to connect into the running VM.

As I already did and described in my articles some years ago, I wanted to make some changes to the Quarkus quickstart application. I wanted to use a custom namespace instead of the default namespace that was used so far. Also I wanted to be able to call the Quarkus kubernetes-quickstart application (running in a VM) from my Windows laptop, so from outside the Kubernetes cluster. For this to work, I had to change the service type. And finally, I wanted to change the number of desired Pods to 3.

Of course, at first I made these changes manually, so I knew they were working, and later on I implemented these changes in the scripts, I mentioned above.

Customizing the namespace

A namespace can be added by applying the following configuration:
[https://quarkus.io/guides/deploying-to-kubernetes#namespace]

quarkus.kubernetes.namespace

Next, on my Windows laptop, in my shared folder, I navigated to kubernetes-quickstart\src\main\resources and changed the content of file application.properties to:
[in bold, I highlighted the changes]

quarkus.container-image.registry=localhost:8443
quarkus.container-image.username=mylocregusername
quarkus.container-image.password=mylocregpassword
quarkus.container-image.group=quarkus
quarkus.kubernetes.namespace=nl-amis-development

Remark about quarkus.kubernetes.namespace:

Kubernetes property Type Default
quarkus.kubernetes.namespace
The namespace the generated resources should belong to. If not value is set, then the ‘namespace’ field will not be added to the ‘metadata’ section of the generated manifests. This in turn means that when the manifests are applied to a cluster, the namespace will be resolved from the current Kubernetes context (see organize-cluster-access-kubeconfig for more details).
Environment variable: QUARKUS_KUBERNETES_NAMESPACE
string

[https://quarkus.io/guides/all-config]

In order to recreate the Kubernetes manifests, I used the following commands on the Linux Command Prompt:

cd /mnt/mysharedfolder/kubernetes-quickstart

mvn clean install

Below, you can see the content of the target/kubernetes/kubernetes.yml Kubernetes manifests, provided by the Quarkus project packaging:
[in bold, I highlighted the changes (except app.quarkus.io/build-timestamp)]

---
apiVersion: v1
kind: Service
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.24.1
    app.quarkus.io/build-timestamp: 2025-07-05 - 06:04:58 +0000
  labels:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: kubernetes-quickstart
  namespace: nl-amis-development
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 8080
  selector:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.24.1
    app.quarkus.io/build-timestamp: 2025-07-05 - 06:04:58 +0000
  labels:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: kubernetes-quickstart
  namespace: nl-amis-development
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/version: 1.0.0-SNAPSHOT
      app.kubernetes.io/name: kubernetes-quickstart
  template:
    metadata:
      annotations:
        app.quarkus.io/quarkus-version: 3.24.1
        app.quarkus.io/build-timestamp: 2025-07-05 - 06:04:58 +0000
      labels:
        app.kubernetes.io/managed-by: quarkus
        app.kubernetes.io/version: 1.0.0-SNAPSHOT
        app.kubernetes.io/name: kubernetes-quickstart
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: localhost:8443/quarkus/kubernetes-quickstart:1.0.0-SNAPSHOT
          imagePullPolicy: Always
          name: kubernetes-quickstart
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP

Remark:
The Kubernetes manifest for the Namespace itself isn’t generated. Which is to be expected because a namespace can be used by several Kubernetes manifests, generated from several Quarkus applications.

Creating the namespace

For creating the namespace, I used an existing yaml file (present in my shared folder) which I used before, with the following content:

apiVersion: v1
kind: Namespace
metadata:
  name: "nl-amis-development"
  labels:
    name: "nl-amis-development"

In order to create the namespace, I used the following commands on the Linux Command Prompt:

cd /mnt/mysharedfolder

kubectl apply -f yaml/namespace-development.yaml

With the following output:

namespace/nl-amis-development created

In order to get a list of all the namespaces , I used the following commands on the Linux Command Prompt:

cd /mnt/mysharedfolder

kubectl get namespaces

With the following output:

NAME                   STATUS   AGE
default                Active   5d12h
kube-node-lease        Active   5d12h
kube-public            Active   5d12h
kube-system            Active   5d12h
kubernetes-dashboard   Active   5d12h
nl-amis-development    Active   20s

Services in Kubernetes

Next, I had a look at the “Kubernetes” documentation, “Service” section.

The Service API, part of Kubernetes, is an abstraction to help you expose groups of Pods over a network. Each Service object defines a logical set of endpoints (usually these endpoints are Pods) along with a policy about how to make those pods accessible.

For example, consider a stateless image-processing backend which is running with 3 replicas. Those replicas are fungible—frontends do not care which backend they use. While the actual Pods that compose the backend set may change, the frontend clients should not need to be aware of that, nor should they need to keep track of the set of backends themselves.

The Service abstraction enables this decoupling.

The set of Pods targeted by a Service is usually determined by a selector that you define. To learn about other ways to define Service endpoints, see Services without selectors.

[https://kubernetes.io/docs/concepts/services-networking/service/#services-in-kubernetes]

Customizing the service type

The type of service that will be generated for the application can be set by applying the following configuration:
[https://quarkus.io/guides/all-config]

quarkus.kubernetes.service-type

For some parts of your application (for example, frontends) you may want to expose a Service onto an external IP address, one that’s accessible from outside of your cluster.

Kubernetes Service types allow you to specify what kind of Service you want.
[https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types]

The available type values and their behaviors are:

Type Behavior
ClusterIP Exposes the Service on a cluster-internal IP. Choosing this value makes the Service only reachable from within the cluster. This is the default that is used if you don’t explicitly specify a type for a Service. You can expose the Service to the public internet using an Ingress or a Gateway.
NodePort Exposes the Service on each Node’s IP at a static port (the NodePort). To make the node port available, Kubernetes sets up a cluster IP address, the same as if you had requested a Service of type: ClusterIP.
LoadBalancer Exposes the Service externally using an external load balancer. Kubernetes does not directly offer a load balancing component; you must provide one, or you can integrate your Kubernetes cluster with a cloud provider.
ExternalName Maps the Service to the contents of the externalName field (for example, to the hostname api.foo.bar.example). The mapping configures your cluster’s DNS server to return a CNAME record with that external hostname value. No proxying of any kind is set up.

[https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types]

Remark about Ingress:
If your workload speaks HTTP, you might choose to use an Ingress to control how web traffic reaches that workload. Ingress is not a Service type, but it acts as the entry point for your cluster. An Ingress lets you consolidate your routing rules into a single resource, so that you can expose multiple components of your workload, running separately in your cluster, behind a single listener.
[https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types]

Remark about Gateway:
The Gateway API for Kubernetes provides extra capabilities beyond Ingress and Service. You can add Gateway to your cluster – it is a family of extension APIs, implemented using CustomResourceDefinitions – and then use these to configure access to network services that are running in your cluster.
[https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types]

Because I wanted to expose a Service onto an external IP address, one that’s accessible from outside of my cluster, I opted for using service type NodePort (including using my own port number), as I already did before and described in one of my articles some years ago.
[https://technology.amis.nl/2020/10/03/quarkus-supersonic-subatomic-java-trying-out-quarkus-guide-quarkus-kubernetes-extension-part-2/]

Service with service type ClusterIP

Up till now, the generated Kubernetes service object was of service type ClusterIP, as you may remember.

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 2

Below, you can see the content again of the target/kubernetes/kubernetes.yml Kubernetes manifests, provided by the Quarkus project packaging:

---
apiVersion: v1
kind: Service
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.22.3
    app.quarkus.io/build-timestamp: 2025-06-11 - 15:02:34 +0000
  labels:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: kubernetes-quickstart
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 8080
  selector:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.22.3
    app.quarkus.io/build-timestamp: 2025-06-11 - 15:02:34 +0000
  labels:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: kubernetes-quickstart
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: kubernetes-quickstart
      app.kubernetes.io/version: 1.0.0-SNAPSHOT
  template:
    metadata:
      annotations:
        app.quarkus.io/quarkus-version: 3.22.3
        app.quarkus.io/build-timestamp: 2025-06-11 - 15:02:34 +0000
      labels:
        app.kubernetes.io/managed-by: quarkus
        app.kubernetes.io/name: kubernetes-quickstart
        app.kubernetes.io/version: 1.0.0-SNAPSHOT
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: localhost:8443/quarkus/kubernetes-quickstart:1.0.0-SNAPSHOT
          imagePullPolicy: Always
          name: kubernetes-quickstart
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP

Below, you see an overview of my Kubernetes cluster at this moment:

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 3

Service with service type: NodePort

If you set the type field to NodePort, the Kubernetes control plane allocates a port from a range specified by –service-node-port-range flag (default: 30000-32767). Each node proxies that port (the same port number on every Node) into your Service. Your Service reports the allocated port in its .spec.ports[*].nodePort field.

Using a NodePort gives you the freedom to set up your own load balancing solution, to configure environments that are not fully supported by Kubernetes, or even to expose one or more nodes’ IP addresses directly.

For a node port Service, Kubernetes additionally allocates a port (TCP, UDP or SCTP to match the protocol of the Service). Every node in the cluster configures itself to listen on that assigned port and to forward traffic to one of the ready endpoints associated with that Service. You’ll be able to contact the type: NodePort Service, from outside the cluster, by connecting to any node using the appropriate protocol (for example: TCP), and the appropriate port (as assigned to that Service).
[https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport]

Choosing your own port
If you want a specific port number, you can specify a value in the nodePort field. The control plane will either allocate you that port or report that the API transaction failed. This means that you need to take care of possible port collisions yourself. You also have to use a valid port number, one that’s inside the range configured for NodePort use.
[https://kubernetes.io/docs/concepts/services-networking/service/#nodeport-custom-port]

Next, on my Windows laptop, in my shared folder, I navigated to kubernetes-quickstart\src\main\resources and changed the content of file application.properties to:
[in bold, I highlighted the changes]

quarkus.container-image.registry=localhost:8443
quarkus.container-image.username=mylocregusername
quarkus.container-image.password=mylocregpassword
quarkus.container-image.group=quarkus
quarkus.kubernetes.namespace=nl-amis-development
quarkus.kubernetes.ports."ports".host-port=8180
quarkus.kubernetes.ports."ports".node-port=30010
quarkus.kubernetes.service-type=node-port

Remark about quarkus.kubernetes.ports.”ports”.host-port:

Kubernetes property Type Default
quarkus.kubernetes.ports.”ports”.host-port
The nodePort to which this port should be mapped to. This only takes affect when the serviceType is set to node-port.
Environment variable:
QUARKUS_KUBERNETES_PORTS__PORTS__NODE_PORT
int

[https://quarkus.io/guides/all-config]

Remark about quarkus.kubernetes.ports.”ports”.node-port:

Kubernetes property Type Default
quarkus.kubernetes.ports.”ports”.host-port
The nodePort to set when serviceType is set to node-port.
Environment variable: QUARKUS_KUBERNETES_NODE_PORT
int

[https://quarkus.io/guides/all-config]

Remark about quarkus.kubernetes.service-type:

Kubernetes property Type Default
quarkus.kubernetes.service-type
The type of service that will be generated for the application
Environment variable: QUARKUS_KUBERNETES_SERVICE_TYPE
cluster-ip,
node-port,
load-balancer, external-name
cluster-ip

[https://quarkus.io/guides/all-config]

In order to recreate the Kubernetes manifests, I used the following commands on the Linux Command Prompt:

cd /mnt/mysharedfolder/kubernetes-quickstart

mvn clean install

Below, you can see the content of the target/kubernetes/kubernetes.yml Kubernetes manifests, provided by the Quarkus project packaging:
[in bold, I highlighted the changes (except app.quarkus.io/build-timestamp)]

---
apiVersion: v1
kind: Service
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.24.1
    app.quarkus.io/build-timestamp: 2025-07-05 - 15:12:19 +0000
  labels:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: kubernetes-quickstart
  namespace: nl-amis-development
spec:
  ports:
    - name: ports
      nodePort: 30010
      port: 8180
      protocol: TCP
      targetPort: null
    - name: http
      port: 80
      protocol: TCP
      targetPort: 8080
  selector:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.24.1
    app.quarkus.io/build-timestamp: 2025-07-05 - 15:12:19 +0000
  labels:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: kubernetes-quickstart
  namespace: nl-amis-development
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/version: 1.0.0-SNAPSHOT
      app.kubernetes.io/name: kubernetes-quickstart
  template:
    metadata:
      annotations:
        app.quarkus.io/quarkus-version: 3.24.1
        app.quarkus.io/build-timestamp: 2025-07-05 - 15:12:19 +0000
      labels:
        app.kubernetes.io/managed-by: quarkus
        app.kubernetes.io/version: 1.0.0-SNAPSHOT
        app.kubernetes.io/name: kubernetes-quickstart
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: localhost:8443/quarkus/kubernetes-quickstart:1.0.0-SNAPSHOT
          imagePullPolicy: Always
          name: kubernetes-quickstart
          ports:
            - name: ports
              protocol: TCP
            - containerPort: 8080
              name: http
              protocol: TCP

This was not quite what I wanted, because now I got two sets of ports, one with name http and the other with name ports.

Next, on my Windows laptop, in my shared folder, I navigated to kubernetes-quickstart\src\main\resources and changed the content of file application.properties to:
[in bold, I highlighted the changes]

quarkus.container-image.registry=localhost:8443
quarkus.container-image.username=mylocregusername
quarkus.container-image.password=mylocregpassword
quarkus.container-image.group=quarkus
quarkus.kubernetes.namespace=nl-amis-development
quarkus.kubernetes.ports."ports".container-port=8080
quarkus.kubernetes.ports."ports".host-port=8180
quarkus.kubernetes.ports."ports".node-port=30010
quarkus.kubernetes.service-type=node-port

Remark about quarkus.kubernetes.ports.”ports”.container-port:

Kubernetes property Type Default
quarkus.kubernetes.ports.”ports”.container-port
The port number. Refers to the container port.
Environment variable:
QUARKUS_KUBERNETES_PORTS__PORTS__CONTAINER_PORT
int

[https://quarkus.io/guides/all-config]

In order to recreate the Kubernetes manifests, I used the following commands on the Linux Command Prompt:

cd /mnt/mysharedfolder/kubernetes-quickstart

mvn clean install

Below, you can see the content of the target/kubernetes/kubernetes.yml Kubernetes manifests, provided by the Quarkus project packaging:
[in bold, I highlighted the changes (except app.quarkus.io/build-timestamp)]

---
apiVersion: v1
kind: Service
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.24.1
    app.quarkus.io/build-timestamp: 2025-07-05 - 15:26:21 +0000
  labels:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: kubernetes-quickstart
  namespace: nl-amis-development
spec:
  ports:
    - name: ports
      nodePort: 30010
      port: 8180
      protocol: TCP
      targetPort: 8080
  selector:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.24.1
    app.quarkus.io/build-timestamp: 2025-07-05 - 15:26:21 +0000
  labels:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: kubernetes-quickstart
  namespace: nl-amis-development
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/version: 1.0.0-SNAPSHOT
      app.kubernetes.io/name: kubernetes-quickstart
  template:
    metadata:
      annotations:
        app.quarkus.io/quarkus-version: 3.24.1
        app.quarkus.io/build-timestamp: 2025-07-05 - 15:26:21 +0000
      labels:
        app.kubernetes.io/managed-by: quarkus
        app.kubernetes.io/version: 1.0.0-SNAPSHOT
        app.kubernetes.io/name: kubernetes-quickstart
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: localhost:8443/quarkus/kubernetes-quickstart:1.0.0-SNAPSHOT
          imagePullPolicy: Always
          name: kubernetes-quickstart
          ports:
            - containerPort: 8080
              name: ports
              protocol: TCP

So, this was what I wanted 😊.

Now, I wanted to change the number of replicas.

Remark about build error Can’t edit matching ports. No match found.:

Occasionally, after using the mvn clean install command, I got the following error:

WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/opt/apache-maven-3.9.10/lib/guice-5.1.0-classes.jar)
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< org.acme:kubernetes-quickstart >-------------------
[INFO] Building kubernetes-quickstart 1.0.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ kubernetes-quickstart ---
[INFO] Deleting /mnt/mysharedfolder/kubernetes-quickstart/target
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ kubernetes-quickstart ---
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO]
[INFO] --- quarkus:3.24.1:generate-code (default) @ kubernetes-quickstart ---
[INFO]
[INFO] --- compiler:3.14.0:compile (default-compile) @ kubernetes-quickstart ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug parameters release 21] to target/classes
[INFO]
[INFO] --- quarkus:3.24.1:generate-code-tests (default) @ kubernetes-quickstart ---
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ kubernetes-quickstart ---
[INFO] skip non existing resourceDirectory /mnt/mysharedfolder/kubernetes-quickstart/src/test/resources
[INFO]
[INFO] --- compiler:3.14.0:testCompile (default-testCompile) @ kubernetes-quickstart ---
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 2 source files with javac [debug parameters release 21] to target/test-classes
[INFO]
[INFO] --- surefire:3.5.3:test (default-test) @ kubernetes-quickstart ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.acme.GreetingResourceTest
2025-07-06 15:51:41,008 INFO  [io.quarkus] (main) kubernetes-quickstart 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.24.1) started in 4.222s. Listening on: http://localhost:8081
2025-07-06 15:51:41,012 INFO  [io.quarkus] (main) Profile test activated.
2025-07-06 15:51:41,012 INFO  [io.quarkus] (main) Installed features: [cdi, compose, kubernetes, rest, smallrye-context-propagation, vertx]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.493 s -- in org.acme.GreetingResourceTest
2025-07-06 15:51:42,968 WARNING [org.jun.jup.eng.des.AbstractExtensionContext] (main) Type implements CloseableResource but not AutoCloseable: io.quarkus.test.junit.QuarkusTestExtension$ExtensionState
Exception in thread "vert.x-internal-blocking-1" java.lang.IllegalAccessError: module java.base does not open java.lang to unnamed module @53a50b0a; to use the thread-local-reset capability on Java 24 or later, use this JVM option: --add-opens java.base/java.lang=ALL-UNNAMED
        at org.jboss.threads.JDKSpecific$ThreadAccess.<clinit>(JDKSpecific.java:32)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:13)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1447)
2025-07-06 15:51:43,072 INFO  [io.quarkus] (main) kubernetes-quickstart stopped in 0.084s
Exception in thread "executor-thread-1" java.lang.NoClassDefFoundError: Could not initialize class org.jboss.threads.JDKSpecific$ThreadAccess
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:13)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1447)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalAccessError: module java.base does not open java.lang to unnamed module @53a50b0a; to use the thread-local-reset capability on Java 24 or later, use this JVM option: --add-opens java.base/java.lang=ALL-UNNAMED [in thread "vert.x-internal-blocking-1"]
        at org.jboss.threads.JDKSpecific$ThreadAccess.<clinit>(JDKSpecific.java:32)
        ... 3 more
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jar:3.4.1:jar (default-jar) @ kubernetes-quickstart ---
[INFO] Building jar: /mnt/mysharedfolder/kubernetes-quickstart/target/kubernetes-quickstart-1.0.0-SNAPSHOT.jar
[INFO]
[INFO] --- quarkus:3.24.1:build (default) @ kubernetes-quickstart ---
[INFO] [io.quarkus.kubernetes.deployment.PropertyUtil] Kubernetes manifests are generated with 'The container port http' having default value '8080'. The app and manifests will get out of sync if the property 'quarkus.http.port' is changed at runtime.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  23.254 s
[INFO] Finished at: 2025-07-06T15:51:49Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal io.quarkus.platform:quarkus-maven-plugin:3.24.1:build (default) on project kubernetes-quickstart: Failed to build quarkus application: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[ERROR]         [error]: Build step io.quarkus.kubernetes.deployment.KubernetesProcessor#build threw an exception: java.lang.RuntimeException: Can't edit matching ports. No match found.
[ERROR]         at io.fabric8.kubernetes.api.model.ServiceSpecFluent.editMatchingPort(ServiceSpecFluent.java:731)
[ERROR]         at io.quarkus.kubernetes.deployment.AddNodePortDecorator.andThenVisit(AddNodePortDecorator.java:35)
[ERROR]         at io.quarkus.kubernetes.deployment.AddNodePortDecorator.andThenVisit(AddNodePortDecorator.java:15)
[ERROR]         at io.dekorate.kubernetes.decorator.NamedResourceDecorator.andThenVisit(NamedResourceDecorator.java:90)
[ERROR]         at io.dekorate.kubernetes.decorator.NamedResourceDecorator$ResourceVisitor.visit(NamedResourceDecorator.java:105)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitor.visit(Visitor.java:30)
[ERROR]         at io.fabric8.kubernetes.api.builder.VisitorWiretap.visit(VisitorWiretap.java:49)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitable.accept(Visitable.java:53)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitable.lambda$accept$1(Visitable.java:67)
[ERROR]         at java.base/java.util.Optional.ifPresent(Optional.java:178)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitable.accept(Visitable.java:59)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitable.accept(Visitable.java:39)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitable.accept(Visitable.java:35)
[ERROR]         at io.dekorate.kubernetes.decorator.NamedResourceDecorator.visit(NamedResourceDecorator.java:63)
[ERROR]         at io.dekorate.kubernetes.decorator.NamedResourceDecorator.visit(NamedResourceDecorator.java:29)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitor.visit(Visitor.java:30)
[ERROR]         at io.fabric8.kubernetes.api.builder.VisitorWiretap.visit(VisitorWiretap.java:49)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitable.accept(Visitable.java:53)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitable.lambda$accept$1(Visitable.java:67)
[ERROR]         at java.base/java.util.Optional.ifPresent(Optional.java:178)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitable.accept(Visitable.java:59)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitable.accept(Visitable.java:39)
[ERROR]         at io.fabric8.kubernetes.api.builder.Visitable.accept(Visitable.java:35)
[ERROR]         at io.dekorate.ResourceRegistry.lambda$generate$2(ResourceRegistry.java:181)
[ERROR]         at java.base/java.util.HashMap.forEach(HashMap.java:1430)
[ERROR]         at io.dekorate.ResourceRegistry.generate(ResourceRegistry.java:173)
[ERROR]         at io.dekorate.Session.generate(Session.java:293)
[ERROR]         at io.dekorate.Session.close(Session.java:256)
[ERROR]         at io.quarkus.kubernetes.deployment.KubernetesProcessor.lambda$build$5(KubernetesProcessor.java:198)
[ERROR]         at java.base/java.util.Optional.ifPresent(Optional.java:178)
[ERROR]         at io.quarkus.kubernetes.deployment.KubernetesProcessor.build(KubernetesProcessor.java:141)
[ERROR]         at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:735)
[ERROR]         at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
[ERROR]         at io.quarkus.builder.BuildContext.run(BuildContext.java:255)
[ERROR]         at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2651)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2630)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1622)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1589)
[ERROR]         at java.base/java.lang.Thread.run(Thread.java:1447)
[ERROR]         at org.jboss.threads.JBossThread.run(JBossThread.java:501)
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException 

In that case there are no Kubernetes manifest files created in the target/kubernetes/ directory.

The workaround for me, was to temporary change the port from 8080 to for example 8090 in the line quarkus.kubernetes.ports.”ports”.container-port=8080 in the file application.properties and then execute the mvn clean install command, followed by an undo of that port change and then execute the mvn clean install command again, until the build succeeded and the Kubernetes manifest files were created again.

Customizing the number of replicas

The number of desired Pods can be set by applying the following configuration:

quarkus.kubernetes.replicas

Next, on my Windows laptop, in my shared folder, I navigated to kubernetes-quickstart\src\main\resources and changed the content of file application.properties to:
[in bold, I highlighted the changes]

quarkus.container-image.registry=localhost:8443
quarkus.container-image.username=mylocregusername
quarkus.container-image.password=mylocregpassword
quarkus.container-image.group=quarkus
quarkus.kubernetes.namespace=nl-amis-development
quarkus.kubernetes.ports."ports".container-port=8080
quarkus.kubernetes.ports."ports".host-port=8180
quarkus.kubernetes.ports."ports".node-port=30010
quarkus.kubernetes.replicas=3
quarkus.kubernetes.service-type=node-port

Remark about quarkus.kubernetes.replicas:

Kubernetes property Type Default
quarkus.kubernetes.replicas
The number of desired pods
Environment variable: QUARKUS_KUBERNETES_REPLICAS
int 1

[https://quarkus.io/guides/all-config]

In order to recreate the Kubernetes manifests, I used the following commands on the Linux Command Prompt:

cd /mnt/mysharedfolder/kubernetes-quickstart

mvn clean install

Below, you can see the content of the target/kubernetes/kubernetes.yml Kubernetes manifests, provided by the Quarkus project packaging:
[in bold, I highlighted the changes (except app.quarkus.io/build-timestamp)]

---
apiVersion: v1
kind: Service
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.24.1
    app.quarkus.io/build-timestamp: 2025-07-06 - 14:37:48 +0000
  labels:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: kubernetes-quickstart
  namespace: nl-amis-development
spec:
  ports:
    - name: ports
      nodePort: 30010
      port: 8180
      protocol: TCP
      targetPort: 8080
  selector:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    app.quarkus.io/quarkus-version: 3.24.1
    app.quarkus.io/build-timestamp: 2025-07-06 - 14:37:48 +0000
  labels:
    app.kubernetes.io/name: kubernetes-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
  name: kubernetes-quickstart
  namespace: nl-amis-development
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/version: 1.0.0-SNAPSHOT
      app.kubernetes.io/name: kubernetes-quickstart
  template:
    metadata:
      annotations:
        app.quarkus.io/quarkus-version: 3.24.1
        app.quarkus.io/build-timestamp: 2025-07-06 - 14:37:48 +0000
      labels:
        app.kubernetes.io/managed-by: quarkus
        app.kubernetes.io/version: 1.0.0-SNAPSHOT
        app.kubernetes.io/name: kubernetes-quickstart
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: localhost:8443/quarkus/kubernetes-quickstart:1.0.0-SNAPSHOT
          imagePullPolicy: Always
          name: kubernetes-quickstart
          ports:
            - containerPort: 8080
              name: ports
              protocol: TCP

Next, in order to build and push a container image for my project, I used the following commands on the Linux Command Prompt:

cd /mnt/mysharedfolder/kubernetes-quickstart

mvn clean install -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true

With the following output:

vagrant@ubuntu2204:/mnt/mysharedfolder/kubernetes-quickstart$ mvn clean install -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/opt/apache-maven-3.9.10/lib/guice-5.1.0-classes.jar)
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< org.acme:kubernetes-quickstart >-------------------
[INFO] Building kubernetes-quickstart 1.0.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ kubernetes-quickstart ---
[INFO] Deleting /mnt/mysharedfolder/kubernetes-quickstart/target
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ kubernetes-quickstart ---
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO]
[INFO] --- quarkus:3.24.1:generate-code (default) @ kubernetes-quickstart ---
[INFO]
[INFO] --- compiler:3.14.0:compile (default-compile) @ kubernetes-quickstart ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug parameters release 21] to target/classes
[INFO]
[INFO] --- quarkus:3.24.1:generate-code-tests (default) @ kubernetes-quickstart ---
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ kubernetes-quickstart ---
[INFO] skip non existing resourceDirectory /mnt/mysharedfolder/kubernetes-quickstart/src/test/resources
[INFO]
[INFO] --- compiler:3.14.0:testCompile (default-testCompile) @ kubernetes-quickstart ---
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 2 source files with javac [debug parameters release 21] to target/test-classes
[INFO]
[INFO] --- surefire:3.5.3:test (default-test) @ kubernetes-quickstart ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.acme.GreetingResourceTest
2025-07-06 16:49:51,831 INFO  [io.quarkus] (main) kubernetes-quickstart 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.24.1) started in 4.880s. Listening on: http://localhost:8081
2025-07-06 16:49:51,842 INFO  [io.quarkus] (main) Profile test activated.
2025-07-06 16:49:51,843 INFO  [io.quarkus] (main) Installed features: [cdi, compose, kubernetes, rest, smallrye-context-propagation, vertx]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.814 s -- in org.acme.GreetingResourceTest
2025-07-06 16:49:54,075 WARNING [org.jun.jup.eng.des.AbstractExtensionContext] (main) Type implements CloseableResource but not AutoCloseable: io.quarkus.test.junit.QuarkusTestExtension$ExtensionState
Exception in thread "vert.x-internal-blocking-1" java.lang.IllegalAccessError: module java.base does not open java.lang to unnamed module @53a50b0a; to use the thread-local-reset capability on Java 24 or later, use this JVM option: --add-opens java.base/java.lang=ALL-UNNAMED
        at org.jboss.threads.JDKSpecific$ThreadAccess.<clinit>(JDKSpecific.java:32)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:13)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1447)
Exception in thread "executor-thread-1" java.lang.NoClassDefFoundError: Could not initialize class org.jboss.threads.JDKSpecific$ThreadAccess
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:13)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1447)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalAccessError: module java.base does not open java.lang to unnamed module @53a50b0a; to use the thread-local-reset capability on Java 24 or later, use this JVM option: --add-opens java.base/java.lang=ALL-UNNAMED [in thread "vert.x-internal-blocking-1"]
        at org.jboss.threads.JDKSpecific$ThreadAccess.<clinit>(JDKSpecific.java:32)
        ... 3 more
2025-07-06 16:49:54,180 INFO  [io.quarkus] (main) kubernetes-quickstart stopped in 0.093s
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jar:3.4.1:jar (default-jar) @ kubernetes-quickstart ---
[INFO] Building jar: /mnt/mysharedfolder/kubernetes-quickstart/target/kubernetes-quickstart-1.0.0-SNAPSHOT.jar
[INFO]
[INFO] --- quarkus:3.24.1:build (default) @ kubernetes-quickstart ---
[INFO] [io.quarkus.kubernetes.deployment.PropertyUtil] Kubernetes manifests are generated with 'The container port http' having default value '8080'. The app and manifests will get out of sync if the property 'quarkus.http.port' is changed at runtime.
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Starting (local) container image build for jar using jib.
[WARNING] [io.quarkus.container.image.jib.deployment.JibProcessor] Base image 'registry.access.redhat.com/ubi9/openjdk-21-runtime:1.21' does not use a specific image digest - build may not be reproducible
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Using base image with digest: sha256:360822c35c5741f542ab78fe123e6c4d9b68e0113a88d6e0250bb1f377b17f29
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  29.664 s
[INFO] Finished at: 2025-07-06T16:50:05Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal io.quarkus.platform:quarkus-maven-plugin:3.24.1:build (default) on project kubernetes-quickstart: Failed to build quarkus application: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[ERROR]         [error]: Build step io.quarkus.container.image.jib.deployment.JibProcessor#buildFromJar threw an exception: java.lang.RuntimeException: Unable to create container image
[ERROR]         at io.quarkus.container.image.jib.deployment.JibProcessor.containerize(JibProcessor.java:257)
[ERROR]         at io.quarkus.container.image.jib.deployment.JibProcessor.buildFromJar(JibProcessor.java:184)
[ERROR]         at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:735)
[ERROR]         at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
[ERROR]         at io.quarkus.builder.BuildContext.run(BuildContext.java:255)
[ERROR]         at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2651)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2630)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1622)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1589)
[ERROR]         at java.base/java.lang.Thread.run(Thread.java:1447)
[ERROR]         at org.jboss.threads.JBossThread.run(JBossThread.java:501)
[ERROR] Caused by: java.util.concurrent.ExecutionException: java.nio.file.AccessDeniedException: /tmp/jib-core-application-layers-cache/tmp/14449416404610522282
[ERROR]         at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:292)
[ERROR]         at com.google.common.util.concurrent.AbstractFutureState.blockingGet(AbstractFutureState.java:235)
[ERROR]         at com.google.common.util.concurrent.Platform.get(Platform.java:54)
[ERROR]         at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:253)
[ERROR]         at com.google.common.util.concurrent.FluentFuture$TrustedFuture.get(FluentFuture.java:91)
[ERROR]         at com.google.cloud.tools.jib.builder.steps.PushLayerStep.call(PushLayerStep.java:78)
[ERROR]         at com.google.cloud.tools.jib.builder.steps.PushLayerStep.call(PushLayerStep.java:33)
[ERROR]         at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.runInterruptibly(TrustedListenableFutureTask.java:128)
[ERROR]         at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:74)
[ERROR]         at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:80)
[ERROR]         at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1095)
[ERROR]         at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:619)
[ERROR]         at java.base/java.lang.Thread.run(Thread.java:1447)
[ERROR] Caused by: java.nio.file.AccessDeniedException: /tmp/jib-core-application-layers-cache/tmp/14449416404610522282
[ERROR]         at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:90)
[ERROR]         at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
[ERROR]         at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
[ERROR]         at java.base/sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:414)
[ERROR]         at java.base/java.nio.file.Files.createDirectory(Files.java:647)
[ERROR]         at java.base/java.nio.file.TempFileHelper.create(TempFileHelper.java:130)
[ERROR]         at java.base/java.nio.file.TempFileHelper.createTempDirectory(TempFileHelper.java:162)
[ERROR]         at java.base/java.nio.file.Files.createTempDirectory(Files.java:890)
[ERROR]         at com.google.cloud.tools.jib.filesystem.TempDirectoryProvider.newDirectory(TempDirectoryProvider.java:54)
[ERROR]         at com.google.cloud.tools.jib.cache.CacheStorageWriter.writeUncompressed(CacheStorageWriter.java:278)
[ERROR]         at com.google.cloud.tools.jib.cache.Cache.writeUncompressedLayer(Cache.java:145)
[ERROR]         at com.google.cloud.tools.jib.builder.steps.BuildAndCacheApplicationLayerStep.call(BuildAndCacheApplicationLayerStep.java:108)
[ERROR]         at com.google.cloud.tools.jib.builder.steps.BuildAndCacheApplicationLayerStep.call(BuildAndCacheApplicationLayerStep.java:38)
[ERROR]         ... 6 more
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

So, after changing the values in the application.properties as mentioned above and executing the maven command as mentioned above, out of the blue, I got the following error in the output:

[ERROR] Caused by: java.util.concurrent.ExecutionException: java.nio.file.AccessDeniedException: /tmp/jib-core-application-layers-cache/tmp/14449416404610522282

I searched on the Internet and I found a solution, that worked for me, setting the access rights for directory /tmp/jib-core-application-layers-cache/tmp.

I used the following commands in the Linux Command Prompt:

cd /tmp/jib-core-application-layers-cache/tmp

ls -latr

With the following output:

total 8
drwxr-xr-x 5 root root 4096 Jun 29 18:15 ..
drwxr-xr-x 2 root root 4096 Jun 29 18:15 .

Next, I used the following commands in the Linux Command Prompt:

sudo chmod ugo+w /tmp/jib-core-application-layers-cache/tmp

ls -latr

With the following output:

total 8
drwxr-xr-x 5 root root 4096 Jun 29 18:15 ..
drwxrwxrwx 2 root root 4096 Jun 29 18:15 .

Then, I used the following commands on the Linux Command Prompt:

cd /mnt/mysharedfolder/kubernetes-quickstart

mvn clean install -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true

With the following output:

WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/opt/apache-maven-3.9.10/lib/guice-5.1.0-classes.jar)
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< org.acme:kubernetes-quickstart >-------------------
[INFO] Building kubernetes-quickstart 1.0.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ kubernetes-quickstart ---
[INFO] Deleting /mnt/mysharedfolder/kubernetes-quickstart/target
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ kubernetes-quickstart ---
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO]
[INFO] --- quarkus:3.24.1:generate-code (default) @ kubernetes-quickstart ---
[INFO]
[INFO] --- compiler:3.14.0:compile (default-compile) @ kubernetes-quickstart ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug parameters release 21] to target/classes
[INFO]
[INFO] --- quarkus:3.24.1:generate-code-tests (default) @ kubernetes-quickstart ---
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ kubernetes-quickstart ---
[INFO] skip non existing resourceDirectory /mnt/mysharedfolder/kubernetes-quickstart/src/test/resources
[INFO]
[INFO] --- compiler:3.14.0:testCompile (default-testCompile) @ kubernetes-quickstart ---
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 2 source files with javac [debug parameters release 21] to target/test-classes
[INFO]
[INFO] --- surefire:3.5.3:test (default-test) @ kubernetes-quickstart ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.acme.GreetingResourceTest
2025-07-06 17:18:35,820 INFO  [io.quarkus] (main) kubernetes-quickstart 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.24.1) started in 5.817s. Listening on: http://localhost:8081
2025-07-06 17:18:35,825 INFO  [io.quarkus] (main) Profile test activated.
2025-07-06 17:18:35,825 INFO  [io.quarkus] (main) Installed features: [cdi, compose, kubernetes, rest, smallrye-context-propagation, vertx]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.233 s -- in org.acme.GreetingResourceTest
2025-07-06 17:18:38,535 WARNING [org.jun.jup.eng.des.AbstractExtensionContext] (main) Type implements CloseableResource but not AutoCloseable: io.quarkus.test.junit.QuarkusTestExtension$ExtensionState
Exception in thread "vert.x-internal-blocking-1" java.lang.IllegalAccessError: module java.base does not open java.lang to unnamed module @53a50b0a; to use the thread-local-reset capability on Java 24 or later, use this JVM option: --add-opens java.base/java.lang=ALL-UNNAMED
        at org.jboss.threads.JDKSpecific$ThreadAccess.<clinit>(JDKSpecific.java:32)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:13)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1447)
Exception in thread "executor-thread-1" java.lang.NoClassDefFoundError: Could not initialize class org.jboss.threads.JDKSpecific$ThreadAccess
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:13)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1447)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalAccessError: module java.base does not open java.lang to unnamed module @53a50b0a; to use the thread-local-reset capability on Java 24 or later, use this JVM option: --add-opens java.base/java.lang=ALL-UNNAMED [in thread "vert.x-internal-blocking-1"]
        at org.jboss.threads.JDKSpecific$ThreadAccess.<clinit>(JDKSpecific.java:32)
        ... 3 more
2025-07-06 17:18:38,613 INFO  [io.quarkus] (main) kubernetes-quickstart stopped in 0.052s
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jar:3.4.1:jar (default-jar) @ kubernetes-quickstart ---
[INFO] Building jar: /mnt/mysharedfolder/kubernetes-quickstart/target/kubernetes-quickstart-1.0.0-SNAPSHOT.jar
[INFO]
[INFO] --- quarkus:3.24.1:build (default) @ kubernetes-quickstart ---
[INFO] [io.quarkus.kubernetes.deployment.PropertyUtil] Kubernetes manifests are generated with 'The container port http' having default value '8080'. The app and manifests will get out of sync if the property 'quarkus.http.port' is changed at runtime.
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Starting (local) container image build for jar using jib.
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Using docker to run the native image builder
[WARNING] [io.quarkus.container.image.jib.deployment.JibProcessor] Base image 'registry.access.redhat.com/ubi9/openjdk-21-runtime:1.21' does not use a specific image digest - build may not be reproducible
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Using base image with digest: sha256:360822c35c5741f542ab78fe123e6c4d9b68e0113a88d6e0250bb1f377b17f29
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Container entrypoint set to [/opt/jboss/container/java/run/run-java.sh]
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Created container image localhost:8443/quarkus/kubernetes-quickstart:1.0.0-SNAPSHOT (sha256:46997a190a24ddf6de5a7e3f05ee181d53ae2a17420fe19ec5b8b00b6d857038)

[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 21353ms
[INFO]
[INFO] --- failsafe:3.5.3:integration-test (default) @ kubernetes-quickstart ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- quarkus:3.24.1:native-image-agent (default) @ kubernetes-quickstart ---
[INFO] Missing native-image-agent-base-config directory with native image agent configuration to transform
[INFO]
[INFO] --- failsafe:3.5.3:verify (default) @ kubernetes-quickstart ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- install:3.1.2:install (default-install) @ kubernetes-quickstart ---
[INFO] Installing /mnt/mysharedfolder/kubernetes-quickstart/pom.xml to /home/vagrant/.m2/repository/org/acme/kubernetes-quickstart/1.0.0-SNAPSHOT/kubernetes-quickstart-1.0.0-SNAPSHOT.pom
[INFO] Installing /mnt/mysharedfolder/kubernetes-quickstart/target/kubernetes-quickstart-1.0.0-SNAPSHOT.jar to /home/vagrant/.m2/repository/org/acme/kubernetes-quickstart/1.0.0-SNAPSHOT/kubernetes-quickstart-1.0.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  42.722 s
[INFO] Finished at: 2025-07-06T17:19:00Z
[INFO] ------------------------------------------------------------------------
vagrant@ubuntu2204:/mnt/mysharedfolder/kubernetes-quickstart$ mvn clean install -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/opt/apache-maven-3.9.10/lib/guice-5.1.0-classes.jar)
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< org.acme:kubernetes-quickstart >-------------------
[INFO] Building kubernetes-quickstart 1.0.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ kubernetes-quickstart ---
[INFO] Deleting /mnt/mysharedfolder/kubernetes-quickstart/target
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ kubernetes-quickstart ---
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO]
[INFO] --- quarkus:3.24.1:generate-code (default) @ kubernetes-quickstart ---
[INFO]
[INFO] --- compiler:3.14.0:compile (default-compile) @ kubernetes-quickstart ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug parameters release 21] to target/classes
[INFO]
[INFO] --- quarkus:3.24.1:generate-code-tests (default) @ kubernetes-quickstart ---
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ kubernetes-quickstart ---
[INFO] skip non existing resourceDirectory /mnt/mysharedfolder/kubernetes-quickstart/src/test/resources
[INFO]
[INFO] --- compiler:3.14.0:testCompile (default-testCompile) @ kubernetes-quickstart ---
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 2 source files with javac [debug parameters release 21] to target/test-classes
[INFO]
[INFO] --- surefire:3.5.3:test (default-test) @ kubernetes-quickstart ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.acme.GreetingResourceTest
2025-07-06 17:19:52,263 INFO  [io.quarkus] (main) kubernetes-quickstart 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.24.1) started in 4.934s. Listening on: http://localhost:8081
2025-07-06 17:19:52,271 INFO  [io.quarkus] (main) Profile test activated.
2025-07-06 17:19:52,271 INFO  [io.quarkus] (main) Installed features: [cdi, compose, kubernetes, rest, smallrye-context-propagation, vertx]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.978 s -- in org.acme.GreetingResourceTest
2025-07-06 17:19:54,481 WARNING [org.jun.jup.eng.des.AbstractExtensionContext] (main) Type implements CloseableResource but not AutoCloseable: io.quarkus.test.junit.QuarkusTestExtension$ExtensionState
Exception in thread "vert.x-internal-blocking-1" java.lang.IllegalAccessError: module java.base does not open java.lang to unnamed module @53a50b0a; to use the thread-local-reset capability on Java 24 or later, use this JVM option: --add-opens java.base/java.lang=ALL-UNNAMED
        at org.jboss.threads.JDKSpecific$ThreadAccess.<clinit>(JDKSpecific.java:32)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:13)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1447)
Exception in thread "executor-thread-1" java.lang.NoClassDefFoundError: Could not initialize class org.jboss.threads.JDKSpecific$ThreadAccess
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:13)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1447)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalAccessError: module java.base does not open java.lang to unnamed module @53a50b0a; to use the thread-local-reset capability on Java 24 or later, use this JVM option: --add-opens java.base/java.lang=ALL-UNNAMED [in thread "vert.x-internal-blocking-1"]
        at org.jboss.threads.JDKSpecific$ThreadAccess.<clinit>(JDKSpecific.java:32)
        ... 3 more
2025-07-06 17:19:54,531 INFO  [io.quarkus] (main) kubernetes-quickstart stopped in 0.027s
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jar:3.4.1:jar (default-jar) @ kubernetes-quickstart ---
[INFO] Building jar: /mnt/mysharedfolder/kubernetes-quickstart/target/kubernetes-quickstart-1.0.0-SNAPSHOT.jar
[INFO]
[INFO] --- quarkus:3.24.1:build (default) @ kubernetes-quickstart ---
[INFO] [io.quarkus.kubernetes.deployment.PropertyUtil] Kubernetes manifests are generated with 'The container port http' having default value '8080'. The app and manifests will get out of sync if the property 'quarkus.http.port' is changed at runtime.
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Starting (local) container image build for jar using jib.
[WARNING] [io.quarkus.container.image.jib.deployment.JibProcessor] Base image 'registry.access.redhat.com/ubi9/openjdk-21-runtime:1.21' does not use a specific image digest - build may not be reproducible
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Using base image with digest: sha256:360822c35c5741f542ab78fe123e6c4d9b68e0113a88d6e0250bb1f377b17f29
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Container entrypoint set to [/opt/jboss/container/java/run/run-java.sh]
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Pushed container image localhost:8443/quarkus/kubernetes-quickstart:1.0.0-SNAPSHOT (sha256:891d4e684e00f91fd2d338f44bd564b7ac454e1c46123bb982329a0192514c6e)

[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 11209ms
[INFO]
[INFO] --- failsafe:3.5.3:integration-test (default) @ kubernetes-quickstart ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- quarkus:3.24.1:native-image-agent (default) @ kubernetes-quickstart ---
[INFO] Missing native-image-agent-base-config directory with native image agent configuration to transform
[INFO]
[INFO] --- failsafe:3.5.3:verify (default) @ kubernetes-quickstart ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- install:3.1.2:install (default-install) @ kubernetes-quickstart ---
[INFO] Installing /mnt/mysharedfolder/kubernetes-quickstart/pom.xml to /home/vagrant/.m2/repository/org/acme/kubernetes-quickstart/1.0.0-SNAPSHOT/kubernetes-quickstart-1.0.0-SNAPSHOT.pom
[INFO] Installing /mnt/mysharedfolder/kubernetes-quickstart/target/kubernetes-quickstart-1.0.0-SNAPSHOT.jar to /home/vagrant/.m2/repository/org/acme/kubernetes-quickstart/1.0.0-SNAPSHOT/kubernetes-quickstart-1.0.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  29.114 s
[INFO] Finished at: 2025-07-06T17:20:06Z
[INFO] ------------------------------------------------------------------------

So, this time it worked.

Removing the created Kubernetes objects

So, as I mentioned in my previous article, the Quarkus generated manifest kubernetes.yml, was applied to the Kubernetes cluster and created the following Kubernetes objects (in the default namespace):

  • Service
  • Deployment
  • Replica Set
  • Pod

Because I wanted to create the Kubernetes objects again, first I had to delete the existing ones. I repeated some of the steps I already described in my previous article.
[https://technology.amis.nl/software-development/java/quarkus-supersonic-subatomic-java-trying-out-quarkus-guide-quarkus-kubernetes-extension-reinvestigated-part-3-using-a-local-private-registry-with-quarkus-and-k3s/]

In order to delete the Replica Set and all of the dependent Pods (in the default namespace), I used the following command on the Linux Command Prompt:

kubectl delete -n default replicaset $( kubectl get replicasets -n default -o=jsonpath='{range .items..metadata}{.name}{"\n"}{end}' | grep kubernetes-quickstart- | awk '{print $1}')

With the following output:

replicaset.apps “kubernetes-quickstart-fdcfb757” deleted

To delete a ReplicaSet and all of its Pods, use kubectl delete. The Garbage collector automatically deletes all of the dependent Pods by default.
[https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/#deleting-a-replicaset-and-its-pods]

In order to delete the Deployment, I used the following command on the Linux Command Prompt:

kubectl delete -n default deployment kubernetes-quickstart

With the following output:

deployment.apps "kubernetes-quickstart" deleted

In order to delete the Service, I used the following command on the Linux Command Prompt:

kubectl delete -n default service kubernetes-quickstart

With the following output:

service "kubernetes-quickstart" deleted

Recreating the Kubernetes objects in the nl-amis-development namespace, including a service with service type NodePort

Next, in order to recreate the Kubernetes manifests (in the nl-amis-development namespace), I used the following commands on the Linux Command Prompt:

cd /mnt/mysharedfolder/kubernetes-quickstart

kubectl apply -f target/kubernetes/kubernetes.yml

With the following output:

service/kubernetes-quickstart created
deployment.apps/kubernetes-quickstart created

Remark:
Be aware that I already created the nl-amis-development namespace object.

Then, I quickly checked whether the Pods were running successfully, via a series of commands on the Linux Command Prompt.

kubectl get services --all-namespaces

With the following output:

NAMESPACE              NAME                        TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
default                kubernetes                  ClusterIP      10.43.0.1       <none>        443/TCP                      6d23h
kube-system            kube-dns                    ClusterIP      10.43.0.10      <none>        53/UDP,53/TCP,9153/TCP       6d23h
kube-system            metrics-server              ClusterIP      10.43.125.144   <none>        443/TCP                      6d23h
kube-system            traefik                     LoadBalancer   10.43.61.157    10.0.2.15     80:30907/TCP,443:30294/TCP   6d23h
kubernetes-dashboard   dashboard-metrics-scraper   ClusterIP      10.43.252.155   <none>        8000/TCP                     6d23h
kubernetes-dashboard   kubernetes-dashboard        ClusterIP      10.43.220.43    <none>        443/TCP                      6d23h
nl-amis-development    kubernetes-quickstart       NodePort       10.43.236.153   <none>        8180:30010/TCP               104s
kubectl get replicasets --all-namespaces

With the following output:

NAMESPACE              NAME                                   DESIRED   CURRENT   READY   AGE
kube-system            coredns-697968c856                     1         1         1       6d23h
kube-system            local-path-provisioner-774c6665dc      1         1         1       6d23h
kube-system            metrics-server-6f4c6675d5              1         1         1       6d23h
kube-system            traefik-c98fdf6fb                      1         1         1       6d23h
kubernetes-dashboard   dashboard-metrics-scraper-749c668b7f   1         1         1       6d23h
kubernetes-dashboard   kubernetes-dashboard-76b75d676c        1         1         1       6d23h
nl-amis-development    kubernetes-quickstart-85b9dc865d       3         3         3       58s
kubectl get pods --all-namespaces

With the following output:

NAMESPACE              NAME                                         READY   STATUS      RESTARTS      AGE
kube-system            coredns-697968c856-72ml9                     1/1     Running     0             6d23h
kube-system            helm-install-traefik-crd-fvqvg               0/1     Completed   0             6d23h
kube-system            helm-install-traefik-md9j8                   0/1     Completed   1             6d23h
kube-system            local-path-provisioner-774c6665dc-h5j22      1/1     Running     0             6d23h
kube-system            metrics-server-6f4c6675d5-4h64s              1/1     Running     0             6d23h
kube-system            svclb-traefik-a86d68ac-4zxjr                 2/2     Running     0             6d23h
kube-system            traefik-c98fdf6fb-csd67                      1/1     Running     0             6d23h
kubernetes-dashboard   dashboard-metrics-scraper-749c668b7f-hlpr6   1/1     Running     0             6d23h
kubernetes-dashboard   kubernetes-dashboard-76b75d676c-ghdpr        1/1     Running     1 (48m ago)   6d23h
nl-amis-development    kubernetes-quickstart-85b9dc865d-27mdm       1/1     Running     0             79s
nl-amis-development    kubernetes-quickstart-85b9dc865d-d9b5x       1/1     Running     0             79s
nl-amis-development    kubernetes-quickstart-85b9dc865d-sl99t       1/1     Running     0             79s
kubectl get endpoints --all-namespaces

With the following output:

NAMESPACE NAME ENDPOINTS AGE
default kubernetes 10.0.2.15:6443 6d23h
kube-system kube-dns 10.42.0.3:53,10.42.0.3:53,10.42.0.3:9153 6d23h
kube-system metrics-server 10.42.0.2:10250 6d23h
kube-system traefik 10.42.0.8:8000,10.42.0.8:8443 6d23h
kubernetes-dashboard dashboard-metrics-scraper 10.42.0.10:8000 6d23h
kubernetes-dashboard kubernetes-dashboard 10.42.0.9:8443 6d23h
nl-amis-development kubernetes-quickstart 10.42.0.13:8080,10.42.0.14:8080,10.42.0.15:8080 2m6s

kubectl get nodes

With the following output:

NAME                     STATUS   ROLES                  AGE     VERSION
ubuntu2204.localdomain   Ready    control-plane,master   6d23h   v1.32.5+k3s1

In order to determine the IP of the K3s node, I used the following commands on the Linux Command Prompt, as I described in a previous article:
[https://technology.amis.nl/2020/04/30/creating-a-re-usable-vagrant-box-from-an-existing-vm-with-ubuntu-and-k3s-with-the-kubernetes-dashboard-and-adding-mysql-using-vagrant-and-oracle-virtualbox/]

nodeIP=$(kubectl get node ubuntu2204.localdomain -o yaml | grep address: | grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}")
echo "---$nodeIP---"

With the following output:

---10.0.2.15---

Below, you see an overview of my Kubernetes cluster at this moment:

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 4

Kubernetes Dashboard

Next, in order to check the generated objects in Kubernetes, in the Web Browser on my Windows laptop, I started the Kubernetes Dashboard in my demo environment, via:

http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 5

I used the token, that was visible in the output of my script, via:

kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

The Kubernetes Dashboard was opened with the default namespace selected. So, I selected the nl-amis-development namespace.

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 6

Then, I navigated to the Services:

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 7

Next, I navigated to the Deployments:

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 8

Next, I navigated to the Replica Sets:

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 9

Next, I navigated to the Pods:

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 10

Then, I opened the Logs from the Pod:

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 11

Above, you can see, the Quarkus application is listening on: http://0.0.0.0:8080

In order to get the endpoint of the Pod, I navigated to the Services | kubernetes-quickstart:

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 12

So, this confirmed to me that everything was up and running.

Below, again you see an overview of my Kubernetes cluster at this moment:

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 13

For every one of the 3 Pods I quickly checked if they worked. Below you see the check I did for the first Pod (with the endpoint, including the targetPort we saw earlier).

I used the following command on the Linux Command Prompt:

curl http://10.42.0.13:8080/hello

With the following output:

Hello from Quarkus REST

For the other two Pods, I did the same, using the host 10.42.0.14 and 10.42.0.15.

Next, in order to quickly check if the Service worked (via the Cluster IP and port we saw earlier), I used the following command on the Linux Command Prompt:

curl http://10.43.236.153:8180/hello

With the following output:

Hello from Quarkus REST

Then, in order to quickly check if the Service worked (via the Node IP and nodePort we saw earlier), I used the following command on the Linux Command Prompt:

curl http://10.0.2.15:30010/hello

With the following output:

Hello from Quarkus REST

Besides already being able to use the Kubernetes Dashboard (in a Web Browser) on my Windows laptop (via port forwarding), I also wanted to be able to use a Web Browser on my Windows laptop, for sending requests to the Kubernetes kubernetes-quickstart Service on my guest (Ubuntu).

In order to forward local port 8090 to port 30100 on the K3s node ($nodeIP), I used the following command on the Linux Command Prompt, as I described in a previous article:
[https://technology.amis.nl/2020/04/30/creating-a-re-usable-vagrant-box-from-an-existing-vm-with-ubuntu-and-k3s-with-the-kubernetes-dashboard-and-adding-mysql-using-vagrant-and-oracle-virtualbox/]

socat tcp-listen:8090,fork tcp:10.0.2.15:30010 &

With the following output:

[1] 71488

Then, in the Web Browser on my Windows laptop, I entered the URL: http://localhost:8090/hello

And I got the following result:

Quarkus - Kubernetes extension (reinvestigated, part 4), implementing a Service of service type NodePort lameriks 2025 07 14

While using a Service with service type NodePort was okay for my demo environment, I also wanted to try out using a Service with service type LoadBalancer.

By aware that when using a service type NodePort you expose one or more nodes’ IP addresses directly. So, this type of service exposure is not very secure, because external clients basically have access to worker nodes directly. NodePort is mainly recommended for demos and test environments. Do not use this service type in production.

But more about that you can read in my next article in the series of articles about Quarkus.

To further automate all the manual steps mentioned in this article, in the env/scripts directory on my Windows laptop, I changed file quarkus-kubernetes-quickstart.sh to the following content:
[in bold, I highlighted the changes]
[https://technology.amis.nl/software-development/java/quarkus-supersonic-subatomic-java-trying-out-quarkus-guide-quarkus-kubernetes-extension-reinvestigated-part-3-using-a-local-private-registry-with-quarkus-and-k3s/]

#!/bin/bash
echo "**** Begin installing Quarkus kubernetes-quickstart"

rm -rf /mnt/mysharedfolder/kubernetes-quickstart

echo "****** Create Quarkus kubernetes-quickstart"
# Create Quarkus kubernetes-quickstart
cd /mnt/mysharedfolder/
mvn io.quarkus.platform:quarkus-maven-plugin:3.21.2:create -DprojectGroupId=org.acme -DprojectArtifactId=kubernetes-quickstart -Dextensions='rest,kubernetes,jib'

#Create file application.properties
cd /mnt/mysharedfolder/kubernetes-quickstart/src/main/resources
sudo printf "quarkus.container-image.registry=localhost:8443
quarkus.container-image.username=mylocregusername
quarkus.container-image.password=mylocregpassword
quarkus.container-image.group=quarkus
quarkus.kubernetes.namespace=nl-amis-development
quarkus.kubernetes.ports."ports".container-port=8080
quarkus.kubernetes.ports."ports".host-port=8180
quarkus.kubernetes.ports."ports".node-port=30010
quarkus.kubernetes.replicas=3
quarkus.kubernetes.service-type=node-port\n" > application.properties

echo "****** Output from: cat application.properties"
cat application.properties

echo "****** Add self-signed certificate (local-registry.pem) into file cacerts, the default Java truststore, in an entry with an alias of mylocregcert"
#Import the "Server"s self-signed certificate (local-registry.pem) into file cacerts, the default Java truststore, in an entry with an alias of mylocregcert
cd /mnt/mysharedfolder
sudo "$JAVA_HOME/bin/keytool" -noprompt -keystore "$JAVA_HOME/lib/security/cacerts" -importcert -alias mylocregcert -file local-registry.pem

#Print the contents of the truststore entry identified by alias mylocregcert
keytool -list -keystore "$JAVA_HOME/lib/security/cacerts" -alias mylocregcert

echo "****** Set access rights for /tmp/jib-core-application-layers-cache/tmp"
cd /tmp/jib-core-application-layers-cache/tmp
ls -latr
sudo chmod ugo+w /tmp/jib-core-application-layers-cache/tmp
ls -latr

echo "****** Generate Kubernetes manifest (kubernetes.yml)"
cd /mnt/mysharedfolder/kubernetes-quickstart
mvn clean install -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true

echo "****** List of all the docker images inside my secured local private registry"
#Get a list of all the docker images inside my secured local private registry
cd /mnt/mysharedfolder

#curl --cacert local-registry.pem --user mylocregusername https://localhost:8443/v2/_catalog
curl --cacert local-registry.pem https://localhost:8443/v2/_catalog -K- <<< "--user mylocregusername:mylocregpassword"

echo "****** List of all the tags of docker image nginx inside my secured local private registry"
#Get a list of all the tags of docker image nginx inside my secured local private registry
cd /mnt/mysharedfolder

#curl --cacert local-registry.pem --user mylocregusername https://localhost:8443/v2/quarkus/kubernetes-quickstart/tags/list
curl --cacert local-registry.pem https://localhost:8443/v2/nginx/tags/list -K- <<< "--user mylocregusername:mylocregpassword"

echo "****** List of all the tags of docker image quarkus/kubernetes-quickstart inside my secured local private registry"
#Get a list of all the tags of docker image quarkus/kubernetes-quickstart inside my secured local private registry
cd /mnt/mysharedfolder

#curl --cacert local-registry.pem --user mylocregusername https://localhost:8443/v2/quarkus/kubernetes-quickstart/tags/list
curl --cacert local-registry.pem https://localhost:8443/v2/quarkus/kubernetes-quickstart/tags/list -K- <<< "--user mylocregusername:mylocregpassword"

#Apply the generated manifest namespace-development.yaml to create the namespace nl-amis-development
cd /mnt/mysharedfolder

kubectl apply -f yaml/namespace-development.yaml

#Apply the generated manifest kubernetes.yml to the Kubernetes cluster from the project root
cd /mnt/mysharedfolder/kubernetes-quickstart

kubectl apply -f target/kubernetes/kubernetes.yml

# Wait 30 seconds
echo "****** Waiting 30 seconds ..."
sleep 30

echo "****** List Services (in the nl-amis-development namespace)"
kubectl get services -n nl-amis-development

echo "****** List Replica Sets (in the nl-amis-development namespace)"
kubectl get replicasets -n nl-amis-development

echo "****** List Pods (in the nl-amis-development namespace)"
kubectl get pods -n nl-amis-development

echo "****** List Endpoints (in the nl-amis-development namespace)"
kubectl get endpoints -n nl-amis-development

echo "****** List Nodes"
kubectl get nodes

echo "**** End installing Quarkus kubernetes-quickstart"

I conclude this article.

In this article, you can read more about the steps I took to further automate setting up my demo environment (including the shell script local-registry.sh).

You can also read about some extra changes I made to the Quarkus quickstart application. I wanted to use a custom namespace instead of the default namespace that was used so far. Also I wanted to be able to call the Quarkus kubernetes-quickstart application (running in a VM) from my Windows laptop, so from outside the Kubernetes cluster. For this to work, I had to change the service type. I opted for using service type NodePort (including using my own port number). And finally, I wanted to change the number of desired pods to 3.

In a next article, you can read more about the steps I took to use a Service with service type LoadBalancer.

Feel free, among my other articles on this subject, to read:

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.