Skip to content

Commit 53c33e2

Browse files
Replace deploy-application code
- Use new flow - Intermediary step for testing process
1 parent 5620df4 commit 53c33e2

File tree

6 files changed

+310
-384
lines changed

6 files changed

+310
-384
lines changed

.github/workflows/deploy-application.yml

Lines changed: 196 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ on:
2525
- web
2626
- good-job
2727
default: all
28+
git_sha_to_deploy:
29+
description: The git commit SHA to deploy.
30+
required: false
31+
type: string
2832
workflow_call:
2933
inputs:
3034
environment:
@@ -38,15 +42,21 @@ on:
3842
required: true
3943
type: string
4044

41-
permissions: {}
45+
permissions: { }
4246

4347
concurrency:
44-
group: deploy-application-${{ inputs.environment }}
48+
group: deploy-mavis-${{ inputs.environment }}
4549

4650
env:
4751
aws-role: ${{ inputs.environment == 'production'
4852
&& 'arn:aws:iam::820242920762:role/GithubDeployMavisAndInfrastructure'
4953
|| 'arn:aws:iam::393416225559:role/GithubDeployMavisAndInfrastructure' }}
54+
web_codedeploy_application: mavis-${{ inputs.environment }}
55+
web_codedeploy_group: blue-green-group-${{ inputs.environment }}
56+
web_task_definition: mavis-web-task-definition-${{ inputs.environment }}
57+
cluster_name: mavis-${{ inputs.environment }}
58+
good_job_service: mavis-${{ inputs.environment }}-good-job
59+
good_job_task_definition: mavis-good-job-task-definition-${{ inputs.environment }}
5060

5161
jobs:
5262
prepare-deployment:
@@ -58,109 +68,234 @@ jobs:
5868
steps:
5969
- name: Checkout code
6070
uses: actions/checkout@v4
61-
with:
62-
ref: ${{ inputs.git_sha_to_deploy || github.sha }}
6371
- name: Configure AWS Credentials
6472
uses: aws-actions/configure-aws-credentials@v4
6573
with:
6674
role-to-assume: ${{ env.aws-role }}
6775
aws-region: eu-west-2
68-
- name: Install terraform
69-
uses: hashicorp/setup-terraform@v3
70-
with:
71-
terraform_version: 1.11.4
72-
- name: Get terraform output
73-
id: terraform-output
74-
working-directory: terraform/app
76+
- name: Get image digest from ECR
77+
id: get-image-digest
78+
run: |
79+
# Get AWS account ID and construct repository URI
80+
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
81+
REPOSITORY_URI="${AWS_ACCOUNT_ID}.dkr.ecr.eu-west-2.amazonaws.com/mavis"
82+
83+
# Get the image digest for the git SHA
84+
IMAGE_DIGEST=$(aws ecr describe-images \
85+
--repository-name mavis/webapp \
86+
--image-ids imageTag=${{ inputs.git_sha_to_deploy || github.sha }} \
87+
--query 'imageDetails[0].imageDigest' \
88+
--output text)
89+
90+
NEW_IMAGE_URI="${REPOSITORY_URI}@${IMAGE_DIGEST}"
91+
echo "new-image-uri=${NEW_IMAGE_URI}" >> $GITHUB_OUTPUT
92+
echo "New image URI: ${NEW_IMAGE_URI}"
93+
# - name: Get dynamic variables for web
94+
# id: get-dynamic-vars-web
95+
# if: inputs.server_types == 'web' || inputs.server_types == 'all'
96+
# run: |
97+
# # Fetch SSM parameter for web service
98+
# SSM_OUTPUT=$(aws ssm get-parameter --name /${{ inputs.environment }}/ecs/web/container_variables --query Parameter.Value --output text)
99+
#
100+
# # Extract environment variables in the format expected by amazon-ecs-render-task-definition
101+
# ENV_VARS=$(echo "$SSM_OUTPUT" | jq -r '.task_envs | map("'"'"'\(.name)=\(.value)'"'"'") | join("\n")')
102+
#
103+
# # Extract secrets in the format expected by amazon-ecs-render-task-definition
104+
# SECRETS=$(echo "$SSM_OUTPUT" | jq -r '.task_secrets | map("'"'"'\(.name)=\(.valueFrom)'"'"'") | join("\n")')
105+
#
106+
# # Set outputs using multiline format
107+
# echo "environment-variables<<EOF" >> $GITHUB_OUTPUT
108+
# echo "$ENV_VARS" >> $GITHUB_OUTPUT
109+
# echo "EOF" >> $GITHUB_OUTPUT
110+
#
111+
# echo "secrets<<EOF" >> $GITHUB_OUTPUT
112+
# echo "$SECRETS" >> $GITHUB_OUTPUT
113+
# echo "EOF" >> $GITHUB_OUTPUT
114+
#
115+
# # Also extract role ARNs for potential future use
116+
# EXECUTION_ROLE_ARN=$(echo "$SSM_OUTPUT" | jq -r '.execution_role_arn')
117+
# TASK_ROLE_ARN=$(echo "$SSM_OUTPUT" | jq -r '.task_role_arn')
118+
#
119+
# echo "execution-role-arn=$EXECUTION_ROLE_ARN" >> $GITHUB_OUTPUT
120+
# echo "task-role-arn=$TASK_ROLE_ARN" >> $GITHUB_OUTPUT
121+
#
122+
# echo "Environment variables:"
123+
# echo "$ENV_VARS"
124+
# echo ""
125+
# echo "Secrets:"
126+
# echo "$SECRETS"
127+
# - name: Get dynamic variables for good-job
128+
# id: get-dynamic-vars-good-job
129+
# if: inputs.server_types == 'good-job' || inputs.server_types == 'all'
130+
# run: |
131+
# # Fetch SSM parameter for good-job service
132+
# SSM_OUTPUT=$(aws ssm get-parameter --name /${{ inputs.environment }}/ecs/good-job/container_variables --query Parameter.Value --output text)
133+
#
134+
# # Extract environment variables in the format expected by amazon-ecs-render-task-definition
135+
# ENV_VARS=$(echo "$SSM_OUTPUT" | jq -r '.task_envs | map("'"'"'\(.name)=\(.value)'"'"'") | join("\n")')
136+
#
137+
# # Extract secrets in the format expected by amazon-ecs-render-task-definition
138+
# SECRETS=$(echo "$SSM_OUTPUT" | jq -r '.task_secrets | map("'"'"'\(.name)=\(.valueFrom)'"'"'") | join("\n")')
139+
#
140+
# # Set outputs using multiline format
141+
# echo "environment-variables<<EOF" >> $GITHUB_OUTPUT
142+
# echo "$ENV_VARS" >> $GITHUB_OUTPUT
143+
# echo "EOF" >> $GITHUB_OUTPUT
144+
#
145+
# echo "secrets<<EOF" >> $GITHUB_OUTPUT
146+
# echo "$SECRETS" >> $GITHUB_OUTPUT
147+
# echo "EOF" >> $GITHUB_OUTPUT
148+
#
149+
# # Also extract role ARNs for potential future use
150+
# EXECUTION_ROLE_ARN=$(echo "$SSM_OUTPUT" | jq -r '.execution_role_arn')
151+
# TASK_ROLE_ARN=$(echo "$SSM_OUTPUT" | jq -r '.task_role_arn')
152+
#
153+
# echo "execution-role-arn=$EXECUTION_ROLE_ARN" >> $GITHUB_OUTPUT
154+
# echo "task-role-arn=$TASK_ROLE_ARN" >> $GITHUB_OUTPUT
155+
#
156+
# echo "Environment variables:"
157+
# echo "$ENV_VARS"
158+
# echo ""
159+
# echo "Secrets:"
160+
# echo "$SECRETS"
161+
- name: Populate web task definition
162+
if: inputs.server_types == 'web' || inputs.server_types == 'all'
163+
id: render-web-task-definition
75164
run: |
76-
set -e
77-
terraform init -backend-config=env/${{ inputs.environment }}-backend.hcl -reconfigure
78-
terraform output -json | jq -r '
79-
"s3_bucket=" + .s3_bucket.value,
80-
"s3_key=" + .s3_key.value,
81-
"application=" + .codedeploy_application_name.value,
82-
"application_group=" + .codedeploy_deployment_group_name.value,
83-
"cluster_name=" + .ecs_variables.value.cluster_name,
84-
"good_job_service=" + .ecs_variables.value.good_job.service_name,
85-
"good_job_task_definition=" + .ecs_variables.value.good_job.task_definition.arn
86-
' > ${{ runner.temp }}/DEPLOYMENT_ENVS
87-
- name: Upload Artifact
165+
chmod +x ./script/populate_task_definition.sh
166+
./script/populate_task_definition.sh ${{ inputs.environment }} web \
167+
-i "${{ steps.get-image-digest.outputs.new-image-uri }}" \
168+
-o web-task-definition.json
169+
echo "task-definition=web-task-definition.json" >> $GITHUB_OUTPUT
170+
- name: Populate good-job task definition
171+
if: inputs.server_types == 'good-job' || inputs.server_types == 'all'
172+
id: render-good-job-task-definition
173+
run: |
174+
chmod +x ./script/populate_task_definition.sh
175+
./script/populate_task_definition.sh ${{ inputs.environment }} good-job \
176+
-i "${{ steps.get-image-digest.outputs.new-image-uri }}" \
177+
-o good-job-task-definition.json
178+
echo "task-definition=good-job-task-definition.json" >> $GITHUB_OUTPUT
179+
- name: Upload web task definition artifact
180+
if: inputs.server_types == 'web' || inputs.server_types == 'all'
181+
uses: actions/upload-artifact@v4
182+
with:
183+
name: web-task-definition
184+
path: ${{ steps.render-web-task-definition.outputs.task-definition }}
185+
retention-days: 1
186+
- name: Upload good-job task definition artifact
187+
if: inputs.server_types == 'good-job' || inputs.server_types == 'all'
88188
uses: actions/upload-artifact@v4
89189
with:
90-
name: DEPLOYMENT_ENVS-${{ inputs.environment }}
91-
path: ${{ runner.temp }}/DEPLOYMENT_ENVS
190+
name: good-job-task-definition
191+
path: ${{ steps.render-good-job-task-definition.outputs.task-definition }}
192+
retention-days: 1
193+
outputs:
194+
new-image-uri: ${{ steps.get-image-digest.outputs.new-image-uri }}
195+
web-environment-variables: ${{ steps.get-dynamic-vars-web.outputs.environment-variables }}
196+
web-secrets: ${{ steps.get-dynamic-vars-web.outputs.secrets }}
197+
web-execution-role-arn: ${{ steps.get-dynamic-vars-web.outputs.execution-role-arn }}
198+
web-task-role-arn: ${{ steps.get-dynamic-vars-web.outputs.task-role-arn }}
199+
good-job-environment-variables: ${{ steps.get-dynamic-vars-good-job.outputs.environment-variables }}
200+
good-job-secrets: ${{ steps.get-dynamic-vars-good-job.outputs.secrets }}
201+
good-job-execution-role-arn: ${{ steps.get-dynamic-vars-good-job.outputs.execution-role-arn }}
202+
good-job-task-role-arn: ${{ steps.get-dynamic-vars-good-job.outputs.task-role-arn }}
92203

93-
create-web-deployment:
94-
name: Create web deployment
204+
deploy-web:
205+
name: Deploy web service
95206
runs-on: ubuntu-latest
96-
needs: prepare-deployment
97207
if: inputs.server_types == 'web' || inputs.server_types == 'all'
208+
needs: prepare-deployment
209+
environment: ${{ inputs.environment }}
98210
permissions:
99211
id-token: write
100212
steps:
101-
- name: Download artifact
102-
uses: actions/download-artifact@v4
103-
with:
104-
name: DEPLOYMENT_ENVS-${{ inputs.environment }}
105-
path: ${{ runner.temp }}
106213
- name: Configure AWS Credentials
107214
uses: aws-actions/configure-aws-credentials@v4
108215
with:
109216
role-to-assume: ${{ env.aws-role }}
110217
aws-region: eu-west-2
111-
- name: Trigger CodeDeploy deployment
218+
- name: Download web task definition artifact
219+
uses: actions/download-artifact@v4
220+
with:
221+
name: web-task-definition
222+
path: ./artifacts
223+
- name: Register new task definition
112224
run: |
113-
set -e
114-
source ${{ runner.temp }}/DEPLOYMENT_ENVS
225+
# Find the task definition file in the artifacts directory
226+
TASK_DEF_FILE=$(find ./artifacts -name "*.json" -type f | head -1)
227+
aws ecs register-task-definition --cli-input-json file://$TASK_DEF_FILE
228+
- name: Deploy with CodeDeploy
229+
run: |
230+
# Create CodeDeploy deployment for blue-green deployment
115231
deployment_id=$(aws deploy create-deployment \
116-
--application-name "$application" --deployment-group-name "$application_group" \
117-
--s3-location bucket="$s3_bucket",key="$s3_key",bundleType=yaml | jq -r .deploymentId)
118-
echo "Deployment started: $deployment_id"
232+
--application-name ${{ env.web_codedeploy_application }} \
233+
--deployment-group-name ${{ env.web_codedeploy_group }} \
234+
--deployment-config-name CodeDeployDefault.ECSBlueGreenCanary10Percent5Minutes \
235+
--description "Deployment from GitHub Actions" \
236+
| jq -r .deploymentId)
237+
238+
echo "CodeDeploy deployment started: $deployment_id"
119239
echo "deployment_id=$deployment_id" >> $GITHUB_ENV
120-
- name: Wait up to 30 minutes for deployment to complete
240+
- name: Wait for deployment to complete
121241
run: |
122-
set -e
242+
echo "Waiting for CodeDeploy deployment $deployment_id to complete..."
123243
aws deploy wait deployment-successful --deployment-id "$deployment_id"
124244
echo "Deployment successful"
125245
126-
create-good-job-deployment:
127-
name: Create good-job deployment
246+
deploy-good-job:
247+
name: Deploy good-job service
128248
runs-on: ubuntu-latest
129-
needs: prepare-deployment
130249
if: inputs.server_types == 'good-job' || inputs.server_types == 'all'
250+
needs: prepare-deployment
251+
environment: ${{ inputs.environment }}
131252
permissions:
132253
id-token: write
133254
steps:
134-
- name: Download Artifact
135-
uses: actions/download-artifact@v4
136-
with:
137-
name: DEPLOYMENT_ENVS-${{ inputs.environment }}
138-
path: ${{ runner.temp }}
139255
- name: Configure AWS Credentials
140256
uses: aws-actions/configure-aws-credentials@v4
141257
with:
142258
role-to-assume: ${{ env.aws-role }}
143259
aws-region: eu-west-2
144-
- name: Trigger ECS Deployment
260+
- name: Download good-job task definition artifact
261+
uses: actions/download-artifact@v4
262+
with:
263+
name: good-job-task-definition
264+
path: ./artifacts
265+
- name: Register new task definition
145266
run: |
146-
set -e
147-
source ${{ runner.temp }}/DEPLOYMENT_ENVS
148-
DEPLOYMENT_ID=$(aws ecs update-service --cluster $cluster_name --service $good_job_service \
149-
--task-definition $good_job_task_definition --force-new-deployment \
150-
--query 'service.deployments[?rolloutState==`IN_PROGRESS`].[id][0]' --output text)
151-
echo "Deployment started: $DEPLOYMENT_ID"
267+
# Find the task definition file in the artifacts directory
268+
TASK_DEF_FILE=$(find ./artifacts -name "*.json" -type f | head -1)
269+
TASK_DEFINITION_ARN=$(aws ecs register-task-definition --cli-input-json file://$TASK_DEF_FILE --query 'taskDefinition.taskDefinitionArn' --output text)
270+
echo "New task definition registered: $TASK_DEFINITION_ARN"
271+
echo "task_definition_arn=$TASK_DEFINITION_ARN" >> $GITHUB_ENV
272+
- name: Update ECS service
273+
run: |
274+
# Update the good-job service with the new task definition
275+
DEPLOYMENT_ID=$(aws ecs update-service \
276+
--cluster ${{ env.cluster_name }} \
277+
--service ${{ env.good_job_service }} \
278+
--task-definition "$task_definition_arn" \
279+
--force-new-deployment \
280+
--query 'service.deployments[?rolloutState==`IN_PROGRESS`].[id][0]' \
281+
--output text)
282+
283+
echo "ECS deployment started: $DEPLOYMENT_ID"
152284
echo "deployment_id=$DEPLOYMENT_ID" >> $GITHUB_ENV
153285
- name: Wait for deployment to complete
154286
run: |
155-
set -e
156-
source ${{ runner.temp }}/DEPLOYMENT_ENVS
287+
echo "Waiting for ECS deployment $deployment_id to complete..."
157288
DEPLOYMENT_STATE=IN_PROGRESS
158289
while [ "$DEPLOYMENT_STATE" == "IN_PROGRESS" ]; do
159-
echo "Waiting for deployment to complete..."
290+
echo "Checking deployment status..."
160291
sleep 30
161-
DEPLOYMENT_STATE="$(aws ecs describe-services --cluster $cluster_name --services $good_job_service \
162-
--query "services[0].deployments[?id == \`$deployment_id\`].[rolloutState][0]" --output text)"
292+
DEPLOYMENT_STATE=$(aws ecs describe-services \
293+
--cluster ${{ env.cluster_name }} \
294+
--services ${{ env.good_job_service }} \
295+
--query "services[0].deployments[?id == \`$deployment_id\`].[rolloutState][0]" \
296+
--output text)
163297
done
298+
164299
if [ "$DEPLOYMENT_STATE" != "COMPLETED" ]; then
165300
echo "Deployment failed with state: $DEPLOYMENT_STATE"
166301
exit 1

0 commit comments

Comments
 (0)