Skip to content

Commit

Permalink
Add a module to encapsulate some of our Go service best practices.
Browse files Browse the repository at this point in the history
This module encapsulates much of the boilerplate to stand up a regionalized Go service from source using
`ko_build`.

Signed-off-by: Matt Moore <[email protected]>
  • Loading branch information
mattmoor committed Dec 23, 2023
1 parent 100bc25 commit 8a283d4
Show file tree
Hide file tree
Showing 8 changed files with 299 additions and 135 deletions.
1 change: 1 addition & 0 deletions .github/workflows/documentation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
- cloudevent-broker
- cloudevent-trigger
- cloudevent-recorder
- regional-go-service
- otel-collector
- networking
- dashboard/service
Expand Down
71 changes: 17 additions & 54 deletions cloudevent-broker/ingress.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,69 +21,32 @@ resource "google_pubsub_topic_iam_binding" "ingress-publishes-events" {
members = ["serviceAccount:${google_service_account.this.email}"]
}

// Build the ingress image using our minimal hardened base image.
resource "ko_build" "this" {
base_image = "cgr.dev/chainguard/static:latest-glibc"
importpath = "./cmd/ingress"
working_dir = path.module
}

// Sign the image, assuming a keyless signing identity is available.
resource "cosign_sign" "this" {
image = ko_build.this.image_ref

# Only keep the latest signature.
conflict = "REPLACE"
}

module "otel-collector" {
source = "../otel-collector"

project_id = var.project_id
service_account = google_service_account.this.email
}

resource "google_cloud_run_v2_service" "this" {
for_each = var.regions

// Explicitly wait for the iam binding before provisioning the service,
// since the service functionally depends on being able to publish events
// to the topic. In practice, GCP IAM is "eventually consistent" and there
// will still invariably be some latency after even the service is created
// where publishing may fail.
depends_on = [google_pubsub_topic_iam_binding.ingress-publishes-events]

project = var.project_id
name = var.name
location = each.key
module "this" {
source = "../regional-go-service"
project_id = var.project_id
name = var.name
regions = var.regions

// The ingress service is an internal service, and so it should only
// be exposed to the internal network.
ingress = "INGRESS_TRAFFIC_INTERNAL_ONLY"

launch_stage = "BETA" // Needed for vpc_access below
// Route all egress into the VPC
egress = "ALL_TRAFFIC"

template {
vpc_access {
network_interfaces {
network = each.value.network
subnetwork = each.value.subnet
service_account = google_service_account.this.email
containers = {
"ingress" = {
source = {
working_dir = path.module
importpath = "./cmd/ingress"
}
egress = "ALL_TRAFFIC" // This should not egress
}

service_account = google_service_account.this.email
containers {
image = cosign_sign.this.signed_ref

ports { container_port = 8080 }

env {
ports = [{ container_port = 8080 }]
regional-env = [{
name = "PUBSUB_TOPIC"
value = google_pubsub_topic.this[each.key].name
}
value = { for k, v in google_pubsub_topic.this : k => v.name }
}]
}
containers { image = module.otel-collector.image }
}
}

Expand Down
2 changes: 1 addition & 1 deletion cloudevent-broker/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
output "ingress" {
depends_on = [google_cloud_run_v2_service.this]
depends_on = [module.this]
description = "An object holding the name of the ingress service, which can be used to authorize callers to publish cloud events."
value = {
name = var.name
Expand Down
117 changes: 37 additions & 80 deletions cloudevent-recorder/recorder.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,100 +16,59 @@ resource "google_storage_bucket_iam_member" "recorder-writes-to-gcs-buckets" {
member = "serviceAccount:${google_service_account.recorder.email}"
}

resource "ko_build" "recorder-image" {
base_image = "cgr.dev/chainguard/static:latest-glibc"
importpath = "./cmd/recorder"
working_dir = path.module
}

resource "cosign_sign" "recorder-image" {
image = ko_build.recorder-image.image_ref

# Only keep the latest signature.
conflict = "REPLACE"
}

resource "ko_build" "logrotate-image" {
base_image = "cgr.dev/chainguard/static:latest-glibc"
importpath = "./cmd/logrotate"
working_dir = path.module
}

resource "cosign_sign" "logrotate-image" {
image = ko_build.logrotate-image.image_ref

# Only keep the latest signature.
conflict = "REPLACE"
}

module "otel-collector" {
source = "../otel-collector"

project_id = var.project_id
service_account = google_service_account.recorder.email
}

resource "google_cloud_run_v2_service" "recorder-service" {
for_each = var.regions
module "this" {
source = "../regional-go-service"
project_id = var.project_id
name = var.name
regions = var.regions

provider = google-beta # For empty_dir
project = var.project_id
name = var.name
location = each.key
// This service should only be called by our Pub/Sub
// subscription, so flag it as internal only.
ingress = "INGRESS_TRAFFIC_INTERNAL_ONLY"

launch_stage = "BETA"
// Route all egress into the VPC
egress = "ALL_TRAFFIC"

template {
vpc_access {
network_interfaces {
network = each.value.network
subnetwork = each.value.subnet
}
egress = "ALL_TRAFFIC" // This should not egress
}

service_account = google_service_account.recorder.email
containers {
image = cosign_sign.recorder-image.signed_ref

ports {
container_port = 8080
service_account = google_service_account.recorder.email
containers = {
"recorder" = {
source = {
working_dir = path.module
importpath = "./cmd/recorder"
}

env {
ports = [{ container_port = 8080 }]
env = [{
name = "LOG_PATH"
value = "/logs"
}
volume_mounts {
}]
volume_mounts = [{
name = "logs"
mount_path = "/logs"
}
}]
}
containers {
image = cosign_sign.logrotate-image.signed_ref

env {
name = "BUCKET"
value = google_storage_bucket.recorder[each.key].url
"logrotate" = {
source = {
working_dir = path.module
importpath = "./cmd/logrotate"
}
env {
env = [{
name = "LOG_PATH"
value = "/logs"
}
volume_mounts {
}]
regional-env = [{
name = "BUCKET"
value = { for k, v in google_storage_bucket.recorder : k => v.url }
}]
volume_mounts = [{
name = "logs"
mount_path = "/logs"
}
}
containers { image = module.otel-collector.image }
volumes {
name = "logs"
empty_dir {}
}]
}
}
volumes = [{
name = "logs"
empty_dir = {}
}]
}

resource "random_id" "trigger-suffix" {
Expand All @@ -128,20 +87,18 @@ module "triggers" {
broker = var.broker[each.value.region]
filter = { "type" : each.value.type }

depends_on = [google_cloud_run_v2_service.recorder-service]
depends_on = [module.this]
private-service = {
region = each.value.region
name = google_cloud_run_v2_service.recorder-service[each.value.region].name
name = var.name
}
}

module "recorder-dashboard" {
source = "../dashboard/cloudevent-receiver"
service_name = var.name

labels = {
for type, schema in var.types : replace(type, ".", "_") => ""
}
labels = { for type, schema in var.types : replace(type, ".", "_") => "" }

triggers = {
for type, schema in var.types : "type: ${type}" => "${var.name}-${random_id.trigger-suffix[type].hex}"
Expand Down
41 changes: 41 additions & 0 deletions regional-go-service/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# `regional-go-service`

DO NOT SUBMIT

Check failure on line 3 in regional-go-service/README.md

View workflow job for this annotation

GitHub Actions / Do Not Submit

[DO NOT SUBMIT] reported by reviewdog 🐶 DO NOT SUBMIT Raw Output: ./regional-go-service/README.md:3:DO NOT SUBMIT

<!-- BEGIN_TF_DOCS -->
## Requirements

No requirements.

## Providers

| Name | Version |
|------|---------|
| <a name="provider_google"></a> [google](#provider\_google) | n/a |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [google_cloud_run_v2_service_iam_member.authorize-calls](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_v2_service_iam_member) | resource |
| [google_cloud_run_v2_service.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/cloud_run_v2_service) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_name"></a> [name](#input\_name) | The name of the Cloud Run service in this region. | `string` | n/a | yes |
| <a name="input_project_id"></a> [project\_id](#input\_project\_id) | n/a | `string` | n/a | yes |
| <a name="input_region"></a> [region](#input\_region) | The region in which this Cloud Run service is based. | `string` | n/a | yes |
| <a name="input_service-account"></a> [service-account](#input\_service-account) | The email of the service account being authorized to invoke the private Cloud Run service. | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_uri"></a> [uri](#output\_uri) | The URI of the private Cloud Run service. |
<!-- END_TF_DOCS -->
Loading

0 comments on commit 8a283d4

Please sign in to comment.