Skip to content

Commit 3319ed5

Browse files
authored
Merge pull request #17 from sprinthubmobile/develop
GraalVM Native
2 parents c8efcf6 + 8849575 commit 3319ed5

File tree

11 files changed

+163
-127
lines changed

11 files changed

+163
-127
lines changed

.github/workflows/deploy.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ jobs:
1313
deploy:
1414

1515
env:
16-
# https://github.com/actions/setup-java#cache-segment-restore-timeout
17-
SEGMENT_DOWNLOAD_TIMEOUT_MINS: '4'
16+
IMAGE_NAME: ${{vars.DOCKER_CRED_HELPER}}/${{vars.IMAGE_PATH}}
1817

1918
runs-on: ubuntu-latest
2019
permissions:
@@ -45,17 +44,17 @@ jobs:
4544
cp ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} cred.json
4645
4746
- name: Build Image
48-
run: docker build -t web . --build-arg project_id=${{vars.PROJECT_ID}}
47+
run: docker build -t web -f ${{vars.DOCKER_FILE_NAME}} . --build-arg PROJECT_ID=${{vars.PROJECT_ID}}
4948

5049
- name: Configure Docker for Artifact Registry
5150
run: gcloud auth configure-docker ${{vars.DOCKER_CRED_HELPER}} -q
5251

5352
- name: Tag and push Docker Image
5453
run: |
55-
docker tag web ${{vars.DOCKER_CRED_HELPER}}/${{vars.IMAGE_PATH}} \
56-
&& docker push ${{vars.DOCKER_CRED_HELPER}}/${{vars.IMAGE_PATH}}
54+
docker tag web ${{env.IMAGE_NAME}} \
55+
&& docker push ${{env.IMAGE_NAME}}
5756
58-
- name: Update VM with new image
57+
- name: Restart VM with new image
5958
run: |
6059
gcloud compute instances update-container ${{vars.VM_NAME}} --zone=${{vars.ZONE}} \
61-
--container-image=${{vars.DOCKER_CRED_HELPER}}/${{vars.IMAGE_PATH}}
60+
--container-image=${{env.IMAGE_NAME}}

Dockerfile

Lines changed: 0 additions & 37 deletions
This file was deleted.

README.md

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,29 +37,32 @@ When running in `prod` Logs are sent to [Cloud Logging](https://cloud.google.com
3737
The Logback plugin only reports logs from the LF4J logging API, so we only use the `org.slf4j.Logger` interface for logging.
3838
When running in `dev` profile, logs are configured to write to the console.
3939

40-
4140
Use this [setup to configure Docker](https://docs.docker.com/config/containers/logging/gcplogs/) to work with Cloud Logging when moving to a new VM
4241

43-
#### Deploying custom config for Google's Ops Agent
44-
Our custom Ops Agent config can be found in the ``config.yaml`` file. Use the following command to Update the Ops Agent config when setting up a new VM
45-
```shell
46-
$ gcloud compute scp config.yaml gated-vm:/etc/google-cloud-ops-agent/config.yaml
47-
```
48-
4942
### Secrets Management 🔒
5043
We use Google Cloud Secrets Manager to manage secrets (API keys, passwords, database URLs, etc.)
5144

52-
### Deployments
45+
## Deployments
5346

5447
Deployments are currently automated via GitHub actions. The workflow file is located at ``/.github/workflows/deploy.yml``
48+
The app runs on a Google Compute Engine VM with full GCP API permissions and required scopes.
49+
50+
### Building the production docker image on a new machine
51+
1. Install Docker and Gcloud CLI
52+
2. Run ``gcloud auth application-default login`` to authenticate with Google Cloud Platform
53+
3. Run ``CP $HOME/.config/gcloud/application_default_credentials.json cred.json`` from the project root folder.
54+
4. Run ``docker build -t <IMAGE_NAME> -f Dockerfile . --build-arg PROJECT_ID=<GCP_PROJECT_ID>`` to build the docker image.\
55+
Replace the `<GCP_PROJECT_ID>` with the appropriate Google Cloud Project ID.\
56+
Replace `Dockerfile` with `native.Dockerfile` if you want to build the GraalVM native docker image.\
57+
Replace `IMAGE_NAME` with `jvm` or `native` to match the service name in the `docker-compose.yml` file if you want to run the images locally.
58+
5. Temporarily allow the production MongoDB Atlas to accept traffic from your local machine's IP address.
59+
6. Run ``docker-compose up <service-name>`` from the project root folder. Use `jvm` or `native` as the service name.
5560

56-
The app runs on a Google Compute Engine VM with full GCP API permissions and required scopes
5761

5862
### Publishing a new version to Google Artifact Registry
5963
You will need to have write access to our Google Artifact Registry on Google Cloud Platform and install docker on your machine.
6064
1. Run ``gcloud auth configure-docker us-central1-docker.pkg.dev`` to enable [Google Cloud CLI to authenticate requests to Artifact Registry](https://cloud.google.com/artifact-registry/docs/docker/store-docker-container-images#linux).
61-
2. Run the ``mvn clean package`` command to publish the new version to Google Artifact Registry. The required repository path is
62-
configured in the [Jib Maven plugin](https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin) in pom.xml file
65+
2. Run the ``docker tag web <GCP_IMAGE_NAME> && docker push <GCP_IMAGE_NAME>`` command to publish the new version to Google Artifact Registry.
6366

6467

6568
### Updating the container image with the new image version
@@ -77,13 +80,6 @@ While will not need to log into the VM to get Telementry information, you can SS
7780

7881
Use Cloud logging to inspect the logs and health of the machine.
7982

80-
### Running the production docker image on local machine
81-
1. Install and start docker daemon
82-
2. Run ``mvn clean compile jib:dockerBuild`` to build the docker image
83-
3. Temporarily allow the production Mongo Atlas to accept traffic from anywhere on the internet.
84-
4. Install Gcloud CLI and authenticate it ``gcloud auth application-default login``
85-
5. Run ``docker-compose up`` from the project root folder.
86-
8783

8884
### Tests 🧪
8985
#### Unit test
@@ -94,11 +90,12 @@ an [Embedded DB](https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo) th
9490
1. `Mockito` is used for Mocking external services
9591
2. `MockMvc` is used for the Integration test
9692

97-
While ``mvn clean test`` is good for running the tests during development, we advise you use the following command to run the `Dockerfile` to verify that the test can run in an
98-
isolated environment without any preconfiguration on your local machine.
93+
While ``mvn clean test`` is good for running the tests during development, we advise you use the following command to build the `test.Dockerfile`
94+
to verify that the test can run in an isolated environment without any preconfiguration on your local machine.
9995
```shell
100-
docker build -t java-docker-image-test --progress=plain --no-cache --target=test .
96+
docker build -t test -f test.Dockerfile .
10197
```
98+
A successful build from the above command indicates that all tests are passing on your local machine.
10299

103100
---
104101

docker-compose.yaml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1-
# Use this file to run the image locally after building the image using 'mvn compile jib:dockerBuild'
1+
# Use this file to run the image locally after building the image
22
services:
3-
cove:
4-
image: us-central1-docker.pkg.dev/gatedaccessdev/cove-repo/vm
3+
jvm:
4+
image: jvm
55
ports:
6-
- 8080:80
6+
- "8080:80"
7+
volumes:
8+
- $HOME/.config/gcloud/application_default_credentials.json:/gcp/cred.json
9+
environment:
10+
- GOOGLE_APPLICATION_CREDENTIALS=/gcp/cred.json
11+
- GCLOUD_PROJECT=gatedaccessdev
12+
native:
13+
image: native
14+
ports:
15+
- "8081:80"
716
volumes:
817
- $HOME/.config/gcloud/application_default_credentials.json:/gcp/cred.json
918
environment:

jvm.Dockerfile

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
LABEL authors="cybersokari"
2+
FROM eclipse-temurin:21 as build
3+
# GOOGLE_APPLICATION_CREDENTIALS and GCLOUD_PROJECT
4+
# environment variables are required for a successful
5+
# AOT compilation process, which starts the app
6+
# before the compilation.
7+
ARG PROJECT_ID
8+
RUN if [ -z "$PROJECT_ID" ]; then \
9+
echo "PROJECT_ID is required but not set"; \
10+
exit 1; \
11+
fi
12+
RUN echo "PROJECT_ID is set to $PROJECT_ID"
13+
ENV GCLOUD_PROJECT=$PROJECT_ID
14+
ENV GOOGLE_APPLICATION_CREDENTIALS=/gcp/cred.json
15+
16+
WORKDIR /app
17+
# Copy the Google Cloud credentials
18+
COPY cred.json $GOOGLE_APPLICATION_CREDENTIALS
19+
# Copy the source code
20+
COPY .mvn/ .mvn/
21+
COPY --chmod=0755 mvnw mvnw
22+
COPY pom.xml .
23+
COPY ./src src/
24+
# Download the dependencies and cache them
25+
RUN ./mvnw dependency:go-offline -DskipTests
26+
# Build the application
27+
RUN ./mvnw package -DskipTests
28+
29+
# Stage 2: Create the final Docker image
30+
FROM bellsoft/liberica-openjre-alpine as final
31+
# Copy the application from the build stage
32+
COPY --from=build /app/target/web-0.0.1-SNAPSHOT.jar .
33+
# Command to run the application
34+
ENTRYPOINT ["java", "-jar", "/web-0.0.1-SNAPSHOT.jar"]
35+
# Expose the port the application runs on
36+
EXPOSE 80

native.Dockerfile

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
LABEL authors="cybersokari"
2+
FROM ghcr.io/graalvm/graalvm-ce:latest as build
3+
# GOOGLE_APPLICATION_CREDENTIALS and GCLOUD_PROJECT
4+
# environment variables are required for a successful
5+
# AOT compilation process, which starts the app
6+
# before the compilation.
7+
ARG PROJECT_ID
8+
RUN if [ -z "$PROJECT_ID" ]; then \
9+
echo "PROJECT_ID is required but not set"; \
10+
exit 1; \
11+
fi
12+
RUN echo "PROJECT_ID is set to $PROJECT_ID"
13+
ENV GCLOUD_PROJECT=$PROJECT_ID
14+
ENV GOOGLE_APPLICATION_CREDENTIALS=/gcp/cred.json
15+
16+
WORKDIR /app
17+
# Copy the Google Cloud credentials
18+
COPY cred.json $GOOGLE_APPLICATION_CREDENTIALS
19+
# Copy the source code
20+
COPY .mvn/ .mvn/
21+
COPY --chmod=0755 mvnw mvnw
22+
COPY pom.xml .
23+
COPY ./src src/
24+
# Download the dependencies and cache them
25+
RUN ./mvnw dependency:go-offline -DskipTests
26+
# Build the application
27+
RUN ./mvnw package -Pnative -DskipTests
28+
29+
# Stage 2: Create the final Docker image
30+
FROM alpine:latest AS final
31+
# Set the working directory
32+
WORKDIR /app
33+
# Installs the libc6-compat package, which provides
34+
# compatibility with glibc-based binaries.
35+
RUN apk add --no-cache libc6-compat
36+
# Copy the native executable from the build stage
37+
COPY --from=build /app/target/web .
38+
# Command to run the application
39+
CMD ["./web"]
40+
# Expose the port the application runs on
41+
EXPOSE 80

pom.xml

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
<properties>
1717
<java.version>17</java.version>
1818
<kotlin.version>1.9.23</kotlin.version>
19-
<image.path>us-central1-docker.pkg.dev/gatedaccessdev/cove-repo/vm</image.path>
20-
<main.class>ng.cove.web.AppKt</main.class>
2119
</properties>
2220
<dependencyManagement>
2321
<dependencies>
@@ -65,6 +63,19 @@
6563
<artifactId>spring-boot-starter-test</artifactId>
6664
<scope>test</scope>
6765
</dependency>
66+
<dependency>
67+
<groupId>org.jetbrains.kotlin</groupId>
68+
<artifactId>kotlin-test</artifactId>
69+
<version>${kotlin.version}</version>
70+
<scope>test</scope>
71+
</dependency>
72+
<dependency>
73+
<groupId>de.flapdoodle.embed</groupId>
74+
<artifactId>de.flapdoodle.embed.mongo.spring30x</artifactId>
75+
<version>4.11.0</version>
76+
<scope>test</scope>
77+
</dependency>
78+
6879
<dependency>
6980
<groupId>org.springframework.boot</groupId>
7081
<artifactId>spring-boot-starter-validation</artifactId>
@@ -91,24 +102,11 @@
91102
<artifactId>kotlin-stdlib-jdk8</artifactId>
92103
<version>${kotlin.version}</version>
93104
</dependency>
94-
<dependency>
95-
<groupId>org.jetbrains.kotlin</groupId>
96-
<artifactId>kotlin-test</artifactId>
97-
<version>${kotlin.version}</version>
98-
<scope>test</scope>
99-
</dependency>
100105
<dependency>
101106
<groupId>org.jetbrains.kotlin</groupId>
102107
<artifactId>kotlin-reflect</artifactId>
103108
</dependency>
104109

105-
<dependency>
106-
<groupId>de.flapdoodle.embed</groupId>
107-
<artifactId>de.flapdoodle.embed.mongo.spring30x</artifactId>
108-
<version>4.11.0</version>
109-
<scope>test</scope>
110-
</dependency>
111-
112110
<!--Cache-->
113111
<dependency>
114112
<groupId>org.springframework.boot</groupId>
@@ -120,41 +118,12 @@
120118
<version>3.1.8</version>
121119
</dependency>
122120

123-
<dependency>
124-
<groupId>org.junit.platform</groupId>
125-
<artifactId>junit-platform-suite</artifactId>
126-
<version>1.11.0-M2</version>
127-
<scope>test</scope>
128-
</dependency>
129-
130121
</dependencies>
131122

132123
<build>
133124
<sourceDirectory>src/main/kotlin</sourceDirectory>
134125
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
135126
<plugins>
136-
<plugin>
137-
<groupId>org.graalvm.buildtools</groupId>
138-
<artifactId>native-maven-plugin</artifactId>
139-
<extensions>true</extensions>
140-
<configuration>
141-
<skipNativeTests>true</skipNativeTests>
142-
<buildArgs>
143-
<arg>--initialize-at-build-time=org.slf4j.helpers</arg>
144-
<!-- 3. Quick build mode -->
145-
<!-- <buildArg>-Ob</buildArg>-->
146-
</buildArgs>
147-
</configuration>
148-
<executions>
149-
<execution>
150-
<id>build-native</id>
151-
<goals>
152-
<goal>compile-no-fork</goal>
153-
</goals>
154-
<phase>package</phase>
155-
</execution>
156-
</executions>
157-
</plugin>
158127
<!-- Jacoco plugin -->
159128
<plugin>
160129
<groupId>org.jacoco</groupId>
@@ -298,5 +267,35 @@
298267
<profile>
299268
<id>test</id>
300269
</profile>
270+
<profile>
271+
<id>native</id>
272+
<build>
273+
<plugins>
274+
<!-- GraalVM -->
275+
<plugin>
276+
<groupId>org.graalvm.buildtools</groupId>
277+
<artifactId>native-maven-plugin</artifactId>
278+
<extensions>true</extensions>
279+
<configuration>
280+
<skipNativeTests>true</skipNativeTests>
281+
<buildArgs>
282+
<arg>--initialize-at-build-time=org.slf4j.helpers</arg>
283+
<!-- 3. Quick build mode -->
284+
<!-- <buildArg>-Ob</buildArg>-->
285+
</buildArgs>
286+
</configuration>
287+
<executions>
288+
<execution>
289+
<id>build-native</id>
290+
<goals>
291+
<goal>compile-no-fork</goal>
292+
</goals>
293+
<phase>package</phase>
294+
</execution>
295+
</executions>
296+
</plugin>
297+
</plugins>
298+
</build>
299+
</profile>
301300
</profiles>
302301
</project>

src/main/resources/application-prod.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
spring.mvc.async.request-timeout=20000
2-
server.tomcat.threads.max=80
2+
server.tomcat.threads.max=100
3+
server.tomcat.threads.min-spare=10
34
server.port=80
45

56
# Disable Swagger UI on production

src/main/resources/application.properties

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ server.forward-headers-strategy=framework
1313
schedule-bill-duration-secs = 43200
1414
springdoc.swagger-ui.path=/swagger-ui.html
1515

16-
springdoc.enable-spring-security=false
1716
secretmanager-project-id=gatedaccessdev
1817

1918
firebase-client-key=AIzaSyBMiQrLbnZkCYuhyebXDmVuFNEKlI2wNAk

0 commit comments

Comments
 (0)