Repository navigation
155 lines (136 loc) · 6.33 KB
/
Copy pathdeploy.yml
File metadata and controls
155 lines (136 loc) · 6.33 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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
name: Build, scan, and deploy
on:
push:
branches: [main]
workflow_dispatch:
inputs:
promote_to_production:
description: "Promote the currently-deployed staging image to production"
type: boolean
default: false
env:
REGION: us-east4
PROJECT_ID: ${{ vars.GCP_PROJECT_ID }}
REPOSITORY: clearpay
IMAGE: api
permissions:
id-token: write # required for Workload Identity Federation, no downloaded key
contents: read
jobs:
build-scan-push:
if: ${{ !inputs.promote_to_production }}
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.tag.outputs.tag }}
steps:
- uses: actions/checkout@v4
- name: Compute image tag
id: tag
run: echo "tag=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- name: Build images
run: |
docker build -t clearpay-api:${{ steps.tag.outputs.tag }} ./api
docker build -f ui/Dockerfile.prod -t clearpay-ui:${{ steps.tag.outputs.tag }} ./ui
# Fails the build on critical/high vulnerabilities that have a
# fix. ignore-unfixed leaves the gate on. exit-code 0 would
# turn it off. See Chapter 11.
- name: Scan API image
uses: aquasecurity/trivy-action@master
with:
image-ref: clearpay-api:${{ steps.tag.outputs.tag }}
severity: CRITICAL,HIGH
ignore-unfixed: true
exit-code: "1"
- name: Scan UI image
uses: aquasecurity/trivy-action@master
with:
image-ref: clearpay-ui:${{ steps.tag.outputs.tag }}
severity: CRITICAL,HIGH
ignore-unfixed: true
exit-code: "1"
- name: Authenticate to GCP
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.GCP_CI_SERVICE_ACCOUNT }}
- uses: google-github-actions/setup-gcloud@v2
- name: Configure Docker for Artifact Registry
run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev --quiet
- name: Push images
run: |
API_URL="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/api"
UI_URL="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/ui"
docker tag clearpay-api:${{ steps.tag.outputs.tag }} "$API_URL:${{ steps.tag.outputs.tag }}"
docker tag clearpay-api:${{ steps.tag.outputs.tag }} "$API_URL:staging-latest"
docker tag clearpay-ui:${{ steps.tag.outputs.tag }} "$UI_URL:${{ steps.tag.outputs.tag }}"
docker tag clearpay-ui:${{ steps.tag.outputs.tag }} "$UI_URL:staging-latest"
docker push "$API_URL:${{ steps.tag.outputs.tag }}"
docker push "$API_URL:staging-latest"
docker push "$UI_URL:${{ steps.tag.outputs.tag }}"
docker push "$UI_URL:staging-latest"
- name: Get GKE credentials
uses: google-github-actions/get-gke-credentials@v2
with:
cluster_name: clearpay
location: us-east4-a
- name: Deploy to staging
run: |
cd k8s/overlays/staging
# secrets.staging.env is gitignored. Pull the Ticket 11F
# drawers. Do not print the file.
umask 077
{
printf 'JWT_SECRET=%s\n' "$(gcloud secrets versions access latest --secret=clearpay-staging-jwt-secret)"
printf 'DATABASE_URL=%s\n' "$(gcloud secrets versions access latest --secret=clearpay-staging-database-url)"
} > secrets.staging.env
sed -i "s/@PROJECT_ID.iam/@${PROJECT_ID}.iam/" patch-serviceaccount.yaml
sed -i "s#projects/PROJECT_ID/#projects/${PROJECT_ID}/#" secretproviderclass.yaml
kustomize edit set image \
REGION-docker.pkg.dev/PROJECT_ID/clearpay/api=${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/api:${{ steps.tag.outputs.tag }}
kustomize edit set image \
REGION-docker.pkg.dev/PROJECT_ID/clearpay/ui=${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/ui:${{ steps.tag.outputs.tag }}
kubectl apply -k .
kubectl -n staging rollout status deployment/clearpay-api --timeout=180s
kubectl -n staging rollout status deployment/clearpay-ui --timeout=180s
# Production is a later ticket. A push to main only builds, scans,
# and deploys staging. The promotion gate script is Ticket 15.
# You run it. This job does not.
# Promotion to production is a separate, manually-triggered
# job, never automatic.
promote-to-production:
if: ${{ inputs.promote_to_production }}
runs-on: ubuntu-latest
environment: production # requires a manual approval rule configured on this GitHub Environment
steps:
- uses: actions/checkout@v4
- name: Authenticate to GCP
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.GCP_CI_SERVICE_ACCOUNT }}
- uses: google-github-actions/setup-gcloud@v2
- uses: google-github-actions/get-gke-credentials@v2
with:
cluster_name: clearpay
location: us-east4-a
- name: Find the currently-deployed staging images
id: current
run: |
API=$(kubectl -n staging get deployment clearpay-api \
-o jsonpath='{.spec.template.spec.containers[0].image}')
UI=$(kubectl -n staging get deployment clearpay-ui \
-o jsonpath='{.spec.template.spec.containers[0].image}')
echo "api=$API" >> "$GITHUB_OUTPUT"
echo "ui=$UI" >> "$GITHUB_OUTPUT"
- name: Deploy those exact images to production
run: |
cd k8s/overlays/production
sed -i "s/@PROJECT_ID.iam/@${PROJECT_ID}.iam/" patch-serviceaccount.yaml
sed -i "s#projects/PROJECT_ID/#projects/${PROJECT_ID}/#" secretproviderclass.yaml
kustomize edit set image \
REGION-docker.pkg.dev/PROJECT_ID/clearpay/api=${{ steps.current.outputs.api }}
kustomize edit set image \
REGION-docker.pkg.dev/PROJECT_ID/clearpay/ui=${{ steps.current.outputs.ui }}
kubectl apply -k .
kubectl -n production rollout status deployment/clearpay-api --timeout=180s
kubectl -n production rollout status deployment/clearpay-ui --timeout=180s