Home | Send Feedback

Deploy Angular and Spring Boot application to Google cloud

Published: May 05, 2020  •  java, angular, spring

In this blog post, I show you how to deploy an Angular application to Firebase Hosting and a Spring Boot application to Google Cloud Run.

As an example, I use the chat application that I wrote for this blog post. It's an Angular/Ionic web application and a Spring Boot server application.

Prerequisites

When you create the Firebase project, you can select the Google project and connect it with Firebase, or create a new project.

Application changes

The client and server will be accessible under two different domains.

With this configuration, requests the client sends to the server are considered cross-origin requests. It is, therefore, crucial that CORS handling is enabled on the server.

In a Spring WebFlux application, we can install a global CORS handler for this purpose.

@SpringBootApplication
@EnableWebFlux
public class Application implements WebFluxConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/cettia/**")
                .allowedOrigins("https://cryptochat.ralscha.ch")
                .allowedMethods("GET", "POST")
                .allowCredentials(true)
                .maxAge(3600);
    }

On the client, I had to configure the URL of the server. I externalized this setting into the environment file, so I only needed to change the SERVER_URL entry in src/environments/environment.prod.ts.

export const environment = {
  production: true,
  SERVER_URL: 'https://cryptochatserver.ralscha.ch'
};

Angular

The Angular CLI supports deployment to the following providers:

Provider Package
Firebase @angular/fire
Azure @azure/ng-deploy
Now @zeit/ng-deploy
Netlify @netlify-builder/deploy
GitHub pages angular-cli-ghpages
Amazon Cloud S3 @jefiozie/ngx-aws-deploy

See the Angular documentation for more information:
https://angular.io/guide/deployment


We are going to deploy the application to Firebase. Firebase provides a free tier where you can store up to 1 GB of data and use a bandwidth of 10 GB per month. Firebase supports custom domains and TLS support, and you can host multiple sites in one project.

The deployment options mentioned above are not installed by default. You have to install them with ng add.

ng add @angular/fire

During the installation, you have to select the project you want the app to deploy to. This command also opens a browser where you have to log in to your Firebase account.

After the installation, you find two new files in the root of your project: .firebaserc and firebase.json. The add command also added a new "deploy" configuration to the angular.json file and installed the necessary dependencies


When you use the default settings of the Angular router, you have to make sure that requests for unknown sites are redirected to index.html. The ng add command already configured this in the firebase.json. When you open the file, you find a "rewrites" rule that redirects all requests to index.html.

Check out the Angular deployment documentation to learn more.

Note that this configuration is only necessary when you use the default settings of the Angular Router. This particular application uses the hash location strategy, so the server rewrite is technically not necessary.


With the Firebase adapter in place, we can now issue the deploy command

ng deploy

This command creates a production build of the Angular application and uploads it to Firebase. The application does not work yet. We have to deploy the server first.


Custom domain

By default, you get a Firebase URL to access your application. This is usually not the URL you want to give to your users. Instead, you want to use your own domain. To configure that, open the project console, and click on Add custom domain

custom domain

Enter the domain

enter custom domain

Firebase now needs to verify that you are the owner of this domain. Log in to your DNS hosting provider's website and insert the TXT record that Firebase displays. Verify the ownership with a click on Verify.

If Firebase can find the TXT record it presents the following dialog.

a records

Insert these A records into your DNS configuration.

You should now be able to access your deployed application with the custom domain, but you might see a security certificate warning in the browser. It can take a few hours until the certificate has been provisioned. provisioned


Undeploy

If you no longer want to host the application, run the following command from the root of your project

npx firebase hosting:disable

Then, open the Firebase console, go to Hosting and delete the files.

Spring Boot

As mentioned before, we are deploying the Spring Boot application to Google Cloud Run. Cloud Run is a fully managed platform where you can run containers. It is a paid service, but Google provides free quotas. Check out the pricing page to learn more.


Build Image

To create an image, we use a feature introduced in Spring Boot 2.3.0. The build-image goal of the Spring Boot Maven plugin builds Docker images. All you have to do is executing this command:

./mvnw spring-boot:build-image

To automate this process, you may add the build-image goal to the pom.xml. Each time you invoke the package phase with ./mvnw package the Docker image is built.

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <executions>
        <execution>
          <goals>
            <goal>build-image</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

build-image requires access to a Docker daemon. Check that the following environment variables are set correctly: DOCKER_HOST, DOCKER_TLS_VERIFY and DOCKER_CERT_PATH.

When I run this command in the cryptochat server directory, an image with the name docker.io/library/cryptochat:0.0.1 is going to be created. The Maven plugin by default names the image docker.io/library/${project.artifactId}:${project.version}.

Check out the Spring Boot documentation how to change this default behavior.

To test the image run it with: docker run docker.io/library/cryptochat:0.0.1

Visit the Spring Boot documentation for more information about building Docker images.


Push Image

The image is currently stored in our local Docker installation. Google Cloud Run can only access images that are stored in Container Registry or Artifact Registry.

So before we can create a Google Cloud Run service, we need to push our image to Google.

First, we need to tag our local image. The tag name must, according to the documentation, follow this pattern: [HOSTNAME]/[PROJECT-ID]/[IMAGE]

[HOSTNAME] in this example is grc.io, which will host the image in a US data center.
You figure out the [PROJECT-ID] with the Google Cloud CLI command: gcloud projects list
[IMAGE] is an arbitrary name. Make sure it's unique if you push multiple images under the same project.

Issue the tag command. The first parameter is the name of the local image, and the second parameter is the new tag name.

docker tag docker.io/library/cryptochat:0.0.1 gcr.io/runtest-276304/cryptochat

Before we can push an image to Container Registry, we need to configure authentication. Run these commands

gcloud auth login
gcloud auth configure-docker

Visit the documentation page for more information about this topic.


We can now push the local image to Container Registry

docker push gcr.io/runtest-276304/cryptochat

Check if your image is stored in the registry by opening the Container Registry console:
https://cloud.google.com/container-registry


Create Cloud Run Service

Open the Google Cloud Run console:
https://console.cloud.google.com/run/

Create a new service

new service

Select Region, which defines the location of the data center.
Enter a Service name, and select Allow unauthenticated invocations. We want to give everybody access to this web application.

service configuration

Select the container image you uploaded in the section before.

image selection

Click on Create creates the container, which takes a few seconds. When the container is running the console display the URL under which this new service is accessible.

service URL


Like in Firebase Hosting, this is rarely the URL you want to use in production. Instead, you want to use your domain.

Custom domain

Click on Manage custom domains

manage custom domain

Enter the domain. If you do this the first time, you have to verify the domain so Google can check if you are the owner. Follow the instructions on the screen. Usually, you have to insert a TXT record into your DNS configuration. In this example, I use a domain that is already validated.

enter domain

The last screen instructs you to add a specific record to your DNS configuration. For this setup, I had to add a CNAME record.

add dns record

To learn more about Custom Domain mapping, visit the Cloud Run documentation page.


That concludes the deployment of our applications to the Google cloud. The Angular application should work and should be able to connect to the server.

It is worth noting that Cloud Run (fully managed) currently does not support HTTP streaming. Therefore, inbound requests with protocols like WebSockets and gRPC (streaming RPCs) are not supported. Cettia, the real-time library we use in this application, is using WebSocket, but it falls back to other methods like polling. So this chat application still works with Google Cloud Run.

Keep in mind that Firebase Hosting and Google Cloud Run cost money as soon as your applications use more resources than the free tiers provide. I recommend setting up alarms in the Google Cloud Console under the menu Billing->Budgets & alerts. Google then informs you when certain thresholds are reached.