Skip to content

Commit

Permalink
feat: improve Cloud Run deployment template (#404)
Browse files Browse the repository at this point in the history
  • Loading branch information
x1unix authored Aug 12, 2024
1 parent 40c5337 commit 1642145
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 38 deletions.
52 changes: 44 additions & 8 deletions docs/deployment/gcloud/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,55 @@
# Google Cloud Run Deployment

## Overview

This example provides a basic Terraform project to deploy the playground
on Google Cloud as a [Cloud Run](https://cloud.google.com/run?hl=en) app.

HCL defines:

* Cloud Run service with the app.
* Simple bucket with shared Go mod and WASM builds cache.
* IAM rules for a cache bucket.

## Prerequisites

* [Terraform](https://www.terraform.io/) or [OpenTofu](https://opentofu.org).
* [gcloud](https://cloud.google.com/sdk/docs/install) tool.
* [Google Cloud CLI (`gcloud`)](https://cloud.google.com/sdk/docs/install).
* [Google Cloud](https://cloud.google.com/) project.

## Setup
## Deployment

### First-time setup

Initialize a Terraform project and prepare a TF variables file:

* Initialize project using `terraform init` command.
* Copy `example.tfvars` to `prod.tfvars` and edit the file.
* Prepare Terraform plan using variables file: \
`terraform plan -var-file="prod.tfvars" -out=tfplan`
* Apply a plan using `terraform apply tfplan` command.
```shell
# Auth on gcloud and init TF project.
# This action should be called only once.
make init

## Configuration
# Create a var file from a template
# and fill it with correct values:
cp example.tfvars prod.tfvars
vim prod.tfvars
```

### App Configuration

See environment variables section in [Docker](../docker/README.md) docs.

### Deploying changes

```shell
# Prepare a Terraform plan
make plan

# Apply a plan
make apply
```

### Destroying a deployment

```shell
make destroy
```
149 changes: 119 additions & 30 deletions docs/deployment/gcloud/main.tf
Original file line number Diff line number Diff line change
@@ -1,28 +1,110 @@
# See: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service

# Beta provider is required for "empty_dir" storage type.
# Beta provider is required for "gcs" storage type.
provider "google-beta" {
project = var.project_id
region = var.region
}

# By default, TF will keep infra state in '*.tfstate' files.
# Uncomment this block if you with to keep TF state in a storage bucket:
#terraform {
# backend "gcs" {
# bucket = "<YOUR BUCKET NAME>"
# prefix = "tfstates"
# }
#}

locals {
cache_bucket_name = "gpg-build-cache-${var.app_env}"
cache_bucket_mount = "/mnt/gpg-build-cache-${var.app_env}"
service_account_id = "gpg-svc-acc-${var.app_env}"
}

# Service account to access playground's cache bucket.
#
# See: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_service_account
resource "google_service_account" "run_sa" {
account_id = local.service_account_id
project = var.project_id
display_name = "Service Account for a Better Go Playground (${var.app_env})"
}

# Bucket to keep cached WASM builds and downloaded Go modules.
#
# See: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket
resource "google_storage_bucket" "static" {
project = var.project_id
location = var.region
name = local.cache_bucket_name
public_access_prevention = "enforced"

# Truncate Go module cache policy
lifecycle_rule {
condition {
age = 14
matches_prefix = ["mod/"]
}

action {
type = "Delete"
}
}

# Truncate WASM builds cache policy
lifecycle_rule {
condition {
age = 7
matches_prefix = ["builds/"]
}

action {
type = "Delete"
}
}

# Truncate incomplete uploads
lifecycle_rule {
condition {
age = 1
}
action {
type = "AbortIncompleteMultipartUpload"
}
}
}

# IAM rule to grant access for a cache bucket.
#
# See: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket_iam
resource "google_storage_bucket_iam_binding" "bucket_access" {
bucket = google_storage_bucket.static.name
role = "roles/storage.objectAdmin"
members = [
"serviceAccount:${google_service_account.run_sa.email}"
]
}

# The app service.
#
# See: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service
resource "google_cloud_run_v2_service" "default" {
provider = google-beta
name = "gpg-${var.app_env}"
location = var.region
launch_stage = "BETA"

template {
# Use service account with cache bucket access
service_account = google_service_account.run_sa.email

scaling {
min_instance_count = 1
max_instance_count = 5
}

volumes {
name = "gpg-build-cache-${var.app_env}"
empty_dir {
medium = "MEMORY"
size_limit = "256Mi"
name = local.cache_bucket_name
gcs {
bucket = local.cache_bucket_name
}
}

Expand All @@ -42,32 +124,50 @@ resource "google_cloud_run_v2_service" "default" {
}
}

env {
name = "APP_LOG_FORMAT"
value = "console"
# Use the cache bucket for WASM builds and Go modules.
volume_mounts {
name = local.cache_bucket_name
mount_path = local.cache_bucket_mount
}

# Disable cache cleanup for stateless containers.
env {
name = "APP_SKIP_MOD_CLEANUP"
value = "1"
name = "APP_BUILD_DIR"
value = "${local.cache_bucket_mount}/builds"
}

env {
name = "SENTRY_ENVIRONMENT"
value = var.app_env
name = "GOMODCACHE"
value = "${local.cache_bucket_mount}/mod"
}

# Logging
env {
name = "SENTRY_RELEASE"
value = "v${var.app_version}"
name = "APP_LOG_FORMAT"
value = "console"
}

# Disable cache cleanup for stateless containers.
env {
name = "SENTRY_DSN"
value = var.sentry_dsn
name = "APP_SKIP_MOD_CLEANUP"
value = "1"
}

# Uncomment this if you're using Sentry.
# env {
# name = "SENTRY_ENVIRONMENT"
# value = var.app_env
# }

# env {
# name = "SENTRY_RELEASE"
# value = "v${var.app_version}"
# }

# env {
# name = "SENTRY_DSN"
# value = var.sentry_dsn
# }

dynamic "env" {
for_each = var.env_vars
content {
Expand All @@ -76,17 +176,6 @@ resource "google_cloud_run_v2_service" "default" {
}
}

# Use WASM build cache directory.
env {
name = "APP_BUILD_DIR"
value = "/var/cache/wasm-builds"
}

volume_mounts {
name = "gpg-build-cache-${var.app_env}"
mount_path = "/var/cache/wasm-builds"
}

startup_probe {
http_get {
path = "/api/version"
Expand Down

0 comments on commit 1642145

Please sign in to comment.