Deploy an application on AppEngine with Gradle and Java 11
Last week I had to deploy an application written with Java 11 to Google's App Engine. The project has Gradle as automation system. I found that following the guidelines of Google I was not able to deploy my application to the platform.
Then, in this post I provide the settings that worked for me, and a brief explanation about how the deployment works. In this guide I am going to consider that you have an understanding of the basic concepts of Google Cloud.
The theory
Check that you are running Java 11, and your JAVA_HOME
environment variable is not empty.
When running the deployment task, the application is built, the plugin copies the packaged application and the app.yaml
configuration file, and copies them to the build/staged-app
folder. After that, both files are uploaded to Google Cloud.
AppEngine will clone an image of Java and will include you deployed files to generate a new service release. After that the service is launched.
If you require another version of Java, or a custom implementation, you can define a Dockerfile with your setup. Check the Google's documentation to check the steps to follow [4].
Project folder structure
Your project should look similar to the following folder structure:
MyApp
├── app.yaml
├── build
│ └── staged-app
│ ├── MyApp-1.0-SNAPSHOT.war
│ └── app.yaml
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── src
├── main
│ ├── appengine
│ │ └── app.yaml
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── myapp
│ │ └── MyApplication.java
│ └── resources
│ └── application.properties
└── test
└── java
└── com
└── example
└── myapp
└── MyApplicationTests.java
Configuration files
Modify the build.gradle
file to contain a similar configuration as shown below. The app.yaml
file just requires to have both the runtime and entrypoint properties.
- build.grade file:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath 'com.google.cloud.tools:appengine-gradle-plugin:2.2.0'
classpath "org.springframework.boot:spring-boot-gradle-plugin:2.2.5.RELEASE"
}
}
apply plugin: 'org.springframework.boot'
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'com.google.cloud.tools.appengine'
dependencies {
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
providedCompile 'com.google.appengine:appengine:+'
compile 'jstl:jstl:1.2'
runtime group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.3.1'
runtime group: 'com.squareup.okhttp3', name : 'logging-interceptor', version :'4.3.1'
runtime group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: '1.3.0'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testCompile group: 'org.mockito', name: 'mockito-core', version: '2.+'
testImplementation 'org.springframework.amqp:spring-rabbit-test'
testCompile 'com.google.truth:truth:0.33'
testCompile 'com.google.appengine:appengine-testing:+'
testCompile 'com.google.appengine:appengine-api-stubs:+'
testCompile 'com.google.appengine:appengine-tools-sdk:+'
}
test {
useJUnitPlatform()
}
sourceSets {
main {
java.srcDirs = ['src/main/java']
}
}
appengine {
deploy {
stopPreviousVersion = true
promote = true
projectId = System.getenv('GOOGLE_CLOUD_PROJECT')
version = '1'
}
}
group = "com.example.myapp"
version = "1.0-SNAPSHOT"
sourceCompatibility = 1.11
targetCompatibility = 1.11
- app.yaml file: notice that the extension of the executable file at the
entrypoint
property iswar
instead ofjar
. If you check thebuild\staged-app
folder, you will find that awar
file is created.
runtime: java11
entrypoint: java -noverify -jar MyApp-1.0-SNAPSHOT.war
service: 'myapp'
env_variables:
SERVER_PORT: 8080
ELASTICSEARCH_HOST: 127.0.0.1
ELASTICSEARCH_PORT: 9200
Deployment commands
You can deploy directly using the Google SDK, or use an automation system as Gradle or Maven. The first method is useful to check if the app is working properly, the second method is a more production ready way to deploy the app.
Method 1: Using SDK
There is no need to set up Gradle. Just for checking that the application works in the platform. You can also set in the command to read the app.yaml
file that contains the settings about how to run the app.
GOOGLE_CLOUD_PROJECT=flashdeals-dev-37743 gcloud app deploy build/libs/MyApp-1.0-SNAPSHOT.war --verbosity=info
Method 2: Using Gradle
Requires to set up build.gradle
and app.yaml
files. You have also to use same folder structure as shown in following sections.
GOOGLE_CLOUD_PROJECT=your-project-id gradle appengineDeploy --info
References
[1] Testing and deploying your application, https://cloud.google.com/appengine/docs/standard/java11/testing-and-deploying-your-app
[2] app.yaml configuration file, https://cloud.google.com/appengine/docs/standard/java11/config/appref
[3] GoogleCloudPlatform/gradle-appengine-plugin, https://github.com/GoogleCloudPlatform/gradle-appengine-plugin
[4] Using Gradle and App Engine Plugin, https://cloud.google.com/appengine/docs/standard/java11/using-gradle