GCP Cloud Run manager terraform module
This module manages a Cloud Run-hosted container. It takes care of making sure the container is connected to a Cloud SQL instance and sets environment variables on the application.
Specify the project to deploy into on the command line. So, for example, to deploy to the project
my-project
:
$ terraform init
$ terraform apply -var project=my-project
In this example, terraform is configured to use default application credentials. For Google APIs and
these credentials should correspond to a user with owner or editor access to the target project. You
can use the gcloud
command line tool to set your personal credentials as application default
credentials. See the gcloud auth application-default
command output for more information.
Versioning
The master
branch contains the tip of development and corresponds to the v8
branch. The v1
,
v2
, v3
etc. branches will maintain source compatibility with the initial release.
Ingress style
There are two supported ingress styles depending on var.ingress_style
variable.
var.ingress_style
can be:
-
domain-mapping
(default): passing DNS domains asvar.dns_names
orvar.dns_name
, which takes precedence overvar.dns_names
, will create domain mappings to the Cloud Run service. Before setting this, you must have verified ownership of the provided domains with Google. Instructions on how to do this can be found in the DevOps division guidebook. -
load-balancer
: a load balancer will be configured instead of a domain mapping. The DNS domains invar.dns_names
orvar.dns_name
, which takes precedence overvar.dns_names
, will get Google-managed or custom TLS certificates depending onvar.use_ssl_certificates
andvar.ssl_certificates
. An IPv6 address can also be allocated to the load balancer ifvar.enable_ipv6
istrue
.
Pre-deploy Cloud Run job
The v8
release introduced an enable_pre_deploy_job
variable. When set to true
a Cloud
Run job is created to execute a configurable command
before the main Cloud Run service is deployed. The initial use case for this is to run database
migrations, however in the future we're sure there'll be more.
The pre-deploy job uses the image specified in var.pre_deploy_job_image_name
if set, otherwise it
falls back to the same var.image_name
that the main service uses. The command and arguments that
the job executes are configurable via the pre_deploy_job_command
and pre_deploy_job_args
variables.
A null_resource
is also configured to execute the pre-deploy job whenever it detects that the
value of var.image_name
has changed (or at every apply
if var.force_pre_deploy_job
is set to
true
). This uses the gcloud run jobs execute
command and is run in the context of the
terraform-deploy
service account via an access token. Using null_resource
is never ideal.
However, in this situation it provides a very handy way to trigger this simple job so it has been
accepted.
To ensure that the pre-deploy job always runs before a new revision of the Cloud Run webapp
service is deployed, the resources in question are explicitly configured with depends_on
relationships, as follows.
- The
google_cloud_run_v2_job.pre_deploy
Cloud Run job has nodepends_on
relationships defined and is therefore deployed first. - The
null_resource.pre_deploy_job_trigger
resource depends ongoogle_cloud_run_v2_job.pre_deploy
and therefore won't be deployed until the Cloud Run job is deployed successfully. - Finally, the
google_cloud_run_service.webapp
Cloud Run service depends onnull_resource.pre_deploy_job_trigger
, meaning it is only deployed once thenull_resource.pre_deploy_job_trigger
has executed successfully.
Monitoring and Alerting
If the variable alerting_email_address is set, the module adds basic uptime alerting via email for failing http polling.
If the variable disable_monitoring is true, the module will disable monitoring. This is different from disabling alerting; if no alerting email addresses are provided, the uptime checks will still be configured, there just won't be any alerts sent if they fail. Disabling monitoring will also disable alerting as without any monitoring there is nothing to alert(!)
See variables.tf for how to configure alerting and monitoring.
Note that the project containing resources to be monitored must be in a Stackdriver monitoring workspace and this must be configured manually. At the time of writing there is no terraform support for this. This module will error when applying if this is not so.
Stackdriver distinguishes between workspaces and projects within those workspaces. Each workspace
must have a host project and that project must be the default project of the google.stackdriver
provider used by this module. The google.stackdriver
must be configured with credentials allowing
monitoring resources to be created in the host project.
If the workspace host project differs from the project which contains the resources to be monitored, you can use a provider alias:
provider "google" {
project = "my-project"
# ... some credentials for the *project* admin ...
}
provider "google" {
project = "stackdriver-host-project"
alias = "host"
# ... some credentials for the *product* admin ...
}
module "cloud_run_service" {
# ... other parameters ...
providers = {
google.stackdriver = google.host
}
}
Monitoring instances which require service account authentication
If allow_unauthenticated_invocations
is not true, a Cloud Function will be created which
authenticates via a service account, allowing the StackDriver monitoring to call the Cloud Function,
with the Cloud Function authentication and proxying the request to the Cloud Run instance.
Because this requires a Cloud Function to be created, the cloudfunctions.googleapis.com
service
should be enabled on the project that houses the Cloud Run instance.
Static Egress IP
A static egress IP can be allocated for the cloud run instance, using the variable
enable_static_egress_ip
. This will configure the necessary resources to route outbound traffic
from the cloud run through a static ip.
Important!
The static ip is configured with prevent_destroy = true
, meaning that it cannot be destroyed
without removing it from terraform state using terraform state rm
and then manually destroying the
resource within the GCP console. This is to prevent accidental destruction of an IP which is likely
to be whitelisted within firewall configuration that lives outside of our deployments.
Secrets as Volumes and Env Vars
Secret Manager secrets can be as environment variables or volume mounts (files) in the running container.
The service account that Cloud Run runs as needs access to the secrets for this feature to work.
Thus, this module gives secretAccessor
role to that service account for the secrets passed on
secrets_volume
and secrets_envars
.
Any number of items in the list is supported and not defining these variables when calling this
module is acceptable. The path of the mounted file will be based on path/name
.
For the example configuration below the files will be /secrets-1/foobarfile1
and
/secrets-2/foobarfile2
. A common path
for multiple secrets is not supported, they must be
unique.
Note:
name
should only have alphanumeric characters, hyphens and underscores.
Setting version = ""
is equivalent to version = "latest"
but the variable is not optional.
module "webapp" {
source = "git::https://gitlab.developers.cam.ac.uk/uis/devops/infra/terraform/gcp-cloud-run-app.git?ref=v3"
...
secrets_volume = [
{
name = "foobarfile1"
path = "/secret-1"
id = google_secret_manager_secret.secret-a.secret_id
version = "latest"
},
{
name = "foobarfile2"
path = "/secret-2"
id = google_secret_manager_secret.secret-b.secret_id
version = "2"
}
]
secrets_envars = [
{
name = "FOOBAR1"
id = google_secret_manager_secret.secret-c.secret_id
version = "latest"
},
{
name = "FOOBAR2"
id = google_secret_manager_secret.secret-d.secret_id
version = ""
}
]
...
Passing Image Names to the Module
Originally, the module did not deploy images except on the very first use (using
gcr.io/cloudrun/hello:latest
).
Currently, the module deploys the image from the mandatory variable image_name
.