Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch from App Engine to Cloud Run for zosia site #4

Open
wants to merge 3 commits into
base: zosia_site_v2024
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 0 additions & 27 deletions zosia_site/app_engine.tf

This file was deleted.

128 changes: 128 additions & 0 deletions zosia_site/cloud_run.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
locals {
docker_image_url = "${local.region}-docker.pkg.dev/${local.project_id}/${google_artifact_registry_repository.zosia-repo.repository_id}/${local.docker_image_name}:latest"
}

resource "google_artifact_registry_repository" "zosia-repo" {
location = local.region
repository_id = "zosia-repo"
description = "Repository for zosia site production images"
format = "DOCKER"

cleanup_policies {
id = "keep-minimum-versions"
action = "KEEP"
most_recent_versions {
keep_count = 5
}
}
}

resource "google_cloud_run_v2_job" "migrate" {
name = "migrate"
location = local.region

template {
template {
service_account = google_service_account.cloudrun_service_account.email

containers {
image = local.docker_image_url
command = ["./scripts/migrate.sh"]

env {
name = "GOOGLE_CLOUD_PROJECT"
value = local.project_id
}
}
}
}
}

resource "google_cloud_run_v2_job" "collectstatic" {
name = "collectstatic"
location = local.region

template {
template {
service_account = google_service_account.cloudrun_service_account.email

containers {
image = local.docker_image_url
command = ["./scripts/collectstatic.sh"]

env {
name = "GOOGLE_CLOUD_PROJECT"
value = local.project_id
}

env {
name = "GCS_BUCKET_NAME"
value = google_storage_bucket.static_files_bucket.name
}
}
}
}
}

resource "google_cloud_run_v2_service" "zosia_site" {
name = "zosia"
location = local.region

template {
service_account = google_service_account.cloudrun_service_account.email

containers {
image = local.docker_image_url
command = ["./scripts/start_prod_server.sh"]

env {
name = "GOOGLE_CLOUD_PROJECT"
value = local.project_id
}

env {
name = "GCS_BUCKET_NAME"
value = google_storage_bucket.static_files_bucket.name
}

# TODO: Add domain mapping to zosia.org and www.zosia.org
env {
name = "HOSTS"
value = "zosia.org, www.zosia.org"
}
Comment on lines +78 to +92
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I would consider configuring it as a locally defined map and using dynamic blocks with for_each. However, for three variables, it can remain as is :)

}
}
}

# This allows zosia website to be accessed by anyone without authentication
resource "google_cloud_run_v2_service_iam_member" "noauth" {
location = google_cloud_run_v2_service.zosia_site.location
name = google_cloud_run_v2_service.zosia_site.name
role = "roles/run.invoker"
member = "allUsers"
}

resource "random_id" "static_files_bucket_prefix" {
byte_length = 8
}

resource "google_storage_bucket" "static_files_bucket" {
name = "${random_id.static_files_bucket_prefix.hex}-static-files-bucket"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand what you're trying to achieve, but you could have simply created a more readable prefix like "ksiuwr-" or "ksiuwr-infra-" ;)

location = local.region
force_destroy = false
storage_class = "STANDARD"

cors {
origin = ["*"]
method = ["GET"]
response_header = ["*"]
}
Comment on lines +115 to +119
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this bucket is not set to act as a "website", then you don't need to define CORS.

}

# This allows anyone on the internet to view static files
resource "google_storage_bucket_iam_member" "static_files_bucket_public" {
bucket = google_storage_bucket.static_files_bucket.name
role = "roles/storage.objectViewer"
member = "allUsers"
}

32 changes: 18 additions & 14 deletions zosia_site/iam.tf
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
# Required for App Engine app to access Secret Manager in runtime
resource "google_service_account" "cloudrun_service_account" {
account_id = "cloudrun-service-account"
Comment on lines +1 to +2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest renaming it to indicate that it is a service account for the Zosia website service (even though currently this is the only service you have in this infrastructure).

display_name = "Cloud Run Service Account"
}

# Required for Cloud Run to access Secret Manager in runtime
resource "google_secret_manager_secret_iam_member" "service_account_secret_accessor" {
secret_id = google_secret_manager_secret.django_settings.secret_id
role = "roles/secretmanager.secretAccessor"
member = data.google_app_engine_default_service_account.default.member

# Wait for the service account to be created before assigning roles
depends_on = [
google_app_engine_application.zosia_site,
data.google_app_engine_default_service_account.default
]
member = google_service_account.cloudrun_service_account.member
}

# Required for App Engine app to access Cloud SQL in runtime
# Required for Cloud Run to access Cloud SQL in runtime
resource "google_project_iam_binding" "service_account_cloudsql_client" {
project = local.project_id
role = "roles/cloudsql.client"

members = [
data.google_app_engine_default_service_account.default.member,
google_service_account.cloudrun_service_account.member
]
}

# Wait for the service account to be created before assigning roles
depends_on = [
google_app_engine_application.zosia_site,
data.google_app_engine_default_service_account.default
# Required for Cloud Run to access Cloud Storage with static files in runtime
resource "google_project_iam_binding" "cloud_storage_admin" {
project = local.project_id
role = "roles/storage.objectAdmin"

members = [
google_service_account.cloudrun_service_account.member
]

}
5 changes: 3 additions & 2 deletions zosia_site/locals.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
locals {
project_id = ""
region = "europe-central2"
project_id = ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can get this from the project datasource, but it's better to provide it explicitly to ensure you're running it on the correct project. Therefore, I suggest adding a comment like "< update this >".

region = "europe-central2"
docker_image_name = "zosia_prod"

db_settings = {
username = "zosia-admin"
Expand Down
10 changes: 10 additions & 0 deletions zosia_site/services.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ resource "google_project_service" "sql_service" {
project = local.project_id
service = "sql-component.googleapis.com"
}

resource "google_project_service" "artifactregistry_service" {
project = local.project_id
service = "artifactregistry.googleapis.com"
}

resource "google_project_service" "cloudrun_service" {
project = local.project_id
service = "run.googleapis.com"
}
Comment on lines 14 to +26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can change it to a single resource declaration with for_each and provide a list of services to activate.