Skip to content

Commit 7099fd5

Browse files
committed
update deploy-ecs, made keys explicit
1 parent a06ad37 commit 7099fd5

File tree

4 files changed

+251
-50
lines changed

4 files changed

+251
-50
lines changed

.github/workflows/appspec.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: 1
2+
Resources:
3+
- TargetService:
4+
Type: 'AWS::ECS::Service'
5+
Properties:
6+
# Placeholder text - gets replaced when pipeline runs
7+
TaskDefinition: '<TASK_DEFINITION>'
8+
LoadBalancerInfo:
9+
ContainerName: app-server
10+
ContainerPort: 8080
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Deploy to staging-alt3
2+
3+
concurrency:
4+
group: ${{ github.ref }}
5+
cancel-in-progress: true
6+
7+
on:
8+
push:
9+
branches:
10+
- staging-alt3
11+
12+
jobs:
13+
deploy:
14+
name: Deploy
15+
uses: ./.github/workflows/deploy-ecs.yml
16+
with:
17+
environment: 'staging'
18+
environment-site-name: 'staging-alt3'
19+
shortEnv: 'prod'
20+
ecs-cpu: 1024
21+
ecs-memory: 2048
22+
aws-region: 'ap-southeast-1'
23+
aws-account-id: '205930608298'
24+
cicd-role: 'arn:aws:iam::205930608298:role/formsg-stg-alt3-github-oidc-role'
25+
codedeploy-application: 'formsg-ecs-app'
26+
codedeploy-appspec-path: deploy/appspec.yml
27+
codedeploy-deployment-group: 'formsg-ecs-dg'
28+
ecr-repository: 'formsg'
29+
ecs-cluster-name: 'formsg-ecs'
30+
ecs-service-name: 'formsg-ecs-service'
31+
ecs-task-definition: 'formsg'
32+
ecs-task-definition-path: 'deploy/task-definition-production.json'
33+
ecs-container-name: 'app-server'
34+
app-version: ${{ github.sha }}
35+
dd-sample-rate: 100
36+
app-url: 'https://staging-alt3.form.gov.sg'
37+
react-app-form-sg-sdk-mode: 'staging'
38+
dd-env: 'staging-alt3'
39+
dd-rum-client-token: 'pub30d7ad4705b1bbb6d6bb60b4ac23f789'
40+
ga-tracking-id: 'UA-130216930-3'
41+
dd-rum-app-id: '95d75367-83a9-47f0-b2ab-cd91a253fcb5'
42+
43+
secrets:
44+
DD_API_KEY: ${{ secrets.DD_API_KEY }}

.github/workflows/deploy-ecs.yml

Lines changed: 143 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,128 @@ on:
33
push:
44
branches:
55
- staging-alt3
6+
workflow_call:
7+
inputs:
8+
environment:
9+
description: 'Deployment environment'
10+
required: true
11+
type: string
12+
environment-site-name:
13+
description: 'Deployment environment site name'
14+
required: true
15+
type: string # staging, staging-alt, staging-alt2, staging-alt3, prod, uat
16+
shortEnv:
17+
description: 'Deployment environment, the short version (one of [dev, prod, stg, test, uat, vapt])'
18+
required: true
19+
type: string
20+
ecs-cpu:
21+
description: 'ECS CPU units to use'
22+
required: true
23+
type: number
24+
ecs-memory:
25+
description: 'ECS memory to use'
26+
required: true
27+
type: number
28+
aws-account-id:
29+
description: 'AWS account ID to use'
30+
required: true
31+
type: string
32+
aws-region:
33+
description: 'AWS region to use'
34+
required: true
35+
default: 'ap-southeast-1'
36+
type: string
37+
cicd-role:
38+
description: 'AWS IAM role to assume by GitHub action runner'
39+
required: true
40+
type: string
41+
ecr-repository:
42+
description: 'ECR repository to push image to'
43+
required: true
44+
type: string
45+
ecs-cluster-name:
46+
description: 'ECS cluster to deploy to'
47+
required: true
48+
type: string
49+
ecs-task-definition:
50+
description: 'ECS task definition to use'
51+
required: true
52+
type: string
53+
ecs-task-definition-path:
54+
description: 'ECS task definition path'
55+
default: 'ecs-task-definition.json'
56+
type: string
57+
ecs-service-name:
58+
description: 'ECS service to deploy to'
59+
required: true
60+
type: string
61+
ecs-container-name:
62+
description: 'Name of container in ECS task definition'
63+
required: true
64+
type: string
65+
codedeploy-application:
66+
description: 'CodeDeploy application to use'
67+
required: true
68+
type: string
69+
codedeploy-appspec-path:
70+
description: 'CodeDeploy appspec.json/yml file path'
71+
default: 'appspec.json'
72+
type: string
73+
codedeploy-deployment-group:
74+
description: 'CodeDeploy deployment group to use'
75+
required: true
76+
type: string
77+
app-version:
78+
description: 'Version of the app'
79+
required: true
80+
type: string
81+
app-url:
82+
description: 'app url for the frontend'
83+
required: true
84+
type: string
85+
react-app-form-sg-sdk-mode:
86+
description: 'FormSG SDK mode'
87+
required: true
88+
type: string
89+
dd-env:
90+
description: 'Datadog environment'
91+
required: true
92+
type: string
93+
dd-sample-rate:
94+
description: 'Datadog sample rate'
95+
required: true
96+
type: number
97+
dd-rum-client-token:
98+
description: 'Datadog RUM client token'
99+
required: true
100+
type: string
101+
ga-tracking-id:
102+
description: 'Google Analytics tracking ID'
103+
required: true
104+
type: string
105+
dd-rum-app-id:
106+
description: 'Datadog RUM app ID'
107+
required: true
108+
type: string
109+
110+
secrets:
111+
DD_API_KEY:
112+
description: 'Datadog API key'
113+
required: true
6114

7115
# used to configure IAM to trust Github's OIDC provider
8116
permissions:
9117
id-token: write
10118
contents: read
11119

12120
jobs:
13-
set_environment:
14-
name: Set environment for deployment
15-
# Sets the environment for the deployment, which is the same as the branch name
16-
outputs:
17-
current_env: ${{ steps.set_environment.outputs.current_env }}
18-
runs-on: ubuntu-latest
19-
steps:
20-
- id: set_environment
21-
run: echo "current_env=${{github.ref_name}}" >> $GITHUB_OUTPUT
22-
23121
deploy:
24122
name: Deploy to ECS
25-
needs: set_environment
26123
runs-on: ubuntu-latest
27-
environment: ${{ needs.set_environment.outputs.current_env }}
124+
environment: ${{ inputs.environment }}
28125
env:
29-
IMAGE_TAG: github-actions-${{ github.sha }}-${{ github.run_id }}-${{github.run_attempt}}
30-
CURRENT_ENV: ${{ needs.set_environment.outputs.current_env }}
126+
IMAGE_TAG: github-actions-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
127+
CURRENT_ENV: ${{ inputs.environment }}
31128
steps:
32129
- name: Checkout branch source code into runner environment
33130
# Required for the frontend build env vars
@@ -41,16 +138,16 @@ jobs:
41138
42139
- name: Inject frontend build env vars
43140
env:
44-
VITE_APP_DD_RUM_APP_ID: ${{ secrets.DD_RUM_APP_ID }}
45-
VITE_APP_DD_RUM_CLIENT_TOKEN: ${{ secrets.DD_RUM_CLIENT_TOKEN }}
46-
VITE_APP_DD_RUM_ENV: ${{ secrets.DD_ENV }}
47-
VITE_APP_DD_SAMPLE_RATE: ${{ secrets.DD_SAMPLE_RATE }}
48-
VITE_APP_GA_TRACKING_ID: ${{ secrets.GA_TRACKING_ID }}
49-
VITE_APP_FORMSG_SDK_MODE: ${{ secrets.REACT_APP_FORMSG_SDK_MODE }}
50-
VITE_APP_URL: ${{ secrets.APP_URL }}
141+
VITE_APP_DD_RUM_APP_ID: ${{ inputs.dd-rum-app-id }}
142+
VITE_APP_DD_RUM_CLIENT_TOKEN: ${{ inputs.dd-rum-client-token }}
143+
VITE_APP_DD_RUM_ENV: ${{ inputs.dd-env }}
144+
VITE_APP_DD_SAMPLE_RATE: ${{ inputs.dd-sample-rate }}
145+
VITE_APP_GA_TRACKING_ID: ${{ inputs.ga-tracking-id }}
146+
VITE_APP_FORMSG_SDK_MODE: ${{ inputs.react-app-form-sg-sdk-mode }}
147+
VITE_APP_URL: ${{ inputs.app-url }}
51148
run: |
52-
sed -i -e "s|@VITE_APP_URL|${{secrets.APP_URL}}|g" -e "s/@VITE_APP_DD_RUM_APP_ID/$VITE_APP_DD_RUM_APP_ID/g" -e "s/@VITE_APP_DD_RUM_CLIENT_TOKEN/$VITE_APP_DD_RUM_CLIENT_TOKEN/g" -e "s/@VITE_APP_DD_RUM_ENV/$VITE_APP_DD_RUM_ENV/g" -e "s/@VITE_APP_VERSION/${{env.APP_VERSION}}/g" -e "s/@VITE_APP_DD_SAMPLE_RATE/$VITE_APP_DD_SAMPLE_RATE/g" frontend/datadog-chunk.ts
53-
echo VITE_APP_VERSION=${{env.APP_VERSION}} > frontend/.env
149+
sed -i -e "s|@VITE_APP_URL|${{ env.VITE_APP_URL }}|g" -e "s/@VITE_APP_DD_RUM_APP_ID/$VITE_APP_DD_RUM_APP_ID/g" -e "s/@VITE_APP_DD_RUM_CLIENT_TOKEN/$VITE_APP_DD_RUM_CLIENT_TOKEN/g" -e "s/@VITE_APP_DD_RUM_ENV/$VITE_APP_DD_RUM_ENV/g" -e "s/@VITE_APP_VERSION/${{env.APP_VERSION}}/g" -e "s/@VITE_APP_DD_SAMPLE_RATE/$VITE_APP_DD_SAMPLE_RATE/g" frontend/datadog-chunk.ts
150+
echo VITE_APP_VERSION=${{ inputs.app-version }} > frontend/.env
54151
echo VITE_APP_URL=$VITE_APP_URL > frontend/.env
55152
echo VITE_APP_GA_TRACKING_ID=$VITE_APP_GA_TRACKING_ID >> frontend/.env
56153
echo VITE_APP_FORMSG_SDK_MODE=$VITE_APP_FORMSG_SDK_MODE >> frontend/.env
@@ -60,11 +157,9 @@ jobs:
60157
- name: Configure AWS credentials
61158
# Configures the runner environment with AWS credentials
62159
uses: aws-actions/configure-aws-credentials@v4
63-
env:
64-
AWS_REGION: ${{ secrets.DEFAULT_AWS_REGION }}
65160
with:
66-
role-to-assume: ${{ secrets.AWS_CI_ROLE_TO_ASSUME }}
67-
aws-region: ${{ env.AWS_REGION }}
161+
role-to-assume: ${{ inputs.cicd-role }}
162+
aws-region: ${{ inputs.aws-region }}
68163

69164
- name: Login to Amazon ECR
70165
id: login-ecr
@@ -78,7 +173,7 @@ jobs:
78173
env:
79174
DD_API_KEY: ${{ secrets.DD_API_KEY }}
80175
DD_ENV: ${{ secrets.DD_ENV }}
81-
ECR_REPOSITORY: ${{ secrets.ECR_REPO }}-${{ env.CURRENT_ENV }}
176+
ECR_REPOSITORY: ${{ inputs.ecr-repository }}
82177
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
83178
with:
84179
context: .
@@ -88,36 +183,45 @@ jobs:
88183
${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}
89184
${{ github.sha }}
90185
build-args: |
91-
APP_VERSION=${{ env.APP_VERSION }}
92-
APP_URL=${{ secrets.APP_URL }}
186+
APP_VERSION=${{ inputs.app-version }}
187+
APP_URL=${{ inputs.app-url }}
93188
REPO_URL=${{ github.server_url }}/${{ github.repository }}
94189
secrets: |
95190
"dd_api_key=${{ secrets.DD_API_KEY }}"
96191
192+
193+
- name: Replace variables in task definition file
194+
id: replace-variables
195+
run: |
196+
sed -i 's/<AWS_ACCOUNT_ID>/${{ inputs.aws-account-id }}/g' ${{ inputs.ecs-task-definition-path }}
197+
sed -i 's/<ENV>/${{ inputs.environment }}/g' ${{ inputs.ecs-task-definition-path }}
198+
sed -i 's/<SHORT_ENV>/${{ inputs.shortEnv }}/g' ${{ inputs.ecs-task-definition-path }}
199+
sed -i 's/<CPU>/${{ inputs.ecs-cpu }}/g' ${{ inputs.ecs-task-definition-path }}
200+
sed -i 's/<MEMORY>/${{ inputs.ecs-memory }}/g' ${{ inputs.ecs-task-definition-path }}
201+
97202
- name: Fill in the new image ID in the Amazon ECS task definition
98203
# Create a new task definition file with the image to be deployed
99204
id: task-def
100205
env:
101206
ECS_TASK_DEFINITION: ecs-task-definition.json
207+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
102208
CONTAINER_NAME: formsg-app
103209
uses: aws-actions/amazon-ecs-render-task-definition@c804dfbdd57f713b6c079302a4c01db7017a36fc
104210
with:
105-
task-definition: ${{ env.ECS_TASK_DEFINITION }}
211+
task-definition: ${{ inputs.ecs-task-definition-path }}
106212
container-name: ${{ env.CONTAINER_NAME }}
107-
image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}
213+
image: ${{ steps.login-ecr.outputs.registry }}/${{ inputs.ecr-repository }}:${{ env.IMAGE_TAG }}
214+
# TODO: check again if ENV_SITE_NAME is still required
108215
environment-variables: |
109-
ENV_TYPE=${{ contains(env.CURRENT_ENV, 'staging') && 'staging' || contains(env.CURRENT_ENV, 'prod') && 'prod' || contains(env.CURRENT_ENV, 'uat') && 'uat' || env.CURRENT_ENV }}
110-
ENV_SITE_NAME=${{ env.CURRENT_ENV }}
216+
ENV_TYPE=${{ inputs.environment }}
217+
ENV_SITE_NAME=${{ inputs.environment-site-name }}
111218
112219
- name: Deploy Amazon ECS task definition
113-
env: # For ECS deployment
114-
ECS_SERVICE: ${{ secrets.ECS_SERVICE }}
115-
ECS_CLUSTER: ${{ secrets.ECS_CLUSTER }}
116220
uses: aws-actions/amazon-ecs-deploy-task-definition@df9643053eda01f169e64a0e60233aacca83799a
117221
with:
118222
task-definition: ${{ steps.task-def.outputs.task-definition }}
119-
service: ${{ env.ECS_SERVICE }}
120-
cluster: ${{ env.ECS_CLUSTER }}
223+
service: ${{ inputs.ecs-service-name }}
224+
cluster: ${{ inputs.ecs-cluster-name }}
121225
wait-for-service-stability: true
122226
codedeploy-appspec: ${{ inputs.codedeploy-appspec-path }}
123227
codedeploy-application: ${{ inputs.codedeploy-application }}

ecs-task-definition.json

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,60 @@
1-
2-
{
1+
{
32
"containerDefinitions": [
43
{
54
"name": "formsg-app",
65
"essential": true,
7-
"command": "/bin/sh -c \"./generate-env-from-ecs-params.sh && npm start\"",
6+
"#command": "/bin/sh -c \"./generate-env-from-ecs-params.sh && npm start\"",
87
"portMappings": [
9-
{ "containerPort": 3000 }
10-
]
8+
{ "containerPort": 4545, "hostPort": 4545, "protocol": "tcp" }
9+
],
10+
"logConfiguration": {
11+
"logDriver": "awslogs",
12+
"options": {
13+
"awslogs-group": "formsg/ecs/formsg-app",
14+
"awslogs-region": "ap-southeast-1",
15+
"awslogs-stream-prefix": "ecs"
16+
}
17+
}
18+
},
19+
{
20+
"name": "dd-agent",
21+
"image": "public.ecr.aws/datadog/agent:latest",
22+
"portMappings": [
23+
{ "containerPort": 8126, "hostPort": 8126, "protocol": "tcp" }
24+
],
25+
"essential": true,
26+
"environment": [
27+
{ "name": "TZ", "value": "Asia/Singapore" },
28+
{ "name": "DD_APM_NON_LOCAL_TRAFFIC", "value": "true" },
29+
{ "name": "ECS_FARGATE", "value": "true" },
30+
{ "name": "DD_APM_ENABLED", "value": "true" },
31+
{ "name": "DD_SITE", "value": "datadoghq.com" }
32+
],
33+
"mountPoints": [],
34+
"volumesFrom": [],
35+
"secrets": [
36+
{ "name": "DD_API_KEY", "valueFrom": "/<ENV>/DD_API_KEY" },
37+
{ "name": "DD_SERVICE", "valueFrom": "/<ENV>/DD_SERVICE" },
38+
{ "name": "DD_TAGS", "valueFrom": "/<ENV>/DD_TAGS" }
39+
],
40+
"logConfiguration": {
41+
"logDriver": "awslogs",
42+
"options": {
43+
"awslogs-group": "formsg/ecs/app-server-dd-agent",
44+
"awslogs-region": "ap-southeast-1",
45+
"awslogs-stream-prefix": "ecs"
46+
}
47+
}
1148
}
12-
],
13-
"family": "formsg-app",
14-
"requiresCompatibilities": [
15-
"FARGATE"
16-
]
17-
}
49+
],
50+
"family": "formsg-app",
51+
"requiresCompatibilities": ["FARGATE"],
52+
"networkMode": "awsvpc",
53+
"volumes": [],
54+
"placementConstraints": [],
55+
"runtimePlatform": { "operatingSystemFamily": "LINUX" },
56+
"taskRoleArn": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/formsg-ecs-task-role",
57+
"executionRoleArn": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/formsg-ecs-task-exec-role",
58+
"cpu": "<CPU>",
59+
"memory": "<MEMORY>"
60+
}

0 commit comments

Comments
 (0)