Repository navigation
Expand file tree
/
Copy pathcloudbuild.yaml
More file actions
121 lines (114 loc) · 5.36 KB
/
Copy pathcloudbuild.yaml
File metadata and controls
121 lines (114 loc) · 5.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# Build the image, push it, deploy it to Cloud Run.
#
# npm run deploy # uses the defaults below
# npm run deploy -- --substitutions=_REGION=us-east4
#
# One-time project setup: scripts/gcp/setup.sh. Secrets: scripts/gcp/secrets.sh
# or the console. See README "Deploy".
#
# Configuration comes from Secret Manager, fetched natively by Cloud Build
# (availableSecrets below). Values exist only as env vars inside the build step
# that declares them - never in this file, the trigger, or the build log.
#
# Most of what the app reads is NEXT_PUBLIC_*, inlined at build time. That now
# includes NEXT_PUBLIC_GOOGLE_MAPS_BROWSER_KEY, which is meant to be public: it
# is restricted to the Maps JavaScript API and to this app's own domains, so the
# worst a scraped copy can do is draw a map.
#
# GOOGLE_MAPS_API_KEY is the opposite and is mounted into the running service
# instead. It can spend Places quota on geocoding, address lookup is called from
# the server precisely so it never reaches a browser, and inlining it would undo
# that. The two are deliberately different keys.
#
# The Supabase secret key and the database URL bypass RLS and are deliberately
# absent from GCP.
steps:
- id: build
name: gcr.io/cloud-builders/docker
entrypoint: bash
secretEnv:
- NEXT_PUBLIC_SUPABASE_URL
- NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
- NEXT_PUBLIC_LOGO_DEV_TOKEN
- NEXT_PUBLIC_GOOGLE_MAPS_BROWSER_KEY
args:
- -c
- |
set -euo pipefail
# A trailing newline in a secret (easy to add with `echo x | gcloud
# secrets create`) would be inlined into the bundle and break the URL
# or key in ways that are miserable to debug. Strip it here.
# Literal dollar signs in this script are doubled: Cloud Build
# substitutes over the whole string, comments included, and rejects
# references it does not know. A doubled sign is its escape.
clean() { printf '%s' "$$1" | tr -d '\r\n'; }
docker build \
--build-arg NEXT_PUBLIC_SUPABASE_URL="$$(clean "$$NEXT_PUBLIC_SUPABASE_URL")" \
--build-arg NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY="$$(clean "$$NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY")" \
--build-arg NEXT_PUBLIC_LOGO_DEV_TOKEN="$$(clean "$$NEXT_PUBLIC_LOGO_DEV_TOKEN")" \
--build-arg NEXT_PUBLIC_GOOGLE_MAPS_BROWSER_KEY="$$(clean "$$NEXT_PUBLIC_GOOGLE_MAPS_BROWSER_KEY")" \
--build-arg NEXT_PUBLIC_SITE_URL="${_SITE_URL}" \
--tag "${_IMAGE}:${BUILD_ID}" \
--tag "${_IMAGE}:latest" \
.
- id: push
name: gcr.io/cloud-builders/docker
args: [push, --all-tags, "${_IMAGE}"]
- id: deploy
name: gcr.io/google.com/cloudsdktool/cloud-sdk:slim
entrypoint: gcloud
args:
- run
- deploy
- ${_SERVICE}
- --image=${_IMAGE}:${BUILD_ID}
- --region=${_REGION}
# A dedicated identity whose only grant is reading the Maps key: the app
# calls Google with that key, not with this service account.
- --service-account=${_RUNTIME_SA}
- --allow-unauthenticated
- --port=8080
# Cloud Run runs in UTC. Without this, "today" in the date-applied
# default is tomorrow every evening in Montreal, and week buckets on the
# dashboard shift. Set to the zone the user lives in.
- --set-env-vars=TZ=${_TZ}
# Fetched from Secret Manager by the runtime identity at start-up, so a
# rotated key needs a new revision but not a rebuild.
- --set-secrets=GOOGLE_MAPS_API_KEY=GOOGLE_MAPS_API_KEY:latest
- --cpu=1
- --memory=512Mi
# Scale to zero: a personal tracker idles most of the day and costs
# nothing while it does. The first request after idle pays a cold start.
- --min-instances=0
- --max-instances=2
- --cpu-boost
availableSecrets:
secretManager:
- versionName: projects/${PROJECT_ID}/secrets/NEXT_PUBLIC_SUPABASE_URL/versions/latest
env: NEXT_PUBLIC_SUPABASE_URL
- versionName: projects/${PROJECT_ID}/secrets/NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY/versions/latest
env: NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
- versionName: projects/${PROJECT_ID}/secrets/NEXT_PUBLIC_LOGO_DEV_TOKEN/versions/latest
env: NEXT_PUBLIC_LOGO_DEV_TOKEN
- versionName: projects/${PROJECT_ID}/secrets/NEXT_PUBLIC_GOOGLE_MAPS_BROWSER_KEY/versions/latest
env: NEXT_PUBLIC_GOOGLE_MAPS_BROWSER_KEY
substitutions:
# Montreal. Put it in or near your Supabase project's region: every page
# load makes Supabase calls, and the distance is paid on each one.
_REGION: northamerica-northeast1
_SERVICE: job-tracker
_REPO: job-tracker
_TZ: America/Toronto
# Optional. Empty is fine: redirects fall back to the forwarded Host header,
# which Cloud Run sets. Set it once you have a custom domain.
_SITE_URL: ''
_IMAGE: ${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_REPO}/web
_RUNTIME_SA: job-tracker-run@${PROJECT_ID}.iam.gserviceaccount.com
# Builds run as a dedicated deployer identity holding only what this pipeline
# needs (scripts/gcp/setup.sh), not the broad default Cloud Build account.
serviceAccount: projects/${PROJECT_ID}/serviceAccounts/job-tracker-deployer@${PROJECT_ID}.iam.gserviceaccount.com
options:
# _IMAGE and _RUNTIME_SA are built from other substitutions.
dynamicSubstitutions: true
# Required when a build runs as a user-specified service account.
logging: CLOUD_LOGGING_ONLY