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]
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.
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:
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:
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:
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:
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.
Then, I navigated to the Services:
Next, I navigated to the Deployments:
Next, I navigated to the Replica Sets:
Next, I navigated to the Pods:
Then, I opened the Logs from the Pod:
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:
So, this confirmed to me that everything was up and running.
Below, again you see an overview of my Kubernetes cluster at this moment:
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:
Then, in the Web Browser on my Windows laptop, I entered the URL: http://localhost:8090/hello
And I got the following result:
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:
- “Quarkus – Supersonic Subatomic Java, trying out Quarkus guide “Quarkus – Kubernetes extension” (part 1)”, September 27, 2020
In this article, you can read more about the steps I took, trying out the Quarkus code guide “Quarkus – Kubernetes extension”, and more specific the steps related to using custom labels and annotations. - “Quarkus – Supersonic Subatomic Java, trying out some Quarkus code guides (part2)”, October 3, 2020
In this article, you can read more about the steps I took, trying out the Quarkus code guide “Quarkus – Kubernetes extension”, and more specific the steps related to customizing the namespace, the service account name, the number of replicas and the type of service. - “Quarkus – Supersonic Subatomic Java, trying out Quarkus guide “Quarkus – Kubernetes extension (part 3)”, October 10, 2020
In this article, you can read more about the steps I took, trying out the Quarkus code guide “Quarkus – Kubernetes extension”, and more specific the steps related the automatic deployment of the generated resources to a target platform, in my case K3s (lightweight certified Kubernetes distribution).