Deploying a Mostly Serverless Website on GCP
Tags: cloud, cloudskills, gcp, serverless
Published: 2022-07-26 14:45:53

## Introduction

With the technology that we have today there are many options for hosting a website. We are particularly interested in [Serverless Computing](https://cloud.google.com/serverless) and opted to run our website in that fashion; well mostly. When we chose [Google Cloud Platform](https://cloud.google.com/), we were unable to find a serverless relational database system. Our Java Spring Boot application was constructed to use a relational database so shifting to another database offering wasn’t something we wanted to do at this time. The architecture that we chose to implement consisted of the following GCP services. 
* [Cloud CDN](https://cloud.google.com/cdn) for distribution and caching 
* [Cloud DNS](https://cloud.google.com/dns) for DNS registration and routing
* [Cloud Load Balancing](https://cloud.google.com/load-balancing) for distribution 
* [Cloud Run](https://cloud.google.com/run) for the backend logic
* [Cloud SQL](https://cloud.google.com/sql) for persistent storage
* [Cloud Storage](https://cloud.google.com/storage) for static website hosting

> This Cloud SQL service is the only non-serverless part of the architecture. 

![gcp-architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mkg6jkfdhc8t6p8496e1.png)

## Background
Our team is extremely familiar with [Amazon Web Services](https://aws.amazon.com/what-is-aws/) but wanted to explore other clouds to gain that knowledge and provide a personal comparison. We believe that if we simply remain within our comfort zone then we will never truly grow. Additionally, we could be missing out on a better alternative if we lack the courage to explore our options. The bitter truth is that there is no clear-cut cloud provider that is simply better than the rest. You can rank cloud providers on different aspects and shake up the results. The cloud provider that you choose to use should be the one that provides the most value to you for the project that you’re working on. 

## Infrastructure Deployment
When exploring options on how to deploy the architecture we briefly considered [Google Cloud Deployment Manager](https://cloud.google.com/deployment-manager/docs). Upon further investigation we were led to use [Terraform](https://www.terraform.io/) instead. It was evident that Cloud Deployment Manager did not have the necessary support for the resource types that we were trying to create. Many of the supported resource types were still listed in beta. 

> https://cloud.google.com/deployment-manager/docs/configuration/supported-resource-types

Terraform had complete support for all the necessary resources listed above. We used Terraform Cloud to track the configuration changes and store the state.  

## Code Deployment
We realized that if we did not automate code deployments our deployed resources would quickly become stale. In the continued spirit to try something new, we decided to use [Google Cloud Build]( https://cloud.google.com/build) for our code automation. With the lack of our code changes this approach turned out to be free for us. We created a build trigger that would watch our GitHub repository and created a cloudbuild.yaml file that would configure the build job. The documentation claimed that just the Dockerfile was necessary, however, in practice we could not get that to work. We were required to create the yaml file for Cloud Build to successfully update the revision on Cloud Run.

```
options:
  logging: CLOUD_LOGGING_ONLY

steps:
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/rest-java:$COMMIT_SHA', '.']
    timeout: 300s

  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/rest-java:$COMMIT_SHA']
    timeout: 300s

  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args: ['run', 'deploy', 'rest-java', '--image', 'gcr.io/$PROJECT_ID/rest-java:$COMMIT_SHA', '--region', 'us-central1']
    timeout: 300s
```

## Serverless Relational Database Offerings
When debating the database solution for our application we were really seeking for a scalable serverless database that wouldn’t bill us for idle time. Options like [AWS Athena](https://aws.amazon.com/athena), [AWS Aurora Serverless](https://aws.amazon.com/rds/aurora/serverless/), and [Azure Cosmos DB](https://azure.microsoft.com/en-us/services/cosmos-db/) immediately came to mind. We believed that GCP would have a comparable service, yet we could not find one. Even after consulting the [GCP cloud service comparison documentation]( https://cloud.google.com/free/docs/aws-azure-gcp-service-comparison) we were still unable to find any serverless relational database offering. For these reasons we chose the path of least resistance and opted to use a micro instance of Cloud SQL for MySQL.

## Operating Performance
With our basic application running on GCP for a couple months we have been pleased with the performance and stability of the architecture. Our Cloud Run scaling settings were intentionally set low to meet application expectations as well as to avoid potential bill shock from an autoscaling fiasco. Like [AWS App Runner](https://aws.amazon.com/apprunner/) and [AWS Lambda](https://aws.amazon.com/lambda/) we faced cold start delays when scaling up from zero. We could’ve tried to architect around this with something like an automated trigger or always-running instances. Although, the cold start was not a problem for our use-case. We also felt that provisioning always-running instances defeats the purpose of a serverless service. Can a service be considered “serverless” if it can’t scale down to zero so that you’re not paying for idle compute? We said no. 

## Operating Costs
We found that GCP costs were comparable to AWS when the services were matched one-to-one. However, because the AWS CDN service [CloudFront](https://aws.amazon.com/cloudfront/) is a standalone product a simpler, cheaper, alternative architecture is possible on AWS. The GCP CDN service Cloud CDN requires usage in parallel with their Cloud Load Balancer service, which has a minimum operating cost of ~$18/month, even with no traffic. Finally, our Cloud SQL instance bills hourly as well costing us about ~$9/month. This combined ~$27 doesn’t seem like a lot, yet is drastic when comparing low traffic serverless applications that would cost pennies to host on another cloud provider. 

![aws-architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ngxv4stlwhz9gwv45pa5.png)

## Conclusion
In the end we’re glad that we explored this avenue. Our in-depth analysis for this project confirmed that GCP is not the ideal hosting solution for us. The cons for this low traffic serverless application outweigh the pros. We could build a simpler application on AWS with the following changes that would improve the scalability and reduce the cost. Using CloudFront as the CDN removes the need to use the expensive Load Balancing service. Using Aurora Serverless provides us a relational database that can scale to zero so that we’re not paying for idle time. It’s true that Aurora Serverless may face slower query response times when scaling, still we believe it’s worth the cost savings. Lastly, Aurora Serverless would provide the ability to scale past the performance we could have achieved with our single Cloud SQL instance and provided high availability so that we would not be worried about a single point of failure on the database. Perhaps we’ll explore GCP again in the future for another use-case. 

If you liked this content maybe you would like to [Buy Me a Coffee](https://www.buymeacoffee.com/wheeleruniverse) or connect with me on [LinkedIn](https://linkedin.com/in/wheeleruniverse).