Kubernetes Deployment
Kubernetes Extension
You need to finish the Creating containers section before going into Kubernetes section. |
Deploying to Kubernetes with YAMLs
Deploying to Kubernetes is not done using kubectl create deployment
approach at production, but creating and applying YAML files.
For example you can express a Deployment
with the following deployment file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: quarkus-demo-deployment
spec:
replicas: 3
selector:
matchLabels:
app: quarkus-demo
template:
metadata:
labels:
app: quarkus-demo
env: dev
spec:
containers:
- name: quarkus-demo
image: quay.io/rhdevelopers/quarkus-demo:v1
imagePullPolicy: Always
ports:
- containerPort: 8080
Likewise, you can register a service:
apiVersion: v1
kind: Service
metadata:
name: the-service
spec:
selector:
app: quarkus-demo
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
The creation of these resources are cumbersome as in most of the services the content will be similar, to avoid having to repeat again and again the creation of the same files for all services, Quarkus comes with a Kubernetes extension.
Quarkus Kubernetes Extension
Let’s add the extension so Quarkus scaffolds automatcally Kubernetes deployment files when packaging the app.
Run the following command in the project directory:
./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-kubernetes"
With the extension added, run the following command to generate the Kubernetes resources:
./mvnw clean package -DskipTests
After running this command at the target/kubernetes
directory, Quarkus places kubernetes.yaml
and kubernetes.json
files to deploy the application.
One of the great things about the extension is the integration with container extension seen at Creating containers section, so image
tag is pointing out to the image created there.
To deploy the application, we have two options, the first one, applying the resource manually:
kubectl apply -f target/kubernetes/kubernetes.yml
service/quarkus-app-workshop created
deployment.apps/quarkus-app-workshop created
Inspect the deployed pods and services:
kubectl get pods
NAME READY STATUS RESTARTS AGE
quarkus-app-workshop-5b45488995-kck2c 1/1 Running 0 3m5s
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
quarkus-app-workshop ClusterIP 172.30.199.49 <none> 80/TCP 3m23s
Before showing the second way, undeploy the application:
kubectl delete all --all
The second way is at package
time using the quarkus.kubernetes.deploy
property.
When it’s set to true, then Quarkus will create the container and push it (automatically setting quarkus.container-image.push
property to true if not stated otherwise) to the repository and finally apply the generated resources.
In the terminal run the following command:
./mvnw clean package -DskipTests -Dquarkus.kubernetes.deploy=true
....
[INFO] --- quarkus-maven-plugin:2.7.5.Final:build (default) @ todo-app ---
[INFO] Checking for existing resources in: /Users/asotobu/git/kube-native-java-apps/apps/todo-app/src/main/kubernetes.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeploy] Kubernetes API Server at 'https://api.sandbox.x8i5.p1.openshiftapps.com:6443/' successfully contacted.
[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/ubi8/openjdk-11-runtime:1.11' does not use a specific image digest - build may not be reproducible
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] LogEvent [level=INFO, message=trying docker-credential-desktop for quay.io]
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeploy] Kubernetes API Server at 'https://api.sandbox.x8i5.p1.openshiftapps.com:6443/' successfully contacted.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeploy] Kubernetes API Server at 'https://api.sandbox.x8i5.p1.openshiftapps.com:6443/' successfully contacted.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeploy] Kubernetes API Server at 'https://api.sandbox.x8i5.p1.openshiftapps.com:6443/' successfully contacted.
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] LogEvent [level=LIFECYCLE, message=Using credentials from Docker config (/Users/asotobu/.docker/config.json) for quay.io/rhdevelopers/quarkus-app-workshop:1.0.0-SNAPSHOT]
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Using base image with digest: sha256:0aca47bf03430b5ee5033d67ba9b38871470af00fa7d80a38c1cc0ae34270935
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Container entrypoint set to [java, -Djava.util.logging.manager=org.jboss.logmanager.LogManager, -jar, quarkus-run.jar]
[INFO] [io.quarkus.container.image.jib.deployment.JibProcessor] Created container image quay.io/rhdevelopers/quarkus-app-workshop:1.0.0-SNAPSHOT (sha256:da549c4785e018c8830c1d61f544372abedfd5896812f6f11eff20713adac7b4)
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Deploying to kubernetes server: https://api.sandbox.x8i5.p1.openshiftapps.com:6443/ in namespace: asotobue-dev.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Applied: Service quarkus-app-workshop.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Applied: Deployment quarkus-app-workshop.
[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 11640ms
Application is packaged, containerized, pushed to container registry, and finally, deployed to configured cluster.
Inspect the deployed pods and services:
kubectl get pods
NAME READY STATUS RESTARTS AGE
quarkus-app-workshop-8547f6bbc-9gb5w 1/1 Running 0 33m
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
quarkus-app-workshop ClusterIP 172.30.199.49 <none> 80/TCP 3m23s
Now that we have shown the second way, undeploy the application:
kubectl delete all --all
Customize auto-generated Kubernetes resources
Provide additional resources via YAML fragments
Sometimes it’s desirable to either provide additional resources, or provide custom values that will be used as a base for the generation process.
Those resources can be added under src/main/kubernetes
directory.
Suppose you want to change the default exposed port in the generated service from 80
(the default one) to 8080
.
Create the src/main/kubernetes
directory with a file named kubernetes.yml
.
apiVersion: v1
kind: Service
metadata:
name: quarkus-app-workshop
spec:
ports:
- name: http
port: 8080
targetPort: 8080
selector:
app.kubernetes.io/name: quarkus-app-workshop
app.kubernetes.io/version: 1.0.0-SNAPSHOT
type: ClusterIP
Finally, regenerate the resources by executing the following command:
./mvnw clean package -DskipTests
If you inspect the target/kubernetes/kubernetes.yml
content, the service port is 8080.
Overwrite generated Kubernetes resources using configurations
You can also overwrite the auto-generated Kubernetes resources by adding different configurations within application.properties
:
quarkus.kubernetes.service-type=load-balancer(1)
quarkus.kubernetes.deploy=true(2)
quarkus.kubernetes.ingress.expose=true(3)
1 | Generate a Kubernes Service of type LoadBalancer . |
2 | Deploy to Kubernetes every time the application is packaged. |
3 | Expose via Ingress the deployed resources. |
If you inspect again the generated target/kubernetes/kubernetes.yml
, you should notice that the Service type is changed and Ingress definition is present:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
app.quarkus.io/build-timestamp: 2022-04-11 - 18:28:06 +0000
labels:
app.kubernetes.io/name: quarkus-app-workshop
app.kubernetes.io/version: 1.0.0-SNAPSHOT
name: quarkus-app-workshop
spec:
rules:
- http:
paths:
- backend:
service:
name: quarkus-app-workshop
port:
name: http
path: /
pathType: Prefix