Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App Engine Java 11 generator to create thin JARs #10362

Closed
1 task done
saturnism opened this issue Sep 5, 2019 · 11 comments · Fixed by #10420
Closed
1 task done

App Engine Java 11 generator to create thin JARs #10362

saturnism opened this issue Sep 5, 2019 · 11 comments · Fixed by #10420
Assignees
Labels
area: enhancement 🔧 $$ bug-bounty $$ https://www.jhipster.tech/bug-bounties/ status: good first issue theme: GCP $100 https://www.jhipster.tech/bug-bounties/
Milestone

Comments

@saturnism
Copy link
Member

Overview of the feature request

from @ludoch #10331 (comment)

What I really would like to do as well is the take benefit of a exploded fatjar deployment for App Engine.
The Jib plugin does it automatically to help optimizing Docker layers.
GAE Java deployment also does it (since 2009), ie it will only deploy updated files from a previous deployment... When there is a single fatjar, all those upload optimizations are gone, even it the app changed 1 character!

Basically, if we could unjar the fatjar in the target/appengine-staging directory (and remove the orginal fatjar), the entrypoint would have to be like:

entrypoint: java -agentpath:/opt/cdbg/cdbg_java_agent.so=--log_dir=/var/log -noverify -XX:+AlwaysPreTouch -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom -cp BOOT-INF/resources/:BOOT-INF/classes/:BOOT-INF/lib/* com.mycompany.myapp.YOUAPPCLASSNAME

If this can be done, one extra goodies would be to configure App Engine to use a CDN to access the static resources instead of the JVM itself (from a fatjar which is also not optimal at all)...

To configure static resources in the app.yaml with an exploded jHipster fatjar, you would have to add this section in app.yaml:

handlers:

url: (/.)
static_files: BOOT-INF/classes/static\1
upload: NOT_USED
require_matching_file: True
login: optional
secure: optional
url: /.

script: unsused
url: /./
script: unused
login: optional
secure: optional
url: .

script: unused
login: optional
secure: optional
With these 2 changes, we are back to the orginal Java GAE design from 2009 with appengine-werb.xml configuration: exploded war for optimal deployement and automatic static file servinf from a CDN. You would see the difference when loading an app where all the static html and images and js scripts are served immediately...

Motivation for or Use Case

To allow JHipster on App Engine Java 11 to take advantage of static file serving.

Related issues or PR

#10331

  • Checking this box is mandatory (this is just to show you read everything)
@saturnism saturnism assigned saturnism and unassigned saturnism Sep 5, 2019
@SudharakaP
Copy link
Member

@saturnism : Thanks for creating the issue. Feel free to assign it to me as well. I'll start this once we finalize the java 11 gae enhancements.

@SudharakaP
Copy link
Member

SudharakaP commented Sep 11, 2019

@ludoch @saturnism : I was trying this out by constructing the thin jar using spring-boot-thin-launcher which I believe is the standard approach of doing this (let me know if you have an alternative suggestion). Although the thin jar construction seems to work in my local after deploying it to Google App Engine I get;

Exception in thread "main" java.lang.IllegalStateException: Cannot create directory for library at /var/www/.m2/repository/org/springframework/boot/experimental/spring-boot-thin-launcher/1.0.22.RELEASE/spring-boot-thin-launcher-1.0.22.RELEASE-exec.jar at org.springframework.boot.loader.wrapper.ThinJarWrapper.download(ThinJarWrapper.java:170) at org.springframework.boot.loader.wrapper.ThinJarWrapper.launch(ThinJarWrapper.java:130) at org.springframework.boot.loader.wrapper.ThinJarWrapper.main(ThinJarWrapper.java:107)

I think this is due to the thin-launcher tries to grab some dependencies at runtime and app engine file-system is read-only. I am thinking of a way to overcome this.

Let me know if you guys have any examples or deployments of using thin jars in app engine with Java 11 or is there other library that is being used to create the thin jars for app engine? I couldn't find much documentation on this except for few lines mentioned at https://cloud.google.com/appengine/docs/standard/java11/runtime#application_startup.

On the plus side it does seems to significantly improve the deployment time (size of jar seems significantly reduced). 😄

@SudharakaP
Copy link
Member

I've created a PR. This adds support for "unjaring" the jar file within the staging directory as ludoch suggested. However I found no information of this process in google documentation; so it was a lot of trial and error. The only piece of documentation I found is; https://cloud.google.com/appengine/docs/standard/java11/runtime#application_startup

There it says and I quote;

With a custom entrypoint, you can construct and package your application as a thin JAR file which only contains your application code and direct dependencies. When deploying your application, the App Engine plugin will only upload the files that changed, rather than the entire uber JAR package.

However I couldn't get this approach to work; the problem is that creating a standard thin jar with the spring-bot-thin-launcher for example doesn't work since it tries to download the dependencies at startup and appengine doesn't allow writing to the disk. I wonder whether the documentation here is wrong (maybe AppEngine Java 11 still in Beta?).

Anyways, therefore this approach just extracts the content of the fatjar within the staging folder, and it seems to work; I've tested it on an actual deployment.

However when running appengine:deploy (or in the case of gradle appengineDeploy) it does the staging again. I mean as far as I know there's no way to do the deployment only and therefore I didn't find a easy method of removing the jar file from the staging folder. If you guys have any suggestions about this let me know. Otherwise I think we have to just keep the jar file within the staging folder?

Also I've uncovered some other issues with the GAE sub-generator (particularly on the Gradle side); I'll create some more issues in the future. 😄

cc: @saturnism @ludoch

@chanseokoh
Copy link

I was trying this out by constructing the thin jar using spring-boot-thin-launcher which I believe is the standard approach of doing this

I don't think this is any way close to being standard.

@SudharakaP
Copy link
Member

SudharakaP commented Sep 16, 2019

@chanseokoh : Thanks for your input; could you please elaborate what it is when it comes to deploying spring boot applications in GAE? As per the following documents it says it can support thin jars but doesn't say exactly which method to use (maybe I missed it, correct me if I am wrong);

https://cloud.google.com/appengine/docs/standard/java11/runtime#application_startup

EDIT: I see you've commented in the GoogleCloudPlatform/app-maven-plugin#399; any further correspondence will be there. Thanks a bunch again 😄

@SudharakaP
Copy link
Member

As per my discussion in GoogleCloudPlatform/app-maven-plugin#399 we need to change this approach. I will refactor the current pull request soon. 😄

@ludoch
Copy link
Contributor

ludoch commented Sep 16, 2019

You could read https://github.com/ludoch/samples/blob/f4fcfb6ea1c7bc5bc37c36307e1c91a38f2445ff/java11/springboot/pom.xml
It does 2 things:
1/ explode the fatjar in an area
2/ delete the jar itself using a hack (I would love a better official way) by forcing a useless param in the plugin pom section so that the fatjar is not used in the final staging area... See line 57...

@SudharakaP
Copy link
Member

SudharakaP commented Sep 16, 2019

@ludoch : My discussion in the other thread; specifically the following comment;

GoogleCloudPlatform/app-maven-plugin#399 (comment)

will enable to not use the fat jar approach at all I believe (and would not need the hack). Let me know if you agree. 😄

@SudharakaP
Copy link
Member

SudharakaP commented Sep 16, 2019

@ludoch : Sorry, I misunderstood you there; yes hack is still needed to remove the fatjar. 👍 And thanks much 🥇

@SudharakaP
Copy link
Member

I've made some changes to the pull request with ludoch's workaround for removing the original jar and I think we are good to go with this. 😄

@SudharakaP
Copy link
Member

@deepu105 : Thanks for assigning a bug bounty for this; although not strictly necessary as I enjoyed doing it. I am getting a lot of coffees and teas for myself these days thanks to the extra pocket money. 🍵 🍵

mraible pushed a commit that referenced this issue Dec 16, 2019
* add support for thin jar in gae

Only adds to maven build; work in progress

* correcting mistake introduced in a pervious pull request

A previous pull request incorrectly removes the com.google.cloud.tools when gaeCloudSQLInstanceNeeded is set to false

#10362

* add correct handlers for retrieving static files

* remove bootWar from gradle

The new GAE with Java 11 builds on JAR; this has been done on the maven side.

* correcting mistake introduced in a pervious pull request

A previous pull request incorrectly removes the com.google.cloud.tools when gaeCloudSQLInstanceNeeded is set to false

* replace deprecated value "project" by "projectId"

* testing with cloudsql; change string to single quotes

If this is not done the following error is created;

yntaxError: Multi-line double-quoted string needs to be sufficiently indented (16:14)
  14 |     datasource:
  15 |         type: com.zaxxer.hikari.HikariDataSource
> 16 |         url: "jdbc:mysql://google/mysql?cloudSqlInstance=abstract-block-253023:us-central1:testjhipster
     |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* Add copyright information

* add mainclass name instead of basename

* add gradle support for unjaring the original jar

This adds Gradle side support for thin jars

* missing symbol from previous commit

* remove the original jar as per discussion

* minor bug fix per code review

* add max heap size to entrypoint field in app.yaml

* Revert Xmx change

* correction of the url strings

* remove whitespaces in project ID

* simplify the prod-gae profile definition

* thin jar generation support for maven

* thin jar generation support for gradle

* adjustments to the maven and gradle deployment commands

* add thinResolve step before staging

* prettier issue fix

* add error code checking for gcloud

- gcloud seems to print out info messages to the error stream as well. We need to check whether it's an actual error

* add trim to remove unnecessary newline and remove silent mode for prompt in order to trigger cloud sql api

* fix the trim line more elegantly

* add missing maven dependency

* refactor code to include application-prod-gae.yml file regardless of Cloud SQL

- this makes sure the correct port environment variable is passed whether the user chose to use cloud sql or not.

* fix dependency problem (similar to #9175) to get rid of the clean option

* add dependency before the check for cloud sql

* changed per code review
@pascalgrimaud pascalgrimaud added this to the 6.6.0 milestone Dec 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: enhancement 🔧 $$ bug-bounty $$ https://www.jhipster.tech/bug-bounties/ status: good first issue theme: GCP $100 https://www.jhipster.tech/bug-bounties/
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants