Skip to content

Commit 8849575

Browse files
authored
Merge pull request #16 from sprinthubmobile/feat/gvm
JVM to GraaVM
2 parents 5586408 + b056076 commit 8849575

File tree

9 files changed

+189
-68
lines changed

9 files changed

+189
-68
lines changed

.github/workflows/deploy.yml

Lines changed: 13 additions & 13 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:
@@ -24,13 +23,6 @@ jobs:
2423
steps:
2524
- uses: actions/checkout@v4
2625

27-
- name: Set up JDK 17
28-
uses: actions/setup-java@v4
29-
with:
30-
java-version: '17'
31-
distribution: 'temurin'
32-
cache: 'maven'
33-
3426
- name: Authenticate Google Cloud
3527
uses: google-github-actions/auth@v2
3628
with:
@@ -47,14 +39,22 @@ jobs:
4739
username: ${{ secrets.DOCKERHUB_USERNAME }}
4840
password: ${{ secrets.DOCKERHUB_TOKEN }}
4941

42+
- name: Create Google Default credentials file
43+
run: |
44+
cp ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} cred.json
5045
51-
- name: Build and Submit to Artifact Registry
52-
run: mvn -B package -DskipTests
46+
- name: Build Image
47+
run: docker build -t web -f ${{vars.DOCKER_FILE_NAME}} . --build-arg PROJECT_ID=${{vars.PROJECT_ID}}
5348

5449
- name: Configure Docker for Artifact Registry
5550
run: gcloud auth configure-docker ${{vars.DOCKER_CRED_HELPER}} -q
5651

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

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:

gcp-vm.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
gcloud compute instances create-with-container graalvm \
2+
--project=gatedaccessdev \
3+
--zone=us-central1-a \
4+
--machine-type=e2-micro \
5+
--network-interface=network-tier=PREMIUM,stack-type=IPV4_ONLY,subnet=default \
6+
--maintenance-policy=MIGRATE \
7+
--provisioning-model=STANDARD \
8+
--service-account=653203556655-compute@developer.gserviceaccount.com \
9+
--scopes=https://www.googleapis.com/auth/cloud-platform \
10+
--tags=sok,http-server,https-server,lb-health-check \
11+
--image=projects/cos-cloud/global/images/cos-stable-113-18244-85-24 \
12+
--boot-disk-size=10GB \
13+
--boot-disk-type=pd-balanced \
14+
--boot-disk-device-name=graalvm \
15+
--container-image=us-central1-docker.pkg.dev/gatedaccessdev/cove-repo/vm:latest \
16+
--container-restart-policy=always \
17+
--no-shielded-secure-boot \
18+
--shielded-vtpm \
19+
--shielded-integrity-monitoring \
20+
--labels=goog-ec-src=vm_add-gcloud,container-vm=cos-stable-113-18244-85-24

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: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +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>
2019
</properties>
2120
<dependencyManagement>
2221
<dependencies>
@@ -125,6 +124,7 @@
125124
<sourceDirectory>src/main/kotlin</sourceDirectory>
126125
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
127126
<plugins>
127+
<!-- Jacoco plugin -->
128128
<plugin>
129129
<groupId>org.jacoco</groupId>
130130
<artifactId>jacoco-maven-plugin</artifactId>
@@ -144,34 +144,18 @@
144144
</execution>
145145
</executions>
146146
</plugin>
147-
<!--Jib-->
147+
<!-- Surefire plugin -->
148148
<plugin>
149-
<groupId>com.google.cloud.tools</groupId>
150-
<artifactId>jib-maven-plugin</artifactId>
151-
<version>3.4.2</version>
152-
<executions>
153-
<execution>
154-
<phase>package</phase>
155-
<goals>
156-
<goal>build</goal>
157-
</goals>
158-
</execution>
159-
</executions>
160-
<configuration>
161-
<from>
162-
<image>
163-
eclipse-temurin:17-jre@sha256:15b50cf95210242511c17e1ec8281fd691ad7d34f163c250a21298943d65de87
164-
</image>
165-
</from>
166-
<to>
167-
<image>${image.path}</image>
168-
</to>
169-
<container>
170-
<ports>
171-
<port>80</port>
172-
</ports>
173-
</container>
174-
</configuration>
149+
<groupId>org.apache.maven.plugins</groupId>
150+
<artifactId>maven-surefire-plugin</artifactId>
151+
<version>3.2.5</version>
152+
<dependencies>
153+
<dependency>
154+
<groupId>org.apache.maven.surefire</groupId>
155+
<artifactId>surefire-junit-platform</artifactId>
156+
<version>3.2.5</version>
157+
</dependency>
158+
</dependencies>
175159
</plugin>
176160
<!--Spring Boot Maven-->
177161
<plugin>
@@ -283,5 +267,35 @@
283267
<profile>
284268
<id>test</id>
285269
</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>
286300
</profiles>
287301
</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

test.Dockerfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# syntax=docker/dockerfile:1
1+
LABEL authors="cybersokari"
22
# Dockerfile for running test
33
FROM eclipse-temurin:17-jdk-jammy as base
44
WORKDIR /build
@@ -20,6 +20,9 @@ RUN --mount=type=bind,source=pom.xml,target=pom.xml \
2020

2121
FROM deps as package
2222
WORKDIR /build
23+
ENV GCLOUD_PROJECT=gatedaccessdev
24+
ENV GOOGLE_APPLICATION_CREDENTIALS=/gcp/cred.json
25+
COPY cred.json $GOOGLE_APPLICATION_CREDENTIALS
2326
COPY ./src src/
2427
RUN --mount=type=bind,source=pom.xml,target=pom.xml \
2528
--mount=type=cache,target=/root/.m2 \

0 commit comments

Comments
 (0)