{{announcement.body}}
{{announcement.title}}

Openshift and AWS Lambda Deployment With Quarkus

DZone 's Guide to

Openshift and AWS Lambda Deployment With Quarkus

Nowadays Quarkus is known as Supersonic Subatomic Java. It provides a lot of features to facilitate build and deployment.

· Microservices Zone ·
Free Resource

Quarkus

Nowadays Quarkus is known as Supersonic Subatomic Java. It provides a lot of features to facilitate build and deployment. To did my best by creating a small blog application with quarkus with installed features: rest-client, security, spring-data-jpa, smallrye-health and openapi, Kubernetes, and AWS deployment to tried it real.

Prerequisites

  • JDK 11 for running app
  • Gradle 6+ — for packaging
  • Docker
  • OpenShift CLI — for deploying on OpenShift
  • AWS CLI, AWS SAM CLI — for deploying AWS Lambda

Docker

Quarkus provides extensions for building (and pushing) container images. Currently, it supports Jib, S2I, Docker.

To working with Docker containerization add Gradle dependency:

implementation 'io.quarkus:quarkus-container-image-docker'

Configure the docker image and remote registry in  application.properties :

Dockerfile
 




xxxxxxxxxx
1


 
1
quarkus.container-image.name=blog-api
2
quarkus.container-image.tag=latest
3
quarkus.container-image.registry=docker.io
4
quarkus.container-image.username=<USERNAME>
5
quarkus.container-image.password=<PASSWORD>
6
quarkus.container-image.push=true



Or override properties on Gradle command:

Dockerfile
 




xxxxxxxxxx
1


 
1
./gradlew quarkusBuild 
2
           -Dquarkus.container-image.username=<USERNAME> \
3
           -Dquarkus.container-image.password=<PASSWORD> \
4
           -Dquarkus.container-image.push=true



As it’s possible to create a multistage Dockerfile to avoid packaging:

Dockerfile
 




xxxxxxxxxx
1
48


 
1
####
2
# This Dockerfile.multistage is used in order to build a container that runs the Quarkus application in JVM mode
3
# docker build -t quarkus-quickstart:jvm -f src/main/docker/Dockerfile.multistage .
4
# docker run -i --rm -p 8080:8080 quarkus-quickstart:jvm
5
###
6
 
           
7
# Build jar with gradle
8
FROM gradle:jdk11 AS build_image
9
 
           
10
ENV APP_HOME=/root/dev/myapp/
11
USER root
12
RUN mkdir -p $APP_HOME/src/main/java
13
WORKDIR $APP_HOME
14
COPY build.gradle gradlew gradlew.bat $APP_HOME
15
COPY gradle $APP_HOME/gradle
16
COPY . .
17
RUN ./gradlew -PawsLambdaEnabled=false quarkusBuild
18
 
           
19
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
20
 
           
21
ARG JAVA_PACKAGE=java-11-openjdk-headless
22
ARG RUN_JAVA_VERSION=1.3.5
23
 
           
24
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
25
 
           
26
# Install java and the run-java script
27
# Also set up permissions for user `1001`
28
RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
29
    && microdnf update \
30
    && microdnf clean all \
31
    && mkdir /deployments \
32
    && chown 1001 /deployments \
33
    && chmod "g+rwX" /deployments \
34
    && chown 1001:root /deployments \
35
    && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
36
    && chown 1001 /deployments/run-java.sh \
37
    && chmod 540 /deployments/run-java.sh \
38
    && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security
39
 
           
40
# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
41
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
42
COPY --from=build_image /root/dev/myapp/build/lib/* /deployments/lib/
43
COPY --from=build_image /root/dev/myapp/build/*-runner.jar /deployments/app.jar
44
 
           
45
EXPOSE 8090
46
USER 1001
47
 
           
48
ENTRYPOINT [ "/deployments/run-java.sh" ]



OpenShift Deployment

To deploy on Openshift without Quarkus possible to define template.yaml:

YAML
 




xxxxxxxxxx
1
105


 
1
apiVersion: v1
2
kind: Template
3
metadata:
4
  name: my-template
5
objects:
6
- kind: DeploymentConfig
7
  apiVersion: v1
8
  metadata:
9
      labels:
10
        ${TAG}: ${SELECTOR_APP_NAME}
11
      name: ${APP_NAME}
12
      namespace: ${NAMESPACE_NAME}
13
  spec:
14
      replicas: 1
15
      revisionHistoryLimit: 10
16
      selector:
17
        app: ${APP_NAME}
18
        deploymentconfig: ${APP_NAME}
19
      strategy:
20
        activeDeadlineSeconds: 21600
21
        resources: {}
22
        rollingParams:
23
          intervalSeconds: 1
24
          maxSurge: 25%
25
          maxUnavailable: 25%
26
          timeoutSeconds: 600
27
          updatePeriodSeconds: 1
28
        type: Rolling
29
      template:
30
        metadata:
31
          annotations:
32
            openshift.io/generated-by: OpenShiftNewApp
33
          creationTimestamp: null
34
          labels:
35
            app: ${APP_NAME}
36
            deploymentconfig: ${APP_NAME}
37
        spec:
38
          containers:
39
            - env:
40
              name: ${APP_NAME}
41
              ports:
42
                - containerPort: 8090
43
                  protocol: TCP
44
              resources: {}
45
          dnsPolicy: ClusterFirst
46
          restartPolicy: Always
47
          schedulerName: default-scheduler
48
          securityContext: {}
49
          terminationGracePeriodSeconds: 30
50
      test: false
51
      triggers:
52
        - type: ConfigChange
53
        - imageChangeParams:
54
            automatic: true
55
            containerNames:
56
              - ${APP_NAME}
57
            from:
58
              kind: ImageStreamTag
59
              name: 'blog-api:latest'
60
              namespace: ${NAMESPACE_NAME}
61
          type: ImageChange
62
- kind: Service
63
  apiVersion: v1
64
  metadata:
65
    labels:
66
        ${TAG}: ${SELECTOR_APP_NAME}
67
    name: ${APP_NAME}
68
    namespace: ${NAMESPACE_NAME}
69
  spec:
70
    ports:
71
        - name: 80-tcp
72
          port: 80
73
          protocol: TCP
74
          targetPort: 8090
75
    selector:
76
        app: ${APP_NAME}
77
        deploymentconfig: ${APP_NAME}
78
  sessionAffinity: None
79
  type: ClusterIP
80
  status:
81
    loadBalancer: {}
82
- kind: Route
83
  apiVersion: v1
84
  metadata:
85
    labels:
86
        ${TAG}: ${SELECTOR_APP_NAME}
87
    name: ${APP_NAME}
88
    namespace: ${NAMESPACE_NAME}
89
  spec:
90
    host: ${HOST_NAME}
91
    port:
92
        targetPort: 80-tcp
93
    to:
94
        kind: Service
95
        name: ${APP_NAME}
96
        weight: 100
97
    wildcardPolicy: None
98
parameters:
99
- name: NAMESPACE_NAME
100
- name: SELECTOR_APP_NAME
101
- name: APP_NAME
102
  value: quarkus-blog-api
103
- name: HOST_NAME
104
- name: TAG
105
  value: app



And processed:

Dockerfile
 




xxxxxxxxxx
1


 
1
oc tag elvaliev/blog-api:latest
2
 
           
3
oc process NAMESPACE_NAME=<OPENSHIFT-PROJECT> \
4
           SELECTOR_APP_NAME=<SELECTOR> \
5
           HOST_NAME=<APPLICATION_HOST> \
6
           -f template.yaml | oc apply -f-



By using docker containerization it’s also possible to deploy an application using image-stream from the docker registry.

Dockerfile
 




xxxxxxxxxx
1


 
1
oc new-app elvaliev/blog-api:latest
2
 
           
3
oc expose svc/blog-api



But, Quarkus offers the ability to automatically generate Kubernetes resources. It currently supports generating resources for Kubernetes, OpenShift, and Knative.

Gradle dependency:

implementation 'io.quarkus:quarkus-kubernetes'

To enable the generation of necessary templates you need to include the target in  application.properties:

quarkus.kubernetes.deployment-target=kubernetes,openshift

Optionally you could set up the custom configuration for your template:

Dockerfile
 




xxxxxxxxxx
1


 
1
quarkus.kubernetes.annotations.app=blog
2
quarkus.kubernetes.labels.app=blog
3
 
           
4
# To create route for your application
5
quarkus.openshift.expose=true



After packaging quarkus generate target templates:

kubernetes

Deploy application via command:

oc create -f build/kubernetes/openshift.yml

Also, it’s possible to deploy — using S2I.
Dockerfile
 




xxxxxxxxxx
1


 
1
oc new-app quay.io/quarkus/ubi-quarkus-native-s2i:19.3.1-java11~<GIT REPOSITORY> 
2
                                         --context-dir=. --name=quarkus-blog-api
3
              
4
oc expose svc/quarkus-blog-a



AWS Deployment

Note: use only the last version of quarkus — 1.4.1.

Dependency for Gradle:

implementation 'io.quarkus:quarkus-amazon-lambda-http'

After packaging quarkus generate sam templates for AWS:

kubernetes

For deploying an application as an AWS Lambda use template from the build. For native build use template build/sam.native.yaml.

I followed quarkus-documentation:

Dockerfile
 




xxxxxxxxxx
1


 
1
sam local start-api --template build/sam.jvm.yaml
2
 
           
3
sam package --template-file build/sam.jvm.yaml --output-template-file packaged.yaml --s3-bucket <S3_BUCKET>
4
 
           
5
sam deploy --template-file packaged.yaml --capabilities CAPABILITY_IAM --stack-name <YOUR_STACK_NAME>



Note: To avoiding timeout error (502 — BAD GATEWAY) — increase  Timeout  in  build/sam.jvm.yaml

Note: For using Docker containerization you need to exclude quarkus-amazon-lambda-http dependency on jar packaging (packaging with the condition properties awsLambdaEnabled=false from   gradle.properties  ):

Dockerfile
 




xxxxxxxxxx
1


 
1
if (project.property(“awsLambdaEnabled”) != “true”) { 
2
   configurations { 
3
       runtime.exclude group: ‘io.quarkus’, 
4
                       module: ‘quarkus-amazon-lambda-http’ 
5
    }
6
}



Github: https://github.com/ElinaValieva/quarkus-quickstarts

Topics:
aws lambda ,deployment ,docker ,gradle ,java ,openshift ,openshift container ,quarkus ,quarkus image ,quarkus tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}