GoogleCloudPlatform / app-maven-plugin

The library has moved to https://github.com/GoogleCloudPlatform/appengine-plugins/tree/main/app-maven-plugin
Apache License 2.0
102 stars 42 forks source link

Deploying Thin Jars with Google App Engine Plugins #399

Closed SudharakaP closed 5 years ago

SudharakaP commented 5 years ago

It is stated in the documentation of GAE Java 11;

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 it is unclear how to do this, as I've evidenced in this issue; https://github.com/jhipster/generator-jhipster/issues/10362

Do you guys have an example or some information on how the thin jar should be build; should it be built with something like spring-boot-thin-launcher ? However this seems not to work since the thin jar will then try to download the dependencies and the GAE filesystem is readonly.

The approach we employed in the aforementioned issue is to extract the content of the fatjar within the staging directory; however with this approach; I am not sure of a easy method of removing the jar file (which then becomes useless) from the staging directory as appengine:deploy seems to both stage (again) and deploy the jar.

Maybe I am missing something here; so feel free to correct me if I am wrong. 😄

loosebazooka commented 5 years ago

I don't think you should be extracting a fat jar. You can build a regular jar, use the dependencies plugin to extract dependencies somewhere: http://maven.apache.org/plugins/maven-dependency-plugin/copy-dependencies-mojo.html

and then configure that target directory as an extra directory for the appengine application you're building, so your appengine-maven configuration will look something like:

<plugin>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
      <configuration>
        <outputDirectory>${project.build.directory}/dependencies</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>
<plugin>
  <groupId>com.google.cloud.tools</groupId>
  <artifactId>appengine-maven-plugin</artifactId>
  <version>2.1.0</version>
  <configuration>
    <!--... whatever you have already ...-->
    <extraFilesDirectories>
       <extraFilesDirectory>${project.build.directory}/dependencies</extraFilesDirectory>
    </extraFilesDirectories>
  </configuration>
</plugin>

And when you run mvn package appengine:stage you should see what you want in the target directory.

Why can't you find <extraFilesDirectories> anywhere in the docs? It looks like we forgot to document it, I'll do that now.

SudharakaP commented 5 years ago

@loosebazooka : I didn't know about the extraFilesDirectory; this is indeed the missing part. Wonderful; thanks much for your help. Let me change our integration to this method. 😄

chanseokoh commented 5 years ago

If the app generated by JHipster is Spring Boot (I think it is), probably you need to adjust a few more things? Like making sure you're not including the fat JAR and having correct metadata (specifically the main method and classpath to those copied dependencies) in the thin JAR.

SudharakaP commented 5 years ago

@chanseokoh : Wonderful. I looked at all sorts of different ways to do this; the main missing part is the <extraFilesDirectories> I think because I was thinking of a way to do exactly that.

If you guys could please, please do update the documents with more details about this; if you have a document repo; I am quite willing submit a pull request. There aren't any examples of doing this out there (at least I couldn't find any) so it's a bit hard. 😄

loosebazooka commented 5 years ago

Yeah so #400 should have documentation for this. But we could probably also add a section in the FAQ about it.

SudharakaP commented 5 years ago

@loosebazooka @chanseokoh : Just want to say thank you both of you for your very quick replies to our questions and adding it to the documentation 😄

On another note maybe if you could; I suggest also changing it here; https://cloud.google.com/appengine/docs/standard/java11/runtime#application_startup to elaborate more on what is meant by thin JAR as the description seems vague to me. Should it be built using spring boot tools like https://github.com/spring-projects-experimental/spring-boot-thin-launcher ; I now see it's not; it's just a regular jar. 😄

loosebazooka commented 5 years ago

@SudharakaP That's a good suggestion, I'll bring it up with the docs team. Thanks!

loosebazooka commented 5 years ago

So I've added faq entry for this repo: https://github.com/GoogleCloudPlatform/app-maven-plugin/blob/master/USER_GUIDE.md#how-do-i-deploy-a-thin-jar-to-app-engine

Going to close this for now.

SudharakaP commented 5 years ago

@loosebazooka : Wonderful. Thanks a bunch. 😄

SudharakaP commented 5 years ago

@loosebazooka : There's one question that is still pondering in my mind. So the extraFilesDirectories gets those extra directories and uploads them to staging? Are they handled separately. I mean if we upload all the dependencies anyways it's just kinda same as extracting a fatjar right? Say if I bump a version that will change the package contents in the extraFilesDirectories and then in the next appengine:deploy trigger it will not only update my pom file but also the bumped dependency within the extraFilesDirectories. Or am I missing something here? 😺

loosebazooka commented 5 years ago

hrmm... I think you might have to do a mvn clean package appengine:deploy or something if the dependency versions change. OR something like this? https://stackoverflow.com/questions/21566352/delete-old-artifact-version-before-copy-dependencies

SudharakaP commented 5 years ago

@loosebazooka : Sorry I was confused a bit working on this problem for too long. I think I now see what you mean clearly. What you are essentially doing is separating the jar and it's dependencies. I once thought given the description at https://cloud.google.com/appengine/docs/standard/java11/runtime#application_startup that the app engine can handle actual "thin jars" where the app engine handles the downloading of dependencies. and we don't have to worry about any dependency copying or uploading whatsoever. What you are doing here (as well as what I have implemented at https://github.com/jhipster/generator-jhipster/issues/10362) isn't too different from each other; only significant difference being since I didn't know about the extraFilesDirectories parameter and so I just dumped the dependencies to the appengine-staging directory before appengine:deploy runs. Also I lacked a workaround to remove the original jar file as suggested by ludoch.

Anyhow thanks for the clarifications. 😄

alamothe commented 4 years ago

Any example for Gradle?

loosebazooka commented 4 years ago

@alamothe please take a look at the gradle plugin page: https://github.com/GoogleCloudPlatform/app-gradle-plugin and file an issue there with FULL details of your issue.

This issue is closed and should not be used to further discussion.