FAQ | This is a LIVE service | Changelog

Skip to content
Snippets Groups Projects
Commit d719d9ab authored by Ryan Kowalewski's avatar Ryan Kowalewski :man_dancing:
Browse files

docs: update documentation

parent a840ce94
No related branches found
No related tags found
1 merge request!63Release 9.0
......@@ -49,3 +49,9 @@ repos:
pass_filenames: false
entry: aquasec/trivy:latest
args: ["--cache-dir", "/tmp/.trivy-cache", "--skip-dirs", "tests", "config", ".", "--exit-code", "1"]
- id: terraform-docs
name: terraform-docs
language: docker_image
pass_filenames: false
entry: quay.io/terraform-docs/terraform-docs:0.17.0
args: ["."]
formatter: markdown table
version: "~> 0.17.0"
header-from: docs/templates/header.md
footer-from: docs/templates/footer.md
output:
file: README.md
sections:
show:
- header
- requirements
- inputs
- outputs
- footer
This diff is collapsed.
......@@ -11,3 +11,9 @@ services:
volumes:
- .:/workdir:rw
- ~/.config/gcloud/application_default_credentials.json:/root/.config/gcloud/application_default_credentials.json:ro
terraform-docs:
image: quay.io/terraform-docs/terraform-docs:0.17.0
entrypoint: ["."]
working_dir: /workdir
volumes:
- .:/workdir:rw
# Example Usage
This page contains some examples of the different ways this module can be
configured.
## Basic
A basic Cloud Run service with a single container definition.
```hcl
module "webapp" {
source = "gitlab.developers.cam.ac.uk/uis/gcp-cloud-run-app/devops"
version = "~> 9.0"
region = "europe-west2"
project = "example-project-id-1234"
containers = {
webapp = {
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
}
```
## Load balancer
A basic Cloud Run service configured to use a load balancer for ingress.
```hcl
module "webapp" {
source = "gitlab.developers.cam.ac.uk/uis/gcp-cloud-run-app/devops"
version = "~> 9.0"
region = "europe-west2"
project = "example-project-id-1234"
containers = {
webapp = {
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
enable_load_balancer = true
dns_names = {
webapp = "webapp.test.example.com"
}
}
resource "google_dns_record_set" "load_balancer_webapp" {
name = "webapp.test.example.com."
type = "A"
ttl = 300
managed_zone = "example-zone"
project = "example-project-id-1234"
rrdatas = [
module.webapp.load_balancer.external_ip
]
}
```
## Secret environment variables and volumes
A Cloud Run service configured to load environment variables and mount volumes
via Google Secret Manager secret objects.
Note that you need to grant the created service account identity the
ability to access the secret objects _outside_ of this module call.
```hcl
resource "google_secret_manager_secret" "main" {
secret_id = "my-secret"
project = "example-project-id-1234"
replication {
auto {}
}
}
resource "google_secret_manager_secret_version" "main" {
secret = google_secret_manager_secret.main.id
secret_data = "my-secret-data"
}
resource "google_secret_manager_secret_iam_member" "main" {
project = "example-project-id-1234"
secret_id = google_secret_manager_secret.main.id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${module.webapp.service_account.email}"
}
module "webapp" {
source = "gitlab.developers.cam.ac.uk/uis/gcp-cloud-run-app/devops"
version = "~> 9.0"
region = "europe-west2"
project = "example-project-id-1234"
containers = {
webapp = {
image = "us-docker.pkg.dev/cloudrun/container/hello"
env = [
{
name = "SECRET",
value_source = {
secret_key_ref = {
secret = google_secret_manager_secret.main.id
version = "latest"
}
}
}
]
volume_mounts = [
{
name = "secret-volume",
mount_path = "/secrets"
}
]
}
}
volumes = [
{
name = "secret-volume",
secret = {
secret = google_secret_manager_secret.main.id
items = [
{
version = "latest",
path = "my-secret"
}
]
}
}
]
}
```
## Mounting CloudSQL instances
A Cloud Run service which mounts an existing CloudSQL instance using the
`mount_cloudsql_instance` helper variable.
```hcl
module "webapp" {
source = "gitlab.developers.cam.ac.uk/uis/gcp-cloud-run-app/devops"
version = "~> 9.0"
region = "europe-west2"
project = "example-project-id-1234"
containers = {
webapp = {
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
mount_cloudsql_instance = module.sql.instance_connection_name
}
module "sql" {
source = "GoogleCloudPlatform/sql-db/google//modules/postgresql"
version = "~> 17.0"
database_version = "POSTGRES_15"
name = "test-sql-1234"
project_id = "example-project-id-1234"
tier = "db-f1-micro"
availability_type = "ZONAL"
region = "europe-west2"
zone = "europe-west2-a"
deletion_protection = false
deletion_protection_enabled = false
}
```
## Pre-deploy job
A Cloud Run service with a corresponding "pre-deploy" Cloud Run job. See the
[Pre-deploy Cloud Run Job](../README.md#pre-deploy-cloud-run-job) section in the
README.md for more information.
```hcl
module "webapp" {
source = "gitlab.developers.cam.ac.uk/uis/gcp-cloud-run-app/devops"
version = "~> 9.0"
region = "europe-west2"
project = "example-project-id-1234"
containers = {
webapp = {
image = "registry.gitlab.developers.cam.ac.uk/uis/devops/infra/dockerimages/django:5.0-py3.12"
}
}
mount_cloudsql_instance = module.sql.instance_connection_name
enable_pre_deploy_job = true
pre_deploy_job_container = {
image = "registry.gitlab.developers.cam.ac.uk/uis/devops/infra/dockerimages/django:5.0-py3.12"
command = ["python3"]
args = ["/usr/src/app/manage.py", "migrate"]
}
pre_deploy_job_mount_cloudsql_instance = module.sql.instance_connection_name
}
module "sql" {
source = "GoogleCloudPlatform/sql-db/google//modules/postgresql"
version = "~> 17.0"
database_version = "POSTGRES_15"
name = "test-sql-1234"
project_id = "example-project-id-1234"
tier = "db-f1-micro"
availability_type = "ZONAL"
region = "europe-west2"
zone = "europe-west2-a"
deletion_protection = false
deletion_protection_enabled = false
}
```
## Multi-container deployment
A Cloud Run service which defines multiple containers (sidecars). For more
information see the [Cloud Run
documentation](https://cloud.google.com/run/docs/deploying#sidecars).
```hcl
module "webapp" {
source = "gitlab.developers.cam.ac.uk/uis/gcp-cloud-run-app/devops"
version = "~> 9.0"
region = "europe-west2"
project = "example-test-b99f7ad6"
containers = {
webapp1 = {
name = "webapp-1"
image = "us-docker.pkg.dev/cloudrun/container/hello"
ports = [
{
container_port = 8080
}
]
}
webapp2 = {
name = "webapp-2"
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
}
```
## Canary release traffic distribution
A Cloud Run service which allocates incoming traffic equally between two
revisions.
This example uses the `revision` variable to deploy named revisions of the Cloud
Run service. This allows you to target these named revisions specifically to
split traffic between one or more revisions via the `traffic` variable.
```hcl
module "webapp" {
source = "gitlab.developers.cam.ac.uk/uis/gcp-cloud-run-app/devops"
version = "~> 9.0"
region = "europe-west2"
project = "example-project-id-1234"
revision = "v1-1-0"
containers = {
webapp = {
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
traffic = [
{
type = "TRAFFIC_TARGET_ALLOCATION_TYPE_REVISION"
revision = "v1-0-0"
percent = 50
},
{
type = "TRAFFIC_TARGET_ALLOCATION_TYPE_REVISION"
revision = "v1-1-0"
percent = 50
}
]
}
```
## Static egress IP configuration
A Cloud Run service configured with a static IP address for egress. See the
[Static Outbound IP
Address](https://cloud.google.com/run/docs/configuring/static-outbound-ip) page
in the Cloud Run documentation for details of this implementation.
The address is available in the `static_egress_ip` output of this module.
```hcl
module "webapp" {
source = "gitlab.developers.cam.ac.uk/uis/gcp-cloud-run-app/devops"
version = "~> 9.0"
enable_static_egress_ip = true
region = "europe-west2"
project = "example-test-b99f7ad6"
containers = {
webapp = {
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
}
```
## Uptime and SSL Monitoring
A basic Cloud Run service with default monitoring enabled.
```hcl
module "webapp" {
source = "gitlab.developers.cam.ac.uk/uis/gcp-cloud-run-app/devops"
version = "~> 9.0"
region = "europe-west2"
project = "example-project-id-1234"
enable_monitoring = true
containers = {
webapp = {
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
}
```
# Pre-deploy Cloud Run job
The `8.0.0` release introduced the `enable_pre_deploy_job` variable which, when
set to `true`, creates a Cloud Run job to execute a configurable command before
new Cloud Run service revisions are deployed. This is a useful way to run
database migrations and other commands which are tightly coupled to the release
cadence of the main Cloud Run service.
The pre-deploy job is configured via the `pre_deploy_job_*` variables which can
be found in `variables.tf`.
## Triggering the Cloud Run job
The Cloud Run job is executed by a `null_resource` resource which simply runs
the `gcloud run jobs execute` command. The `null_resource` is triggered each
time the `var.pre_deploy_job_container.image` value changes by default, although
you can force it to run via the `pre_deploy_job_force` variable.
## Order of operations
To ensure that the pre-deploy job runs before a new revision of the Cloud Run
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 no `depends_on`
relationships defined and is therefore deployed first.
- The `null_resource.pre_deploy_job_trigger` resource depends on
`google_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 on
`null_resource.pre_deploy_job_trigger`, meaning it is only deployed once the
`null_resource.pre_deploy_job_trigger` has executed successfully.
# GCP Cloud Run Terraform Module
This module manages the deployment of containerised applications on Cloud Run.
It includes the following functionality:
- Creation of the main Cloud Run service.
- Creation of a dedicated service account with required IAM bindings.
- Deployment of an optional load balancer configuration.
- Deployment of an optional "pre-deployment" Cloud Run job to handle tasks such
as database migrations.
- Deployment of an optional static egress IP address for the Cloud Run service.
- Configuration of simple uptime checks and SSL certificate expiry alerts.
- Convenience variables to configure certain aspects of the Cloud Run service
which would otherwise be complex, such as mounting Cloud SQL instances.
## Cloud Run v2 API
Following release `9.0.0`, this module has been refactored to use the Cloud Run
`v2` API resources exclusively (i.e. `google_cloud_run_v2_service`). This means
that many input variables are now different and updating from a previous version
will require some changes to your module definition.
## Examples
See the [docs/examples.md](docs/examples.md) page for a full list of detailed
usage examples.
## Pre-deploy Cloud Run Job
The `8.0.0` release introduced the `enable_pre_deploy_job` variable which, when
set to `true`, creates a Cloud Run job to execute a configurable command before
new Cloud Run service revisions are deployed. This is a useful way to run
database migrations and other commands which are tightly coupled to the release
cadence of the main Cloud Run service.
The pre-deploy job is configured via the `pre_deploy_job_*` variables which can
be found in `variables.tf`.
For more information on how the pre-deploy Cloud Run job works see the
[pre-deploy-job.md](../docs/pre-deploy-job.md) page.
# Testing
This project makes use of Terraform's built-in `test` command to run integration
tests. The tests are configured in the `tests` directory and deploy resources to
our dedicated Infra Testing GCP project.
## Running tests locally
To run tests locally you can use the `run_tests.sh` helper script. By default
the script will execute _all_ tests, however, it is often useful to target a
specific test file using the `-t` option. For example, to run the
`cloud_run_service.tftest.hcl` test you would use the following command.
```bash
# You must have authenticated and set the application-default credentials.
gcloud auth application-default login
./run_tests.sh -t tests/cloud_run_service.tftest.hcl
```
Note that the `test` service defined in `docker-compose.yml` sets the
`GOOGLE_IMPERSONATE_SERVICE_ACCOUNT` variable. You must have permission to
impersonate this service account to be able to run these tests.
## GitLab CI/CD test jobs
The `tests` job in the `.gitlab-ci.yml` file is configured to run all of the
test files in the `tests` directory. The tests are run in parallel using a
`matrix` job. Variables are used to allow us to specify version constraints to
test against multiple supported major versions of the Google Terraform provider.
The `tests` job is configured to require a manual trigger. This is due to the
number of resources that the jobs will deploy and the length of time the jobs
take to complete. With this in mind, you should generally only need to run the
tests job at the point you open a merge request, ensuring the job is passing
before requesting a review.
## Resource teardown and cleanup
If a test job fails Terraform attempts to teardown any resources it has already
created. This seems to work well the majority of the time. However, to protect
against resources not being destroyed, and potentially costing £££, there are
two `cleanup` jobs configured in the `.gitlab-ci.yml` file, `pre-cleanup` and
`post-cleanup`. These jobs both run the `tests/cleanup.sh` script which is
configured to check for any resources that _could_ have been created and delete
any that it finds. We run the `pre-cleanup` job to ensure that there is a clean
environment prior to the current test run, avoiding any subnet clashes etc.
It's also fine to run the `tests/cleanup.sh` script from your local machine to
perform an ad-hoc cleanup. First authenticate your `gcloud` session and then
simply run the script, for example:
```bash
gcloud auth login
./tests/cleanup.sh
```
## Troubleshooting
### Google's eventually consistent APIs
Many of Google's APIs are eventually consistent. This often causes issues as IAM
bindings and API enablement can be delayed causing our Terraform to fail.
Unfortunately, this is simply unavoidable and the only workaround is to rerun
the failed job.
#### Error 403: Permission 'iam.serviceaccounts.actAs' denied on service account
The following error is an example of the eventual consistency issue. If you're
unlucky enough to see this failure you should simply retry the job as often it
just works the second time.
```bash
tests/cloud_run_service.tftest.hcl... in progress
run "setup"... pass
run "test_service_with_default_variable_values"... fail
│ Error: Error creating Service: googleapi: Error 403: Permission
'iam.serviceaccounts.actAs' denied on service account
│ test-fab59940-run@infra-testing-int-e2395220.iam.gserviceaccount.com
(or it may not exist).
│ with google_cloud_run_v2_service.webapp,
│ on main.tf line 23, in resource "google_cloud_run_v2_service" "webapp":
│ 23: resource "google_cloud_run_v2_service" "webapp" {
```
### Invalid IPCidrRange: 10.124.0.0/28 conflicts with existing subnetwork
This error usually means a previous test run failed to tear down its resources
correctly so the subnet range is already in use. You should investigate the
previous test runs and destroy all orphaned resources before rerunning the
failed job.
```bash
tests/monitoring.tftest.hcl... in progress
run "setup"... pass
run "test_monitoring_with_alert_policies_created_in_default_project"... pass
run "test_monitoring_with_alert_policies_created_in_scoping_project"... pass
run "test_monitoring_with_auth_proxy"... pass
run "test_monitoring_with_auth_proxy_and_vpc_access_connector"... fail
│ Error: Error waiting to create Subnetwork: Error waiting for Creating
│ Subnetwork: Invalid IPCidrRange: 10.124.0.0/28 conflicts with existing
│ subnetwork 'test-209abb96-vpc-connector' in region 'europe-west2'.
│ with google_compute_subnetwork.vpc_connector[0],
│ on static_egress_ip.tf line 6, in resource "google_compute_subnetwork"
"vpc_connector":
│ 6: resource "google_compute_subnetwork" "vpc_connector" {
```
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment