Deploy application to sandbox-alpha #42
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Deploy application | |
run-name: Deploy application to ${{ inputs.environment }} | |
on: | |
workflow_dispatch: | |
inputs: | |
environment: | |
description: Deployment environment | |
required: true | |
type: choice | |
options: | |
- qa | |
- test | |
- preview | |
- training | |
- production | |
- sandbox-alpha | |
- sandbox-beta | |
server_types: | |
description: Server types to deploy | |
required: true | |
type: choice | |
options: | |
- all | |
- web | |
- good-job | |
default: all | |
git_sha_to_deploy: | |
description: The git commit SHA to deploy. | |
required: false | |
type: string | |
workflow_call: | |
inputs: | |
environment: | |
required: true | |
type: string | |
server_types: | |
required: true | |
type: string | |
git_sha_to_deploy: | |
description: The git commit SHA to deploy. | |
required: true | |
type: string | |
permissions: { } | |
concurrency: | |
group: deploy-mavis-${{ inputs.environment }} | |
env: | |
aws-role: ${{ inputs.environment == 'production' | |
&& 'arn:aws:iam::820242920762:role/GithubDeployMavisAndInfrastructure' | |
|| 'arn:aws:iam::393416225559:role/GithubDeployMavisAndInfrastructure' }} | |
web_codedeploy_application: mavis-${{ inputs.environment }} | |
web_codedeploy_group: blue-green-group-${{ inputs.environment }} | |
web_task_definition: mavis-web-task-definition-${{ inputs.environment }} | |
cluster_name: mavis-${{ inputs.environment }} | |
good_job_service: mavis-${{ inputs.environment }}-good-job | |
good_job_task_definition: mavis-good-job-task-definition-${{ inputs.environment }} | |
jobs: | |
prepare-deployment: | |
name: Prepare deployment | |
runs-on: ubuntu-latest | |
environment: ${{ inputs.environment }} | |
permissions: | |
id-token: write | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Configure AWS Credentials | |
uses: aws-actions/configure-aws-credentials@v4 | |
with: | |
role-to-assume: ${{ env.aws-role }} | |
aws-region: eu-west-2 | |
- name: Get image digest from ECR | |
id: get-image-digest | |
run: | | |
# Get AWS account ID and construct repository URI | |
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) | |
REPOSITORY_URI="${AWS_ACCOUNT_ID}.dkr.ecr.eu-west-2.amazonaws.com/mavis" | |
# Get the image digest for the git SHA | |
IMAGE_DIGEST=$(aws ecr describe-images \ | |
--repository-name mavis/webapp \ | |
--image-ids imageTag=${{ inputs.git_sha_to_deploy || github.sha }} \ | |
--query 'imageDetails[0].imageDigest' \ | |
--output text) | |
NEW_IMAGE_URI="${REPOSITORY_URI}@${IMAGE_DIGEST}" | |
echo "new-image-uri=${NEW_IMAGE_URI}" >> $GITHUB_OUTPUT | |
echo "New image URI: ${NEW_IMAGE_URI}" | |
# - name: Get dynamic variables for web | |
# id: get-dynamic-vars-web | |
# if: inputs.server_types == 'web' || inputs.server_types == 'all' | |
# run: | | |
# # Fetch SSM parameter for web service | |
# SSM_OUTPUT=$(aws ssm get-parameter --name /${{ inputs.environment }}/ecs/web/container_variables --query Parameter.Value --output text) | |
# | |
# # Extract environment variables in the format expected by amazon-ecs-render-task-definition | |
# ENV_VARS=$(echo "$SSM_OUTPUT" | jq -r '.task_envs | map("'"'"'\(.name)=\(.value)'"'"'") | join("\n")') | |
# | |
# # Extract secrets in the format expected by amazon-ecs-render-task-definition | |
# SECRETS=$(echo "$SSM_OUTPUT" | jq -r '.task_secrets | map("'"'"'\(.name)=\(.valueFrom)'"'"'") | join("\n")') | |
# | |
# # Set outputs using multiline format | |
# echo "environment-variables<<EOF" >> $GITHUB_OUTPUT | |
# echo "$ENV_VARS" >> $GITHUB_OUTPUT | |
# echo "EOF" >> $GITHUB_OUTPUT | |
# | |
# echo "secrets<<EOF" >> $GITHUB_OUTPUT | |
# echo "$SECRETS" >> $GITHUB_OUTPUT | |
# echo "EOF" >> $GITHUB_OUTPUT | |
# | |
# # Also extract role ARNs for potential future use | |
# EXECUTION_ROLE_ARN=$(echo "$SSM_OUTPUT" | jq -r '.execution_role_arn') | |
# TASK_ROLE_ARN=$(echo "$SSM_OUTPUT" | jq -r '.task_role_arn') | |
# | |
# echo "execution-role-arn=$EXECUTION_ROLE_ARN" >> $GITHUB_OUTPUT | |
# echo "task-role-arn=$TASK_ROLE_ARN" >> $GITHUB_OUTPUT | |
# | |
# echo "Environment variables:" | |
# echo "$ENV_VARS" | |
# echo "" | |
# echo "Secrets:" | |
# echo "$SECRETS" | |
# - name: Get dynamic variables for good-job | |
# id: get-dynamic-vars-good-job | |
# if: inputs.server_types == 'good-job' || inputs.server_types == 'all' | |
# run: | | |
# # Fetch SSM parameter for good-job service | |
# SSM_OUTPUT=$(aws ssm get-parameter --name /${{ inputs.environment }}/ecs/good-job/container_variables --query Parameter.Value --output text) | |
# | |
# # Extract environment variables in the format expected by amazon-ecs-render-task-definition | |
# ENV_VARS=$(echo "$SSM_OUTPUT" | jq -r '.task_envs | map("'"'"'\(.name)=\(.value)'"'"'") | join("\n")') | |
# | |
# # Extract secrets in the format expected by amazon-ecs-render-task-definition | |
# SECRETS=$(echo "$SSM_OUTPUT" | jq -r '.task_secrets | map("'"'"'\(.name)=\(.valueFrom)'"'"'") | join("\n")') | |
# | |
# # Set outputs using multiline format | |
# echo "environment-variables<<EOF" >> $GITHUB_OUTPUT | |
# echo "$ENV_VARS" >> $GITHUB_OUTPUT | |
# echo "EOF" >> $GITHUB_OUTPUT | |
# | |
# echo "secrets<<EOF" >> $GITHUB_OUTPUT | |
# echo "$SECRETS" >> $GITHUB_OUTPUT | |
# echo "EOF" >> $GITHUB_OUTPUT | |
# | |
# # Also extract role ARNs for potential future use | |
# EXECUTION_ROLE_ARN=$(echo "$SSM_OUTPUT" | jq -r '.execution_role_arn') | |
# TASK_ROLE_ARN=$(echo "$SSM_OUTPUT" | jq -r '.task_role_arn') | |
# | |
# echo "execution-role-arn=$EXECUTION_ROLE_ARN" >> $GITHUB_OUTPUT | |
# echo "task-role-arn=$TASK_ROLE_ARN" >> $GITHUB_OUTPUT | |
# | |
# echo "Environment variables:" | |
# echo "$ENV_VARS" | |
# echo "" | |
# echo "Secrets:" | |
# echo "$SECRETS" | |
- name: Populate web task definition | |
if: inputs.server_types == 'web' || inputs.server_types == 'all' | |
id: render-web-task-definition | |
run: | | |
./script/populate_task_definition.sh ${{ inputs.environment }} web \ | |
-i "${{ steps.get-image-digest.outputs.new-image-uri }}" \ | |
-o web-task-definition.json | |
echo "task-definition=web-task-definition.json" >> $GITHUB_OUTPUT | |
- name: Populate good-job task definition | |
if: inputs.server_types == 'good-job' || inputs.server_types == 'all' | |
id: render-good-job-task-definition | |
run: | | |
./script/populate_task_definition.sh ${{ inputs.environment }} good-job \ | |
-i "${{ steps.get-image-digest.outputs.new-image-uri }}" \ | |
-o good-job-task-definition.json | |
echo "task-definition=good-job-task-definition.json" >> $GITHUB_OUTPUT | |
- name: Upload web task definition artifact | |
if: inputs.server_types == 'web' || inputs.server_types == 'all' | |
uses: actions/upload-artifact@v4 | |
with: | |
name: web-task-definition | |
path: ${{ steps.render-web-task-definition.outputs.task-definition }} | |
retention-days: 1 | |
- name: Upload good-job task definition artifact | |
if: inputs.server_types == 'good-job' || inputs.server_types == 'all' | |
uses: actions/upload-artifact@v4 | |
with: | |
name: good-job-task-definition | |
path: ${{ steps.render-good-job-task-definition.outputs.task-definition }} | |
retention-days: 1 | |
outputs: | |
new-image-uri: ${{ steps.get-image-digest.outputs.new-image-uri }} | |
web-environment-variables: ${{ steps.get-dynamic-vars-web.outputs.environment-variables }} | |
web-secrets: ${{ steps.get-dynamic-vars-web.outputs.secrets }} | |
web-execution-role-arn: ${{ steps.get-dynamic-vars-web.outputs.execution-role-arn }} | |
web-task-role-arn: ${{ steps.get-dynamic-vars-web.outputs.task-role-arn }} | |
good-job-environment-variables: ${{ steps.get-dynamic-vars-good-job.outputs.environment-variables }} | |
good-job-secrets: ${{ steps.get-dynamic-vars-good-job.outputs.secrets }} | |
good-job-execution-role-arn: ${{ steps.get-dynamic-vars-good-job.outputs.execution-role-arn }} | |
good-job-task-role-arn: ${{ steps.get-dynamic-vars-good-job.outputs.task-role-arn }} | |
deploy-web: | |
name: Deploy web service | |
runs-on: ubuntu-latest | |
if: inputs.server_types == 'web' || inputs.server_types == 'all' | |
needs: prepare-deployment | |
environment: ${{ inputs.environment }} | |
permissions: | |
id-token: write | |
steps: | |
- name: Configure AWS Credentials | |
uses: aws-actions/configure-aws-credentials@v4 | |
with: | |
role-to-assume: ${{ env.aws-role }} | |
aws-region: eu-west-2 | |
- name: Download web task definition artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: web-task-definition | |
path: ./artifacts | |
- name: Register new task definition | |
run: | | |
# Find the task definition file in the artifacts directory | |
TASK_DEF_FILE=$(find ./artifacts -name "*.json" -type f | head -1) | |
aws ecs register-task-definition --cli-input-json file://$TASK_DEF_FILE | |
- name: Deploy with CodeDeploy | |
run: | | |
# Create CodeDeploy deployment for blue-green deployment | |
deployment_id=$(aws deploy create-deployment \ | |
--application-name ${{ env.web_codedeploy_application }} \ | |
--deployment-group-name ${{ env.web_codedeploy_group }} \ | |
--deployment-config-name CodeDeployDefault.ECSBlueGreenCanary10Percent5Minutes \ | |
--description "Deployment from GitHub Actions" \ | |
| jq -r .deploymentId) | |
echo "CodeDeploy deployment started: $deployment_id" | |
echo "deployment_id=$deployment_id" >> $GITHUB_ENV | |
- name: Wait for deployment to complete | |
run: | | |
echo "Waiting for CodeDeploy deployment $deployment_id to complete..." | |
aws deploy wait deployment-successful --deployment-id "$deployment_id" | |
echo "Deployment successful" | |
deploy-good-job: | |
name: Deploy good-job service | |
runs-on: ubuntu-latest | |
if: inputs.server_types == 'good-job' || inputs.server_types == 'all' | |
needs: prepare-deployment | |
environment: ${{ inputs.environment }} | |
permissions: | |
id-token: write | |
steps: | |
- name: Configure AWS Credentials | |
uses: aws-actions/configure-aws-credentials@v4 | |
with: | |
role-to-assume: ${{ env.aws-role }} | |
aws-region: eu-west-2 | |
- name: Download good-job task definition artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: good-job-task-definition | |
path: ./artifacts | |
- name: Register new task definition | |
run: | | |
# Find the task definition file in the artifacts directory | |
TASK_DEF_FILE=$(find ./artifacts -name "*.json" -type f | head -1) | |
TASK_DEFINITION_ARN=$(aws ecs register-task-definition --cli-input-json file://$TASK_DEF_FILE --query 'taskDefinition.taskDefinitionArn' --output text) | |
echo "New task definition registered: $TASK_DEFINITION_ARN" | |
echo "task_definition_arn=$TASK_DEFINITION_ARN" >> $GITHUB_ENV | |
- name: Update ECS service | |
run: | | |
# Update the good-job service with the new task definition | |
DEPLOYMENT_ID=$(aws ecs update-service \ | |
--cluster ${{ env.cluster_name }} \ | |
--service ${{ env.good_job_service }} \ | |
--task-definition "$task_definition_arn" \ | |
--force-new-deployment \ | |
--query 'service.deployments[?rolloutState==`IN_PROGRESS`].[id][0]' \ | |
--output text) | |
echo "ECS deployment started: $DEPLOYMENT_ID" | |
echo "deployment_id=$DEPLOYMENT_ID" >> $GITHUB_ENV | |
- name: Wait for deployment to complete | |
run: | | |
echo "Waiting for ECS deployment $deployment_id to complete..." | |
DEPLOYMENT_STATE=IN_PROGRESS | |
while [ "$DEPLOYMENT_STATE" == "IN_PROGRESS" ]; do | |
echo "Checking deployment status..." | |
sleep 30 | |
DEPLOYMENT_STATE=$(aws ecs describe-services \ | |
--cluster ${{ env.cluster_name }} \ | |
--services ${{ env.good_job_service }} \ | |
--query "services[0].deployments[?id == \`$deployment_id\`].[rolloutState][0]" \ | |
--output text) | |
done | |
if [ "$DEPLOYMENT_STATE" != "COMPLETED" ]; then | |
echo "Deployment failed with state: $DEPLOYMENT_STATE" | |
exit 1 | |
fi | |
echo "Deployment successful" |