UPDATE: The manual and sample application was updated to CUBA 7 and the latest GAE SDK version. Now the manual is in the sample’s README file here: https://github.com/cuba-labs/gaef-sample
Thanks to @nelsonflorez and @marc for the contribution!
The previous version
Here are steps to deploy and run the CUBA application in Google App Engine Flexible.
Install the Cloud SDK. See Google Cloud CLI documentation | Google Cloud CLI Documentation. Also, install the app-engine-java component: gcloud components install app-engine-java
.
Create a new project using the GCP Console. I named it cuba-sample.
Create an application using Java language.
Specify a region. In my case it’s the ‘europe-west-3’.
Create a new PostgreSQL Cloud SQL instance. I gave the instance an id cuba-sample-db. Specify a default password for the postgres user (I typed postgres) and select the region.
Dive into the DB instance settings and create a new database. In my case its name is “gaef”.
As stated in this documentation section you’ll need to enable the Cloud SQL Admin API. Follow the “Enable API” link from this section and select a “cuba-sample” project in the appeared dialog. Click “Continue”.
Create a new CUBA project using CUBA Studio. In my case, its name is gaef-sample.
Open the Project properties page and change the database type to PostgreSQL.
Click the Deployment settings button and specify Uber JAR deployment options:
- Check the ‘Build Uber JAR’ checkbox
- Generate the Logback configuration file
- Generate custom Jetty environment file. In the dialog leave the database connection settings as is. We’ll modify them later in the file.
Open the jetty-env.xml file in the IDE.
The database URL should conform the format described in the manual, i.e.:
jdbc:postgresql://google/${database}?useSSL=false&cloudSqlInstance=${INSTANCE_CONNECTION_NAME}&socketFactory=com.google.cloud.sql.postgres.SocketFactory&user=${user}&password=${password}
INSTANCE_CONNECTION_NAME here can be found in the Cloud SQL instance overview page:
In my case the URL will be:
jdbc:postgresql://google/gaef?useSSL=false&cloudSqlInstance=cuba-sample:europe-west3:cuba-sample-db&socketFactory=com.google.cloud.sql.postgres.SocketFactory&user=postgres&password=postgres
Write it to the jetty-env.xml file and comment the username and password tags:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
<New id="CubaDS" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg/>
<Arg>jdbc/CubaDS</Arg>
<Arg>
<New class="org.apache.commons.dbcp2.BasicDataSource">
<Set name="driverClassName">org.postgresql.Driver</Set>
<Set name="url">jdbc:postgresql://google/gaef?useSSL=false&cloudSqlInstance=cuba-sample:europe-west3:cuba-sample-db&socketFactory=com.google.cloud.sql.postgres.SocketFactory&user=postgres&password=postgres</Set>
<!--<Set name="username">postgres</Set>-->
<!--<Set name="password">postgres</Set>-->
<Set name="maxIdle">2</Set>
<Set name="maxTotal">20</Set>
<Set name="maxWaitMillis">5000</Set>
</New>
</Arg>
</New>
</Configure>
Create the app.yaml file in the appengine directory in the root of the project:
runtime: java
runtime_config:
jdk: openjdk8
env: flex
manual_scaling:
instances: 1
readiness_check:
app_start_timeout_sec: 1500
env_variables:
JAVA_OPTS: "-Dapp.home=/opt/app_home"
An important thing here is the JAVA_OPTS environment variable. It seems that uber jar is copied to the root of the docker container. This case causes some relative URL problems when Jetty server starts. To avoid these problems we have to specify an application home directory.
app_start_timeout_sec is increased because sometimes the deployment on my side took more time than the default time.
I did the deployment using the Gradle plugin. IntelliJ plugin also worked.
Add a dependency to the appengine-gradle-plugin in the build.gradle:
dependencies {
classpath 'com.google.cloud.tools:appengine-gradle-plugin:1.+' // Latest 1.x.x release
classpath "com.haulmont.gradle:cuba-plugin:$cubaVersion"
}
In the end of the build.gradle file add necessary gradle tasks:
apply plugin: 'com.google.cloud.tools.appengine'
appengine {
stage {
artifact = "$buildDir/distributions/uberJar/app.jar"
appEngineDirectory = 'appengine' // a directory with app.yaml
stagingDirectory = "$buildDir/staged-app"
}
deploy {
project = 'cuba-sample' // specify a project id if the current project is not the default one
stopPreviousVersion = true // default - stop the current version
promote = true // default - & make this the current version
}
}
appengineStage.dependsOn(buildUberJar)
// a dummy task. It is required for appengineStage task of the google plugin
task assemble {
doLast {}
}
In the dependencies section of the coreModule add a dependency to the postgres-socket-factory:
dependencies {
compile(globalModule)
provided(servletApi)
jdbc(postgres)
jdbc('com.google.cloud.sql:postgres-socket-factory:1.0.11')
testRuntime(postgres)
}
Change the PostgreSQL JDBC driver version:
def postgres = 'org.postgresql:postgresql:42.2.5'
Then run the appengineDeploy gradle task and the project should be deployed:
./gradlew appengineDeploy
After the deployment is completed, open the application URL in the browser and add the /app to the end of the URL:
http://cuba-sample.appspot.com/app
An important note here. You will not be able to save files using the standard FileStorage. If your application uses it, then you 'll have to do something with files persistence. At first look, there are several options here: create your own file storage implementation similar to the Amazon S3 File Storage, but using the Google Cloud Storage. Another option you can try is to mount the NFS directory.
There is a GitHub project with the CUBA app I’ve got after completion of all the steps above: GitHub - cuba-labs/gaef-sample: Google App Engine Flexible Deployment. There are several commits there. The first one just commits the app created by Studio, the second commit contains all modifications required for deployment.