Voraussetzungen

docker / docker desktop

maven

  • MacOS: brew install maven

  • Windows

  • Linux: maven is installed, but not maybe not the newest

Minikube

  • Minikube is also available in "docker desktop" and can be activated.

  • minikube can also installed independently of "docker desktop".

kubectl

  • Used for the communication with Minikube (and later on with the cloud).

  • Install kubectl

  • It is highly recommended to install autocompletion für kubectl.

    source <(kubectl completion zsh)  # set up autocomplete in zsh into the current shell
    echo '[[ $commands[kubectl] ]] && source <(kubectl completion zsh)' >> ~/.zshrc # add autocomplete permanently to your zsh shell
  • kubectl Quick Reference (Cheat Sheet)

1. Start minikube

We do not need minikube at the moment, but we will start to make sure that it is working.

minikube start
result
😄  minikube v1.32.0 on Darwin 14.3.1 (arm64)
✨  Automatically selected the docker driver
📌  Using Docker Desktop driver with root privileges
👍  Starting control plane node minikube in cluster minikube
🚜  Pulling base image ...
💾  Downloading Kubernetes v1.28.3 preload ...
    > preloaded-images-k8s-v18-v1...:  341.16 MiB / 341.16 MiB  100.00% 1.81 Mi
    > gcr.io/k8s-minikube/kicbase...:  410.57 MiB / 410.58 MiB  100.00% 1.36 Mi
🔥  Creating docker container (CPUs=2, Memory=7793MB) ...
🐳  Preparing Kubernetes v1.28.3 on Docker 24.0.7 ...
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔗  Configuring bridge CNI (Container Networking Interface) ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
  • Falls die Meldung erscheint, dass der Cluster veraltet ist, dann minikube stop und minikube delete. Beim anschließenden minikube start wird ein Cluster mit aktueller kubernetes-Software erstellt.

  • Check, in the "🌟 Enabled addons:"-section, that metrics-server and dashboard are installed.

    • When missing:

      minikube addons enable metrics-server
      minikube addons enable dashboard
check the successfull installation with
minikube addons list |grep enabled
result
| dashboard                   | minikube | enabled ✅   | Kubernetes                     |
| default-storageclass        | minikube | enabled ✅   | Kubernetes                     |
| metrics-server              | minikube | enabled ✅   | Kubernetes                     |
| storage-provisioner         | minikube | enabled ✅   | minikube                       |

1.1. Minikube configuration

  • For accessing minikube and later on k8s, we need kubectl.

kubectl
  • check the correct configuration

 kubectl config view
result
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /Users/stuetz/.minikube/ca.crt
    extensions:
    - extension:
        last-update: Sun, 17 Mar 2024 12:10:05 CET
        provider: minikube.sigs.k8s.io
        version: v1.32.0
      name: cluster_info
    server: https://127.0.0.1:59820
  name: minikube
contexts:
- context:
    cluster: minikube
    extensions:
    - extension:
        last-update: Sun, 17 Mar 2024 12:10:05 CET
        provider: minikube.sigs.k8s.io
        version: v1.32.0
      name: context_info
    namespace: default
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: /Users/stuetz/.minikube/profiles/minikube/client.crt
    client-key: /Users/stuetz/.minikube/profiles/minikube/client.key
 kubectl config get-contexts
result
CURRENT   NAME       CLUSTER    AUTHINFO   NAMESPACE
*         minikube   minikube   minikube   default

2. Overview

deployment to minikube
  1. First we create a simple REST-endpoint with quarkus.

  2. We create an uber-jar.

  3. We build a docker image with the jar-filee.

  4. We push the docker image to an image registry (ghcr.io).

  5. We deploy the docker image to minikube.

3. Create the quarkus Project

mvn io.quarkus.platform:quarkus-maven-plugin:3.8.2:create \
    -DprojectGroupId=at.htl.minikube \
    -DprojectArtifactId=minikube-demo \
    -Dextensions='resteasy-reactive, smallrye-health'

or start the script create-project.sh

result
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] --- quarkus:3.7.3:create (default-cli) @ standalone-pom ---
[INFO] Looking for the newly published extensions in registry.quarkus.io
[INFO] -----------
[INFO] selected extensions:
- io.quarkus:quarkus-smallrye-health
- io.quarkus:quarkus-resteasy-reactive

[INFO]
applying codestarts...
[INFO] 📚 java
🔨 maven
📦 quarkus
📝 config-properties
🔧 tooling-dockerfiles
🔧 tooling-maven-wrapper
🚀 resteasy-reactive-codestart
🚀 smallrye-health-codestart
[INFO]
-----------
[SUCCESS] ✅  quarkus project has been successfully generated in:
--> /Users/stuetz/work/_delete/minikube-demo
-----------
[INFO]
[INFO] ========================================================================================
[INFO] Your new application has been created in /Users/stuetz/work/_delete/minikube-demo
[INFO] Navigate into this directory and launch your application with mvn quarkus:dev
[INFO] Your application will be accessible on http://localhost:8080
[INFO] ========================================================================================
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.232 s
[INFO] Finished at: 2024-02-19T08:12:54+01:00
[INFO] ------------------------------------------------------------------------

or create a project on quarkus.io - START CODING.

On quarkus.io you can also create a github-repo automatically.
quarkus io

4. Run the quarkus Project

cd minikube-demo
./mvnw clean quarkus:dev

5. Request the REST-Endpoints

  • Create a REST-Client

    • New folder in project-Root: http-requests

    • create a new file in this folder: requests.http

http request
  • you can also use cURL:

curl -i http://localhost:8080/hello (1)
1 -i shows the header of the response.
result
HTTP/1.1 200 OK
content-length: 28
Content-Type: text/plain;charset=UTF-8

Hello from RESTEasy Reactive%

6. Create a .jar File (uber-jar)

6.1. What is a uber-jar?

uber jar

6.2. How to create an uber-jar?

Precondition - add this entry to the application.properties
quarkus.package.type=uber-jar
./mvnw clean package
  • check, if the runner-jar is created

runner jar in target

7. Create docker Image

  • Therefore, we need a Dockerfile.

  • There are already Dockerfiles in src/main/docker - these are not needed and can be deleted

  • Create a new Dockerfile in src/main/docker

result
tree
...
├── src
│   ├── main
│   │   ├── docker
│   │   │   └── Dockerfile
...
Dockerfile
FROM eclipse-temurin:17-jre

RUN mkdir -p /opt/application
COPY *-runner.jar /opt/application/backend.jar
WORKDIR /opt/application
CMD [ "java", "-jar", "backend.jar" ]
docker build command 2
  • The following steps should be automated, but for now we do it manually:

cp src/main/docker/Dockerfile target
docker build --tag ghcr.io/htl-leonding/backend:latest ./target
docker image ls
result
REPOSITORY                       TAG           IMAGE ID       CREATED         SIZE
...
gghcr.io/htl-leonding/backend    latest        ae27690f900d   53 seconds ago   263MB
...

8. Docker image push to Docker Registry

docker login ghcr.io
You need a personal token to authenticate (click for instructions)
  • github - profile picture - Settings - Developer Settings - Personal access tokens - Tokens (classic)

gh token 1
gh token 2

Troubleshooting:

  • When your gh-user-name contains uppercase letters, change the name to lowercase.

  • When it still, does not work, then delete ~/.docker/config.json and try it again.

Push Container to docker registry
docker push ghcr.io/htl-leonding/backend:latest
result
The push refers to repository [ghcr.io/htl-leonding/backend]
5f70bf18a086: Layer already exists
2359f2e5d796: Pushed
08b2bdc5762e: Layer already exists
6e0f58883206: Layer already exists
eed4bd617b87: Layer already exists
65bb8dcc703b: Layer already exists
63aa4237e067: Layer already exists
98d1994bf6c1: Layer already exists
latest: digest: sha256:50c58e0426ad4b4335c791d7f60efcad24cc9c5554d5e7f35f0438186af508ca size: 1992
Make package public (click for instructions)
gh packages
gh packages 2
gh packages 3
gh packages 4

9. Configure kubernetes Deployment

check, if you are still in project root, then:
mkdir k8s
touch k8s/appsrv.yaml
k8s/appsrv.yaml
# Quarkus Application Server
apiVersion: apps/v1
kind: Deployment
metadata:
  name: appsrv

spec:
  replicas: 1
  selector:
    matchLabels:
      app: appsrv
  template:
    metadata:
      labels:
        app: appsrv
    spec:
      containers:
        - name: appsrv
          image: ghcr.io/htl-leonding/backend:latest (1)
          # remove this when stable. Currently we do not take care of version numbers
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
          startupProbe:
            httpGet:
              path: /q/health
              port: 8080
            timeoutSeconds: 5
            initialDelaySeconds: 15
          readinessProbe:
            tcpSocket:
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /q/health
              port: 8080
            timeoutSeconds: 5
            initialDelaySeconds: 60
            periodSeconds: 120
---
apiVersion: v1
kind: Service
metadata:
  name: appsrv

spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: appsrv
1 Check, that your image name is correct
You could also generate this file with kubectl
create deployment in minikube-instance
kubectl create deployment appsrv --image=ghcr.io/htl-leonding/backend:latest --port=8080
result
deployment.apps/appsrv created
write to file
kubectl get deployments/appsrv -o yaml > appsrv.yaml
create service in minikube-instance
kubectl expose deployments/appsrv --port=8080
exposing the port 8080
kubectl expose deployments/appsrv-depl --port=8080

10. Deploy to minikube the first time

kubectl apply -f k8s/appsrv.yaml
result
deployment.apps/appsrv created
service/appsrv created

10.1. Check the Success

minikube dashboard
result
🤔  Verifying dashboard health ...
🚀  Launching proxy ...
🤔  Verifying proxy health ...
🎉  Opening http://127.0.0.1:53209/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...
  • The following site should be opened in your browser

    • if not just use minikube --url and copy the given url into your browser

dashboard 01
  • We notice there are problems

10.2. Fix problems

dashboard 02
dashboard 03
dashboard 04
  • We have problems with the jdk-version, because …​

    • The pom uses jdk-21

      pom jdk21
    • The Docker image uses jdk-17

      dockerfile
  • We decide to use jdk-17 and fix the pom.xml.

11. Re-Deploy to minikube

build and push the image
./mvnw clean package
cp src/main/docker/Dockerfile target
docker build --tag ghcr.io/htl-leonding/backend:latest ./target
docker push ghcr.io/htl-leonding/backend:latest
Redeploy the app
kubectl rollout restart deployment appsrv
  • Now you see the new pod is already running and the old (broken) pod is still alive.

dashboard 05
  • The broken pods are now history

dashboard 06

12. Port Forward from minikube

Port forwarding
kubectl port-forward appsrv-xxxxxx-xxxxx 8080:8080
Use kubectl-autocomplete for the appsrv
result
❯ kubectl port-forward appsrv-7964857d64-2bhcp 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

13. Access the App

curl -i http://localhost:8080/hello
result
HTTP/1.1 200 OK
content-length: 28
Content-Type: text/plain;charset=UTF-8

Hello from RESTEasy Reactive%

14. Troubleshooting

open an ssh-shell in minikube
minikube ssh
 __   ___     _   ___      __     _      _
 \ \ / (_)___| | | __|_ _ / _|___| |__ _| |
  \ V /| / -_) | | _|| '_|  _/ _ \ / _` |_|
   \_/ |_\___|_| |___|_| |_| \___/_\__, (_)
                                   |___/