Add Cloud Run recipes for updating image and IAM authentication to Cloud SQL

This commit is contained in:
Wiktor Niesiobędzki
2025-08-14 12:56:57 +00:00
parent fe9d1a589e
commit 4175512d37
3 changed files with 323 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
When deploying Cloud Run, and using tags such as `latest`, terraform will not redeploy image after container is built. By using `google_artifact_registry_docker_image` data resource you can force update of the Cloud Run, each time container is rebuild.
```hcl
module "docker_artifact_registry" {
source = "./fabric/modules/artifact-registry"
project_id = var.project_id
format = { docker = { standard = {} } }
location = var.region
name = "docker-registry"
}
data "google_artifact_registry_docker_image" "this" {
project = var.project_id
image_name = "image-name"
location = var.region
repository_id = module.docker_artifact_registry.repository.repository_id
}
module "hello" {
source = "./fabric/modules/cloud-run-v2"
project_id = var.project_id
name = "hello"
region = var.region
containers = {
hello = {
image = data.google_artifact_registry_docker_image.this.self_link # self link returns image URI with hash
}
}
}
# tftest skip
```

View File

@@ -0,0 +1,100 @@
Cloud Run provides shorthand to connect to Cloud SQL database, but that requires connecting using password. In this recipe connection is authorized using IAM
```hcl
# create service account for Cloud Run service
module "run-sa" {
source = "./fabric/modules/iam-service-account"
project_id = var.project_id
name = "db-run"
iam_project_roles = {
(var.project_id) = [
"roles/storage.objectViewer",
"roles/logging.logWriter",
"roles/cloudsql.client",
"roles/cloudsql.instanceUser"
]
}
}
# Create MySQL database
module "db" {
source = "./fabric/modules/cloudsql-instance"
project_id = var.project_id
network_config = {
connectivity = {
psa_config = {
private_network = var.vpc.self_link
}
}
}
name = "db"
region = var.region
database_version = "MYSQL_8_4"
tier = "db-g1-small"
flags = {
cloudsql_iam_authentication = "on"
disconnect_on_expired_password = "on"
}
databases = [
"test"
]
users = {
# IAM Service Account
(module.run-sa.email) = {
type = "CLOUD_IAM_SERVICE_ACCOUNT"
}
}
gcp_deletion_protection = false
terraform_deletion_protection = false
}
module "database_run" {
source = "./fabric/modules/cloud-run-v2"
project_id = var.project_id
name = "db-test"
region = var.region
containers = {
sqlproxy = {
image = "docker.io/phpmyadmin"
ports = {
"" = {
container_port = 8080
name = "http1"
}
}
env = {
PMA_SOCKET = "/cloudsql/${module.db.connection_name}"
PMA_USER = split("@", module.run-sa.email)[0]
}
volume_mounts = {
custom_cloudsql = "/cloudsql"
}
}
authproxy = {
name = "cloudsql"
image = "gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.18.0"
args = [
"--auto-iam-authn",
"--private-ip",
"--unix-socket=/cloudsql",
module.db.connection_name
]
ports = {}
volume_mounts = {
custom_cloudsql = "/cloudsql"
}
}
}
service_account = module.run-sa.email
deletion_protection = false
volumes = {
custom_cloudsql = {
empty_dir_size = "128k"
}
}
}
# tftest inventory=recipe-cloudsql-iam-auth-proxy.yaml e2e
```

View File

@@ -0,0 +1,190 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
values:
module.database_run.google_cloud_run_v2_service.service[0]:
annotations: null
binary_authorization: []
build_config: []
client: null
client_version: null
custom_audiences: null
default_uri_disabled: null
deletion_protection: false
description: null
effective_labels:
goog-terraform-provisioned: 'true'
iap_enabled: false
invoker_iam_disabled: false
labels: null
location: europe-west8
name: db-test
project: project-id
scaling: []
template:
- annotations: null
containers:
- base_image_uri: null
command: null
depends_on: null
env: []
image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.18.0
liveness_probe: []
name: authproxy
volume_mounts:
- mount_path: /cloudsql
name: custom_cloudsql
working_dir: null
- args: null
base_image_uri: null
command: null
depends_on: null
env:
- name: PMA_SOCKET
value_source: []
- name: PMA_USER
value: db-run
value_source: []
image: docker.io/phpmyadmin
liveness_probe: []
name: sqlproxy
ports:
- container_port: 8080
name: http1
volume_mounts:
- mount_path: /cloudsql
name: custom_cloudsql
working_dir: null
encryption_key: null
execution_environment: EXECUTION_ENVIRONMENT_GEN1
gpu_zonal_redundancy_disabled: null
labels: null
node_selector: []
revision: null
service_account: db-run@project-id.iam.gserviceaccount.com
service_mesh: []
session_affinity: null
volumes:
- cloud_sql_instance: []
empty_dir:
- medium: MEMORY
size_limit: 128k
gcs: []
name: custom_cloudsql
nfs: []
secret: []
vpc_access: []
terraform_labels:
goog-terraform-provisioned: 'true'
timeouts: null
module.db.google_sql_database.databases["test"]:
deletion_policy: DELETE
instance: db
name: test
project: project-id
timeouts: null
module.db.google_sql_database_instance.primary:
clone: []
database_version: MYSQL_8_4
deletion_protection: false
name: db
project: project-id
region: europe-west8
restore_backup_context: []
root_password: null
settings:
- activation_policy: ALWAYS
active_directory_config: []
advanced_machine_features: []
availability_type: ZONAL
collation: null
database_flags:
- name: cloudsql_iam_authentication
value: 'on'
- name: disconnect_on_expired_password
value: 'on'
deletion_protection_enabled: false
deny_maintenance_period: []
disk_autoresize: true
disk_autoresize_limit: 0
disk_type: PD_SSD
edition: ENTERPRISE
enable_dataplex_integration: null
enable_google_ml_integration: null
ip_configuration:
- allocated_ip_range: null
authorized_networks: []
custom_subject_alternative_names: null
enable_private_path_for_google_cloud_services: false
ipv4_enabled: false
private_network: projects/xxx/global/networks/aaa
psc_config: []
server_ca_pool: null
maintenance_window: []
password_validation_policy: []
pricing_plan: PER_USE
retain_backups_on_delete: null
sql_server_audit_config: []
tier: db-g1-small
time_zone: null
timeouts: null
module.db.google_sql_user.users["db-run@project-id.iam.gserviceaccount.com"]:
deletion_policy: null
instance: db
name: db-run@project-id.iam.gserviceaccount.com
password: null
password_policy: []
password_wo: null
password_wo_version: null
project: project-id
timeouts: null
type: CLOUD_IAM_SERVICE_ACCOUNT
module.run-sa.google_project_iam_member.project-roles["project-id-roles/cloudsql.client"]:
condition: []
project: project-id
role: roles/cloudsql.client
module.run-sa.google_project_iam_member.project-roles["project-id-roles/cloudsql.instanceUser"]:
condition: []
project: project-id
role: roles/cloudsql.instanceUser
module.run-sa.google_project_iam_member.project-roles["project-id-roles/logging.logWriter"]:
condition: []
project: project-id
role: roles/logging.logWriter
module.run-sa.google_project_iam_member.project-roles["project-id-roles/storage.objectViewer"]:
condition: []
project: project-id
role: roles/storage.objectViewer
module.run-sa.google_service_account.service_account[0]:
account_id: db-run
create_ignore_already_exists: null
description: null
disabled: false
display_name: Terraform-managed.
email: db-run@project-id.iam.gserviceaccount.com
member: serviceAccount:db-run@project-id.iam.gserviceaccount.com
project: project-id
timeouts: null
counts:
google_cloud_run_v2_service: 1
google_project_iam_member: 4
google_service_account: 1
google_sql_database: 1
google_sql_database_instance: 1
google_sql_user: 1
modules: 3
resources: 9
outputs: {}