Skip to content

Deploy application to sandbox-alpha #42

Deploy application to sandbox-alpha

Deploy application to sandbox-alpha #42

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"