diff --git a/.github/actions/k8s/build-deploy-quarkus/action.yml b/.github/actions/k8s/build-deploy-quarkus/action.yml new file mode 100644 index 0000000..048d480 --- /dev/null +++ b/.github/actions/k8s/build-deploy-quarkus/action.yml @@ -0,0 +1,63 @@ +name: Build & Deploy Quarkus to k8s +description: Build & Deploy Quarkus to k8s (if running on deploy-branch) + + +inputs: + github-token: + required: true + description: Github Token + kube-config: + required: true + description: Kubernetes Config + working-directory: + default: . + description: working directory to be used + deploy-branch: + default: refs/heads/main + description: service will only be deployed for this branch + + +runs: + using: composite + steps: + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: assemble + shell: bash + working-directory: ${{ inputs.working-directory}} + run: ./gradlew assemble + env: + QUARKUS_HTTP_ROOT_PATH: / + + - name: build container + shell: bash + working-directory: ${{ inputs.working-directory}} + run: ./gradlew assemble -Dquarkus.container-image.build=true + env: + QUARKUS_HTTP_ROOT_PATH: / + + - uses: azure/k8s-set-context@v3 + with: + method: kubeconfig + kubeconfig: ${{ inputs.kube-config }} + + - name: push & deploy to k8s + shell: bash + working-directory: ${{ inputs.working-directory}} + if: ${{ github.ref == inputs.deploy-branch }} + run: | + ./gradlew assemble -Dquarkus.kubernetes.deploy=true \ + -Dquarkus.container-image.group=${{ github.repository_owner }}/${{ github.event.repository.name }} \ + -Dquarkus.container-image.registry=ghcr.io \ + -Dquarkus.container-image.additional-tags=${{ github.sha }} \ + -Dquarkus.container-image.username=${{ github.actor }} \ + -Dquarkus.container-image.password=${{ inputs.github-token }} + env: + QUARKUS_HTTP_ROOT_PATH: / \ No newline at end of file diff --git a/.github/actions/k8s/deploy-postgres/action.yml b/.github/actions/k8s/deploy-postgres/action.yml new file mode 100644 index 0000000..19a4b57 --- /dev/null +++ b/.github/actions/k8s/deploy-postgres/action.yml @@ -0,0 +1,54 @@ +name: Deploy Postgres with Anti Affinity +description: Deploy Postgres with Anti Affinity + +inputs: + release-name: + required: true + description: release name for the helm chart + anti-affinity-value: + required: true + description: value to be used for the anti-affinity rule + kube-config: + required: true + description: kubernetes config file to connect to the cluster + namespace: + default: benchmarks + description: namespace to be used to install the chart + anti-affinity-key: + default: app.kubernetes.io/name + description: key to be used for the anti-affinity role + deploy-branch: + default: refs/heads/main + description: service will only be deployed for this branch + + +runs: + using: composite + steps: + - name: deploy postgres + uses: vimeda/helm@v1.7.0 + if: ${{ github.ref == inputs.deploy-branch }} + with: + release: ${{ inputs.release-name }} + namespace: ${{ inputs.namespace }} + chart: oci://registry-1.docker.io/bitnamicharts/postgresql + values: | + global: + postgresql: + auth: + username: postgres + database: books-db + + primary: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: ${{ inputs.anti-affinity-key}} + operator: In + values: + - ${{ inputs.anti-affinity-value}} + topologyKey: "kubernetes.io/hostname" + env: + KUBECONFIG_FILE: ${{ inputs.kube-config }} \ No newline at end of file diff --git a/.github/workflows/k8s-quarkus-reactive.yml b/.github/workflows/k8s-quarkus-reactive.yml new file mode 100644 index 0000000..564ee8a --- /dev/null +++ b/.github/workflows/k8s-quarkus-reactive.yml @@ -0,0 +1,31 @@ +name: Quarkus Reactive Build & Deploy on k8s + +on: + push: + branches: + - '**' + paths: + - bookstore-quarkus-reactive/** + + +jobs: + build: + name: build & push + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: build & deploy quarkus + uses: ./.github/actions/k8s/build-deploy-quarkus + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + kube-config: ${{ secrets.KUBECONFIG }} + working-directory: ./bookstore-quarkus-reactive + + - name: deploy postgres + uses: ./.github/actions/k8s/deploy-postgres + with: + release-name: bookstore-quarkus-reactive + anti-affinity-value: bookstore-quarkus-reactive + kube-config: ${{ secrets.KUBECONFIG }} \ No newline at end of file diff --git a/.github/workflows/k8s-quarkus-sync.yml b/.github/workflows/k8s-quarkus-sync.yml new file mode 100644 index 0000000..9f629aa --- /dev/null +++ b/.github/workflows/k8s-quarkus-sync.yml @@ -0,0 +1,31 @@ +name: Quarkus Sync Build & Deploy on k8s + +on: + push: + branches: + - '**' + paths: + - bookstore-quarkus-sync/** + + +jobs: + build: + name: build & push + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: build & deploy quarkus + uses: ./.github/actions/k8s/build-deploy-quarkus + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + kube-config: ${{ secrets.KUBECONFIG }} + working-directory: ./bookstore-quarkus-sync + + - name: deploy postgres + uses: ./.github/actions/k8s/deploy-postgres + with: + release-name: bookstore-quarkus-sync + anti-affinity-value: bookstore-quarkus-sync + kube-config: ${{ secrets.KUBECONFIG }} \ No newline at end of file diff --git a/bookstore-quarkus-reactive/build.gradle.kts b/bookstore-quarkus-reactive/build.gradle.kts index 08d5171..797607e 100644 --- a/bookstore-quarkus-reactive/build.gradle.kts +++ b/bookstore-quarkus-reactive/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { implementation("io.quarkus:quarkus-smallrye-health") implementation("io.quarkus:quarkus-container-image-jib") + implementation("io.quarkus:quarkus-kubernetes") testImplementation("io.quarkus:quarkus-junit5") testImplementation("io.rest-assured:rest-assured") diff --git a/bookstore-quarkus-reactive/gradle.properties b/bookstore-quarkus-reactive/gradle.properties index a8dcd0b..0b308dc 100644 --- a/bookstore-quarkus-reactive/gradle.properties +++ b/bookstore-quarkus-reactive/gradle.properties @@ -1,10 +1,10 @@ # # Quarkus quarkusPluginId=io.quarkus -quarkusPluginVersion=3.7.1 +quarkusPluginVersion=3.7.3 quarkusPlatformGroupId=io.quarkus.platform quarkusPlatformArtifactId=quarkus-bom -quarkusPlatformVersion=3.7.1 +quarkusPlatformVersion=3.7.3 # # Kotlin kotlinVersion=1.9.22 diff --git a/bookstore-quarkus-reactive/gradlew b/bookstore-quarkus-reactive/gradlew old mode 100644 new mode 100755 diff --git a/bookstore-quarkus-reactive/src/main/resources/META-INF/resources/loaderio-61ddb5d318dfddf075a659951abc307c.txt b/bookstore-quarkus-reactive/src/main/resources/META-INF/resources/loaderio-61ddb5d318dfddf075a659951abc307c.txt new file mode 100644 index 0000000..091d848 --- /dev/null +++ b/bookstore-quarkus-reactive/src/main/resources/META-INF/resources/loaderio-61ddb5d318dfddf075a659951abc307c.txt @@ -0,0 +1 @@ +loaderio-61ddb5d318dfddf075a659951abc307c \ No newline at end of file diff --git a/bookstore-quarkus-reactive/src/main/resources/application.properties b/bookstore-quarkus-reactive/src/main/resources/application.properties index 88149a4..4a86b26 100644 --- a/bookstore-quarkus-reactive/src/main/resources/application.properties +++ b/bookstore-quarkus-reactive/src/main/resources/application.properties @@ -22,5 +22,18 @@ quarkus.datasource.reactive.reconnect-attempts=3 quarkus.flyway.migrate-at-start=false quarkus.flyway.clean-at-start=false quarkus.flyway.baseline-on-migrate=true -# Health -quarkus.health.extensions.enabled=false \ No newline at end of file +# +# Kubernetes Deployment Config +quarkus.kubernetes.resources.requests.memory=64Mi +quarkus.kubernetes.resources.requests.cpu=50m +quarkus.kubernetes.resources.limits.memory=512Mi +quarkus.kubernetes.resources.limits.cpu=1000m +quarkus.kubernetes.ingress.expose=true +quarkus.kubernetes.ingress.host=${quarkus.application.name}.benchmarks.k8s.dev.arconsis.com +quarkus.kubernetes.ingress.tls.bookstore-quarkus-reactive-tls.enabled=true +quarkus.kubernetes.ingress.tls.bookstore-quarkus-reactive-tls.hosts=${quarkus.kubernetes.ingress.host} +quarkus.kubernetes.ingress.annotations."cert-manager.io/cluster-issuer"=letsencrypt-prod +quarkus.kubernetes.ingress.annotations."kubernetes.io/tls-acme"=true +quarkus.kubernetes.env.mapping.DB_PASSWORD.from-secret=${quarkus.application.name}-postgresql +quarkus.kubernetes.env.mapping.DB_PASSWORD.with-key=postgres-password +quarkus.kubernetes.env.vars.DB_HOST=${quarkus.application.name}-postgresql diff --git a/bookstore-quarkus-sync/build.gradle.kts b/bookstore-quarkus-sync/build.gradle.kts index f3e29f7..d97c172 100644 --- a/bookstore-quarkus-sync/build.gradle.kts +++ b/bookstore-quarkus-sync/build.gradle.kts @@ -34,6 +34,7 @@ dependencies { implementation("io.quarkus:quarkus-smallrye-health") implementation("io.quarkus:quarkus-container-image-jib") + implementation("io.quarkus:quarkus-kubernetes") testImplementation("io.quarkus:quarkus-junit5") testImplementation("io.rest-assured:rest-assured") diff --git a/bookstore-quarkus-sync/gradle.properties b/bookstore-quarkus-sync/gradle.properties index a8dcd0b..0b308dc 100644 --- a/bookstore-quarkus-sync/gradle.properties +++ b/bookstore-quarkus-sync/gradle.properties @@ -1,10 +1,10 @@ # # Quarkus quarkusPluginId=io.quarkus -quarkusPluginVersion=3.7.1 +quarkusPluginVersion=3.7.3 quarkusPlatformGroupId=io.quarkus.platform quarkusPlatformArtifactId=quarkus-bom -quarkusPlatformVersion=3.7.1 +quarkusPlatformVersion=3.7.3 # # Kotlin kotlinVersion=1.9.22 diff --git a/bookstore-quarkus-sync/src/main/resources/META-INF/resources/loaderio-61ddb5d318dfddf075a659951abc307c.txt b/bookstore-quarkus-sync/src/main/resources/META-INF/resources/loaderio-61ddb5d318dfddf075a659951abc307c.txt new file mode 100644 index 0000000..091d848 --- /dev/null +++ b/bookstore-quarkus-sync/src/main/resources/META-INF/resources/loaderio-61ddb5d318dfddf075a659951abc307c.txt @@ -0,0 +1 @@ +loaderio-61ddb5d318dfddf075a659951abc307c \ No newline at end of file diff --git a/bookstore-quarkus-sync/src/main/resources/application.properties b/bookstore-quarkus-sync/src/main/resources/application.properties index a79dbcd..ee9a8ad 100644 --- a/bookstore-quarkus-sync/src/main/resources/application.properties +++ b/bookstore-quarkus-sync/src/main/resources/application.properties @@ -1,6 +1,7 @@ quarkus.http.port=3000 # As we will expose the same API for Quarkus and SpringBoot AWS LB needs a prefix to route to the correct service %prod.quarkus.http.root-path=/quarkus-sync +# # Database quarkus.datasource.db-kind=postgresql quarkus.datasource.username=${DB_USER:postgres} @@ -10,4 +11,19 @@ quarkus.datasource.jdbc.max-size=20 %dev.quarkus.hibernate-orm.log.sql=true ## Database Migrations quarkus.flyway.migrate-at-start=true -quarkus.flyway.baseline-on-migrate=true \ No newline at end of file +quarkus.flyway.baseline-on-migrate=true +# +# Kubernetes Deployment Config +quarkus.kubernetes.resources.requests.memory=64Mi +quarkus.kubernetes.resources.requests.cpu=50m +quarkus.kubernetes.resources.limits.memory=512Mi +quarkus.kubernetes.resources.limits.cpu=1000m +quarkus.kubernetes.ingress.expose=true +quarkus.kubernetes.ingress.host=${quarkus.application.name}.benchmarks.k8s.dev.arconsis.com +quarkus.kubernetes.ingress.tls.bookstore-quarkus-sync-tls.enabled=true +quarkus.kubernetes.ingress.tls.bookstore-quarkus-sync-tls.hosts=${quarkus.kubernetes.ingress.host} +quarkus.kubernetes.ingress.annotations."cert-manager.io/cluster-issuer"=letsencrypt-prod +quarkus.kubernetes.ingress.annotations."kubernetes.io/tls-acme"=true +quarkus.kubernetes.env.mapping.DB_PASSWORD.from-secret=${quarkus.application.name}-postgresql +quarkus.kubernetes.env.mapping.DB_PASSWORD.with-key=postgres-password +quarkus.kubernetes.env.vars.DB_HOST=${quarkus.application.name}-postgresql diff --git a/postman/Booksstore.postman_collection.json b/postman/Booksstore.postman_collection.json index 2cbb549..2b4919e 100644 --- a/postman/Booksstore.postman_collection.json +++ b/postman/Booksstore.postman_collection.json @@ -1,9 +1,9 @@ { "info": { - "_postman_id": "85ccf0e9-259d-4a30-bd9a-eb718f89748f", + "_postman_id": "86e58453-1d40-4f98-839b-bb1d16953aa3", "name": "Booksstore", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "13324635" + "_exporter_id": "4591907" }, "item": [ { @@ -48,11 +48,10 @@ } }, "url": { - "raw": "localhost:3000/books", + "raw": "{{host}}/books", "host": [ - "localhost" + "{{host}}" ], - "port": "3000", "path": [ "books" ] @@ -66,11 +65,10 @@ "method": "GET", "header": [], "url": { - "raw": "localhost:3000/books", + "raw": "{{host}}/books", "host": [ - "localhost" + "{{host}}" ], - "port": "3000", "path": [ "books" ] @@ -84,14 +82,13 @@ "method": "GET", "header": [], "url": { - "raw": "localhost:3000/books/57161583-685e-4b2e-904b-b1be628fedff", + "raw": "{{host}}/books/bc7ffb20-7e00-4ff8-81c1-fbbe282c745f", "host": [ - "localhost" + "{{host}}" ], - "port": "3000", "path": [ "books", - "57161583-685e-4b2e-904b-b1be628fedff" + "bc7ffb20-7e00-4ff8-81c1-fbbe282c745f" ] } }, @@ -103,14 +100,13 @@ "method": "DELETE", "header": [], "url": { - "raw": "localhost:3000/books/57161583-685e-4b2e-904b-b1be628fedff", + "raw": "{{host}}/books/bc7ffb20-7e00-4ff8-81c1-fbbe282c745f", "host": [ - "localhost" + "{{host}}" ], - "port": "3000", "path": [ "books", - "57161583-685e-4b2e-904b-b1be628fedff" + "bc7ffb20-7e00-4ff8-81c1-fbbe282c745f" ] } }, diff --git a/postman/Bookstore Quarkus Sync (k8s).postman_environment.json b/postman/Bookstore Quarkus Sync (k8s).postman_environment.json new file mode 100644 index 0000000..d707618 --- /dev/null +++ b/postman/Bookstore Quarkus Sync (k8s).postman_environment.json @@ -0,0 +1,15 @@ +{ + "id": "bd98e2c1-11e3-4568-8ad6-aafe07e404b5", + "name": "Bookstore Quarkus Sync (k8s)", + "values": [ + { + "key": "host", + "value": "https://bookstore-quarkus-sync.benchmarks.k8s.dev.arconsis.com", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2024-02-15T18:42:29.418Z", + "_postman_exported_using": "Postman/10.23.1" +} \ No newline at end of file