-
Notifications
You must be signed in to change notification settings - Fork 0
324 lines (292 loc) · 12.6 KB
/
deploy.yml
File metadata and controls
324 lines (292 loc) · 12.6 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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
on:
workflow_call:
inputs:
environment:
description: environment reference i.e. 'prod' or 'dev'
required: true
type: string
lambda_version:
description: "Valid lambda version"
required: true
type: string
frontend_version:
description: "Valid frontend version"
required: false
type: string
default: ""
code_bucket:
description: "Bucket containing lambda and frontend zips"
required: true
type: string
ecs_image_uris:
description: "List of full ECS image URIs"
required: false
type: string
default: "[]"
lambda_matrix:
required: false
type: string
default: "[]"
task_matrix:
required: false
type: string
default: "[]"
lambda_keep:
description: "Number of lambda versions to keep"
default: '5'
type: string
concurrency: # only run one instance of workflow at any one time
group: deploy-${{ inputs.environment }}
cancel-in-progress: false
permissions:
id-token: write
contents: write
env:
AWS_OIDC_ROLE_ARN: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/aws-serverless-github-deploy-${{ inputs.environment }}-github-oidc-role
AWS_REGION: eu-west-2
jobs:
lambdas:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
value: ${{ fromJson(inputs.lambda_matrix) }}
steps:
- uses: actions/checkout@v6
- name: Set AppSpec paths
id: appspec
shell: bash
run: |
lambda_zip_key="lambdas/${{ inputs.lambda_version }}/${{ matrix.value }}.zip"
lambda_appspec_key="lambdas/${{ inputs.lambda_version }}/${{ matrix.value }}-appspec.zip"
echo "lambda_zip_key=$lambda_zip_key" >> $GITHUB_OUTPUT
echo "lambda_appspec_key=$lambda_appspec_key" >> $GITHUB_OUTPUT
- name: Get ${{ matrix.value }} infra
uses: ./.github/actions/terragrunt
id: get-infra
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
tg_directory: infra/live/${{ inputs.environment }}/aws/${{ matrix.value }}
tg_action: init
- name: Get infra detail
id: get_infra_detail
env:
TG_OUTPUTS: ${{ steps.get-infra.outputs.tg_outputs }}
run: |
echo "lambda_function_name=$(echo $TG_OUTPUTS | jq -r '.lambda_function_name.value')" >> $GITHUB_OUTPUT
echo "lambda_alias_name=$(echo $TG_OUTPUTS | jq -r '.lambda_alias_name.value')" >> $GITHUB_OUTPUT
- name: Publish new lambda version
id: publish
uses: ./.github/actions/just
env:
BUCKET_NAME: ${{ inputs.code_bucket }}
FUNCTION_NAME: ${{ steps.get_infra_detail.outputs.lambda_function_name }}
LAMBDA_ZIP_KEY: ${{ steps.appspec.outputs.lambda_zip_key }}
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
just_action: lambda-create-version
- name: Get current lambda version
id: get-version
uses: ./.github/actions/just
env:
FUNCTION_NAME: ${{ steps.get_infra_detail.outputs.lambda_function_name }}
ALIAS_NAME: ${{ steps.get_infra_detail.outputs.lambda_alias_name }}
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
just_action: lambda-get-version
- name: Run CodeDeploy
uses: ./.github/actions/just
env:
KEEP: ${{ inputs.lambda_keep }}
BUCKET_NAME: ${{ inputs.code_bucket }}
FUNCTION_NAME: ${{ steps.get_infra_detail.outputs.lambda_function_name }}
ALIAS_NAME: ${{ steps.get_infra_detail.outputs.lambda_alias_name }}
CURRENT_VERSION: ${{ steps.get-version.outputs.just_outputs }}
NEW_VERSION: ${{ steps.publish.outputs.just_outputs }}
APP_SPEC_FILE: ${{ github.workspace }}/appspec-lambda.yml
APP_SPEC_KEY: ${{ steps.appspec.outputs.lambda_appspec_key }}
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
just_action: lambda-upload-bundle lambda-set-code-deploy-alarms lambda-deploy lambda-prune
migrations:
runs-on: ubuntu-latest
needs: lambdas
steps:
- uses: actions/checkout@v6
- name: Skip when migrations is not in the lambda matrix
if: ${{ !contains(fromJson(inputs.lambda_matrix), 'migrations') }}
run: echo "No migrations Lambda in this deploy matrix."
- name: Get migrations infra
if: ${{ contains(fromJson(inputs.lambda_matrix), 'migrations') }}
uses: ./.github/actions/terragrunt
id: get-infra
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
tg_directory: infra/live/${{ inputs.environment }}/aws/migrations
tg_action: init
- name: Get migrations function name
if: ${{ contains(fromJson(inputs.lambda_matrix), 'migrations') }}
id: get_infra_detail
env:
TG_OUTPUTS: ${{ steps.get-infra.outputs.tg_outputs }}
run: |
echo "lambda_function_name=$(echo "$TG_OUTPUTS" | jq -r '.lambda_function_name.value')" >> "$GITHUB_OUTPUT"
- name: Run database migrations
if: ${{ contains(fromJson(inputs.lambda_matrix), 'migrations') }}
uses: ./.github/actions/just
env:
LAMBDA_NAME: ${{ steps.get_infra_detail.outputs.lambda_function_name }}
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
just_action: lambda-invoke
frontend:
runs-on: ubuntu-latest
if: ${{ inputs.frontend_version != '' }}
needs:
- lambdas
- ecs
steps:
- uses: actions/checkout@v6
- name: Get frontend infra
uses: ./.github/actions/terragrunt
id: get-infra
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
tg_directory: infra/live/${{ inputs.environment }}/aws/frontend
tg_action: init
- name: Get infra detail
id: get_infra_detail
env:
TG_OUTPUTS: ${{ steps.get-infra.outputs.tg_outputs }}
run: |
echo "website_bucket=$(echo $TG_OUTPUTS | jq -r '.bucket_name.value')" >> $GITHUB_OUTPUT
echo "distribution_id=$(echo $TG_OUTPUTS | jq -r '.cloudfront_distribution_id.value')" >> $GITHUB_OUTPUT
- name: Deploy frontend
uses: ./.github/actions/just
env:
BUCKET_NAME: ${{ inputs.code_bucket }}
VERSION: ${{ inputs.frontend_version }}
WEBSITE_BUCKET: ${{ steps.get_infra_detail.outputs.website_bucket }}
DISTRIBUTION_ID: ${{ steps.get_infra_detail.outputs.distribution_id }}
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
just_action: frontend-deploy frontend-invalidate
tasks:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
value: ${{ fromJson(inputs.task_matrix) }}
steps:
- uses: actions/checkout@v6
- name: Resolve image URIs
id: image_uris
env:
ECS_IMAGE_URIS: ${{ inputs.ecs_image_uris }}
TASK_NAME: ${{ matrix.value }}
uses: ./.github/actions/just
with:
just_action: ecs-task-get-image-uris
- name: Set image outputs
id: task_inputs
env:
IMAGE_URIS_JSON: ${{ steps.image_uris.outputs.just_outputs }}
run: |
echo "service_image_uri=$(echo "$IMAGE_URIS_JSON" | jq -r '.service_image_uri')" >> "$GITHUB_OUTPUT"
echo "debug_image_uri=$(echo "$IMAGE_URIS_JSON" | jq -r '.debug_image_uri')" >> "$GITHUB_OUTPUT"
echo "otel_image_uri=$(echo "$IMAGE_URIS_JSON" | jq -r '.otel_image_uri')" >> "$GITHUB_OUTPUT"
- name: Deploy ${{ matrix.value }} ECS task
uses: ./.github/actions/terragrunt
env:
TF_VAR_image_uri: ${{ steps.task_inputs.outputs.service_image_uri }}
TF_VAR_debug_image_uri: ${{ steps.task_inputs.outputs.debug_image_uri }}
TF_VAR_aws_otel_collector_image_uri: ${{ steps.task_inputs.outputs.otel_image_uri }}
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
tg_directory: infra/live/${{ inputs.environment }}/aws/task_${{ matrix.value }}
ecs:
runs-on: ubuntu-latest
needs: tasks
strategy:
fail-fast: false
matrix:
value: ${{ fromJson(inputs.task_matrix) }}
steps:
- uses: actions/checkout@v6
- name: Get ${{ matrix.value }} task infra
uses: ./.github/actions/terragrunt
id: get-task-infra
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
tg_directory: infra/live/${{ inputs.environment }}/aws/task_${{ matrix.value }}
tg_action: init
- name: Get ${{ matrix.value }} task outputs
id: get-task-outputs
env:
TG_OUTPUTS: ${{ steps.get-task-infra.outputs.tg_outputs }}
run: |
echo "task_definition_arn=$(echo "$TG_OUTPUTS" | jq -r '.task_definition_arn.value')" >> "$GITHUB_OUTPUT"
echo "container_name=$(echo "$TG_OUTPUTS" | jq -r '.service_name.value')" >> "$GITHUB_OUTPUT"
- name: Get ${{ matrix.value }} service infra
uses: ./.github/actions/terragrunt
id: get-service-infra
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
tg_directory: infra/live/${{ inputs.environment }}/aws/service_${{ matrix.value }}
tg_action: init
- name: Get ${{ matrix.value }} service outputs
id: get-service-outputs
env:
SERVICE_OUTPUTS: ${{ steps.get-service-infra.outputs.tg_outputs }}
run: |
echo "service_name=$(echo "$SERVICE_OUTPUTS" | jq -r '.service_name.value')" >> "$GITHUB_OUTPUT"
echo "cluster_name=$(echo "$SERVICE_OUTPUTS" | jq -r '.cluster_name.value')" >> "$GITHUB_OUTPUT"
echo "container_port=$(echo "$SERVICE_OUTPUTS" | jq -r '.container_port.value')" >> "$GITHUB_OUTPUT"
echo "codedeploy_app_name=$(echo "$SERVICE_OUTPUTS" | jq -r '.codedeploy_app_name.value')" >> "$GITHUB_OUTPUT"
echo "codedeploy_group_name=$(echo "$SERVICE_OUTPUTS" | jq -r '.codedeploy_deployment_group_name.value')" >> "$GITHUB_OUTPUT"
echo "app_spec_key=ecs/${{ inputs.environment }}/${{ matrix.value }}-$(echo "${{ steps.get-task-outputs.outputs.task_definition_arn }}" | awk -F: '{print $NF}').yml" >> "$GITHUB_OUTPUT"
- name: Work out ECS deployment mode
id: deploy_mode
env:
CODE_DEPLOY_APP_NAME: ${{ steps.get-service-outputs.outputs.codedeploy_app_name }}
CODE_DEPLOY_GROUP_NAME: ${{ steps.get-service-outputs.outputs.codedeploy_group_name }}
run: |
if [[ -n "$CODE_DEPLOY_APP_NAME" && "$CODE_DEPLOY_APP_NAME" != "null" && -n "$CODE_DEPLOY_GROUP_NAME" && "$CODE_DEPLOY_GROUP_NAME" != "null" ]]; then
echo "mode=codedeploy" >> "$GITHUB_OUTPUT"
else
echo "mode=rolling" >> "$GITHUB_OUTPUT"
fi
- name: Upload ECS AppSpec bundle
if: ${{ steps.deploy_mode.outputs.mode == 'codedeploy' }}
uses: ./.github/actions/just
env:
BUCKET_NAME: ${{ inputs.code_bucket }}
APP_SPEC_FILE: ${{ github.workspace }}/appspec-ecs.rendered.yml
APP_SPEC_KEY: ${{ steps.get-service-outputs.outputs.app_spec_key }}
TASK_DEFINITION_ARN: ${{ steps.get-task-outputs.outputs.task_definition_arn }}
CONTAINER_NAME: ${{ steps.get-task-outputs.outputs.container_name }}
CONTAINER_PORT: ${{ steps.get-service-outputs.outputs.container_port }}
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
just_action: ecs-upload-bundle
- name: Run ECS CodeDeploy
if: ${{ steps.deploy_mode.outputs.mode == 'codedeploy' }}
uses: ./.github/actions/just
env:
BUCKET_NAME: ${{ inputs.code_bucket }}
APP_SPEC_KEY: ${{ steps.get-service-outputs.outputs.app_spec_key }}
CODE_DEPLOY_APP_NAME: ${{ steps.get-service-outputs.outputs.codedeploy_app_name }}
CODE_DEPLOY_GROUP_NAME: ${{ steps.get-service-outputs.outputs.codedeploy_group_name }}
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
just_action: ecs-deploy
- name: Run ECS rolling deploy
if: ${{ steps.deploy_mode.outputs.mode == 'rolling' }}
uses: ./.github/actions/just
env:
CLUSTER_NAME: ${{ steps.get-service-outputs.outputs.cluster_name }}
SERVICE_NAME: ${{ steps.get-service-outputs.outputs.service_name }}
TASK_DEFINITION_ARN: ${{ steps.get-task-outputs.outputs.task_definition_arn }}
with:
aws_oidc_role_arn: ${{ env.AWS_OIDC_ROLE_ARN }}
just_action: ecs-rolling-deploy