In this post we are going to deploy a Spring Boot application to the Google Cloud Platform (GCP) App Engine. First, we will take a look at the differences between the standard and flexible environment of App Engine. After that, we will describe step by step how the deployment to GCP App Engine can be accomplished.

1. What Is App Engine?

App Engine is a cloud platform where you quickly can deploy your application without worrying too much about the infrastructure. Besides that, your application can automatically scale up and down, you can debug and monitor your application, split traffic, etc.

Two types of App Engine environments exist: the standard environment and the flexible environment. Which environment to choose, depends on your application’s needs. A complete comparison of features between the two environments can be found here.

You choose for the standard environment when:

  • you don’t mind that your application is running in a sandbox which is limited to a specific set of languages and runtime versions;
  • your application needs rapid scaling;
  • you only want to pay when your application is being used;
  • Pricing is based on instance hours.

You choose for the flexible environment when:

  • you want your application to run inside Docker containers on Compute Engine virtual machines;
  • your application receives a constant flow of traffic and gradually needs scaling up and down;
  • you need to use a programming language or runtime version which is not supported by the standard environment;
  • you need to access resources or services of your GCP project;
  • you pay based on the usage of vCPU, memory and persistent disks.

Besides the functional differences between the standard and flexible environment, also the differences in costs between the two environments can be decisive in which one to choose. A helpful tool in order to find out what the costs will be, is available by means of the GCP Pricing Calculator.

2. Deploy to Flexible Environment

We will start with deployment to the flexible environment. The reason for this will become clear when we try to deploy to the standard environment. Sources being used can be found at GitHub.

2.1 Create the Application

First, we need to create a Spring Boot application. We create this at start.spring.io and choose Java 1.8 and Web MVC. We choose Java 1.8 because this is the supported Java version for the standard environment and our aim is to use this same application for deployment to the standard environment without any changes.

We add a HelloController which prints a Hello Google App Engine welcome message and the host where our application is running:

@RestController
public class HelloController {

  @RequestMapping("/hello")
  public String hello() {
    StringBuilder message = new StringBuilder("Hello Google App Engine!");
    try {
      InetAddress ip = InetAddress.getLocalHost();
      message.append(" From host: " + ip);
    } catch (UnknownHostException e) {
      e.printStackTrace();
    }
      return message.toString();
    }

}

In order to make the deployment to App Engine easier, we add the App Engine Maven Plugin to our pom:

<build>
  <plugins>
    ...
    <plugin>
      <groupId>com.google.cloud.tools</groupId>
      <artifactId>appengine-maven-plugin</artifactId>
      <version>1.3.2</version>
      <configuration>
        <version>1</version>
      </configuration>
    </plugin>
  </plugins>
</build>

We also need an app.yaml file which is needed to configure your App Engine application’s settings. A complete reference for the app.yaml file can be found here. We add the following app.yaml file to directory src/main/appengine/ :

runtime: java
env: flex

handlers:
  - url: /.*
    script: this field is required, but ignored

2.2 Create the GCP Project

Now that we have created our application, it is time to turn to the Google Cloud Platform.

Create a MyGoogleAppEnginePlanet project in GCP. This also shows us the project ID, which we must remember somewhere.

CreateProjectAppEngine

Start the Google Cloud Shell in the browser and clone the git repository:

$ git clone https://github.com/mydeveloperplanet/mygoogleappengineplanet.git

Enter the mygoogleappengineplanet directory and run the application:

$ mvn clean spring-boot:run

Our application now runs in the console and we can use web preview in order to access our hello URL:

WebPreview

In the browser a new tab is opened to the following URL:

https://8080-dot-6340638-dot-devshell.appspot.com/?authuser=0

This will show a 404 error page, because it maps to the root URL. Let’s change it to our hello URL:

https://8080-dot-6340638-dot-devshell.appspot.com/hello/?authuser=0

This will show us our welcome message, as expected:

Hello Google App Engine! From host: cs-6000-devshell-vm-859e05a5-a8a3-4cd2-813f-af385740076b/172.17.0.3

2.3 Deploy to App Engine

When creating an application in AppEngine, we need to choose a region where the application will be running. The list of regions can be shown by issuing the command:

$ gcloud app regions list

We will choose region europe-west and create our AppEngine app:

$ gcloud app create --region europe-west
You are creating an app for project [gentle-respect-234016].
WARNING: Creating an App Engine application for a project is irreversible and the region
cannot be changed. More information about regions is at
<https://cloud.google.com/appengine/docs/locations>.

Creating App Engine application in project [gentle-respect-234016] and region [europe-west]....done.
Success! The app is now created. Please use `gcloud app deploy` to deploy your first app.

From within our git repository directory, we can deploy our application:

$ mvn -DskipTests appengine:deploy

After deployment, open the browser and enter the welcome URL:

https://gentle-respect-234016.appspot.com/hello

This will show us the hello message again.

In order to prevent extra charges against your GCP credit, you should shutdown your GCP project.

3. Deploy to Standard Environment

Deployment to the standard environment deploys your application into a Jetty Web Server. The standard environment is mostly used for stateless web applications which need to respond quickly to requests. Your application also runs in a sandbox. Because our application is running in a Jetty Web Server, the default configuration for a Spring Boot application will not work. This causes several conflicts because Spring Boot uses an embedded Tomcat Web Server. More information about the configuration of a Spring Boot application for the standard environment can be found here. The sources for the standard environment are available in the feature/standardenv branch of our git repository.

3.1 Convert for Standard AppEngine

In this section we will convert our previously created application with configuration for the flexible environment to a configuration which will be deployable to the standard environment.
We need to remove the app.yaml file and we add an appengine-web.xml in directory src/main/webapp/WEB-INF with the following contents:

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <threadsafe>true</threadsafe>
  <runtime>java8</runtime>
  <system-properties>
    <property name="java.util.logging.config.file" value="WEB-INF/classes/logging.properties"/>
  </system-properties>
</appengine-web-app>

We add a SpringBootServletInitializer implementation:

public class ServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(MyGoogleAppEnginePlanetApplication.class);
    }
}

The following changes are made to our pom:

...
<packaging>war</packaging>
...
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
      <exclusion>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
      </exclusion>
    </exclusions>
  </dependency>

  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <scope>provided</scope>
  </dependency>

  <!-- Exclude any jul-to-slf4j -->
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
    <scope>provided</scope>
  </dependency>
..

And finally, we add a logging.properties file into src/main/resources:

.level = INFO

3.2 Run and Deploy

In order to run the application, we need to issue the following command:

$ mvn appengine:run

In the logs we can clearly see that the standard environment is used:

[INFO] Detected App Engine standard environment application.

The URL is again accessible via the web preview, just as we did before at the flexible environment.

Deployment to AppEngine is identical as for the flexible environment:

$ mvn -DskipTests appengine:deploy

Check the correct deployment by accessing the URL via web preview and the following response is issued:

Hello Google App Engine! From host: localhost/127.0.0.1

4. Conclusion

In this post we looked at GCP App Engine and how we can deploy a Spring Boot application to the standard and flexible environment. We would not advise to deploy a Spring Boot application to the standard environment because you need to convert it in order to make it run into a Jetty Web Server. You will lose some benefits of Spring Boot. This does not mean that you should never use the standard environment. Spring Boot is probably not the best technical choice for the standard environment. The flexible environment in combination with Spring Boot is easy to use. Besides that, you have the choice of choosing another runtime than Java 8 and you can keep the benefits of using a Spring Boot application.