Created
January 27, 2023 04:36
-
-
Save sacarino/4891afa97091bc0059d38df1da145273 to your computer and use it in GitHub Desktop.
Bash script to build a docker image, tag it, push to ECR, and deploy to ECS
This file contains 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
#!/bin/bash | |
# Script to build, tag, auth, and deploy to production | |
# Call it like `./deploy-to-cluster.sh {profile}` | |
# AWS ECS task definition that we'll be updating at the end. | |
# This assumes your service and task are named the same thing! | |
TASK_DEFINITION_NAME="my-task-name" | |
# name of the cluster you're deploying to | |
CLUSTER="my-cluster-name" | |
# The profile name should be passed in as the first argument | |
# Profiles are configured via the AWS CLI tool, see | |
# https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html | |
PROFILE=$1 | |
if [ -z "$PROFILE" ] | |
then | |
printf "\nFATAL: Build script must be called with the target AWS profile" | |
exit 1 | |
fi | |
FILE=".env.${PROFILE}" | |
if [[ -f $FILE && $FILE =~ ^. ]] | |
then | |
printf "\n$FILE exists, loading values into ENV" | |
set -a; source $FILE; set +a | |
else | |
printf "\nFATAL: No $FILE file found" | |
exit 1 | |
fi | |
printf "\nProfile: $PROFILE\n" | |
# Using the profile name, let's get the AWS region this belongs to | |
# Regions are configured via the AWS CLI tool, see | |
# https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html | |
printf "\n================ Getting the region for our profile" | |
REGION=$(aws configure get region --profile $PROFILE) | |
if [ -z "$REGION" ] | |
then | |
printf "\nWARN: Check ~/.aws/config for a $PROFILE entry" | |
exit 1 | |
fi | |
printf "\nRegion: $REGION\n" | |
# get the account ID for your profile's token | |
# https://stackoverflow.com/questions/33791069/quick-way-to-get-aws-account-number-from-the-aws-cli-tools | |
printf "\n================ Retrieving the account id for our profile" | |
ACCOUNT=$(aws sts get-caller-identity --profile $PROFILE --query Account --output text) | |
if [ -z "$ACCOUNT" ] | |
then | |
printf "\nWARN: Check ~/.aws/credentials for a $PROFILE entry" | |
exit 1 | |
fi | |
printf "\nAccount: $ACCOUNT\n" | |
# Build our docker image | |
DOCKER_BUILD=$(yarn run docker:build); ec=$? | |
# Bail if there was an error | |
# https://stackoverflow.com/questions/26675681/how-to-check-the-exit-status-using-an-if-statement | |
case $ec in | |
0) ;; | |
*) printf "\nFATAL: Docker failed to build the image. $DOCKER_BUILD" && exit 1; | |
esac | |
# Now we can auth against the ECR instance in the target region | |
printf "\n================ Authenticating with our AWS region" | |
AWS_ECR=$(aws ecr get-login-password --region $REGION --profile $PROFILE | docker login --username AWS --password-stdin $ACCOUNT.dkr.ecr.$REGION.amazonaws.com); ec=$? | |
case $ec in | |
0) printf "\nAWS login: success!\n";; | |
*) printf "\nFATAL: AWS ECR failed. $AWS_ECR" && exit 1; | |
esac | |
# Define a timestamp function for tagging | |
TIMESTAMP="$(TZ=UTC date +%Y-%m-%dT%H%M.%SZ)" | |
# Pull the version info out of the package.json | |
VERSION="v$(cat package.json | jq -r '.version')" | |
# Combine the two for a unique build hash | |
BUILD="${VERSION}_${TIMESTAMP}" | |
# Creating our task definition name | |
NEW_ECR_NAME="$ACCOUNT.dkr.ecr.$REGION.amazonaws.com/${TASK_DEFINITION_NAME}:${BUILD}" | |
# Tag our image with this build hash | |
printf "\n================ Tagging the new image as ${BUILD}" | |
DOCKER_TAG=$(docker tag ${TASK_DEFINITION_NAME}:latest $NEW_ECR_NAME); ec=$? | |
case $ec in | |
0) printf "\nTagging: success!\n";; | |
*) printf '%s\n' "FATAL: Docker tag failed. $DOCKER_TAG" >> build.error ; exit 1; | |
esac | |
# Push this build up to the ECR instance | |
printf "\n================ Pushing ${BUILD} up to ECR" | |
DOCKER_PUSH=$(docker push $NEW_ECR_NAME); ec=$? | |
case $ec in | |
0) printf "\nPushing: success!\n";; | |
*) printf '%s\n' "FATAL: Docker push failed. $DOCKER_PUSH" >> build.error ; exit 1; | |
esac | |
# Getting the current task definition | |
printf "\n================ Creating a new task definition in ${VERSION}.json" | |
CURRENT_TASK_DEFINITION=$(aws ecs describe-task-definition --task-definition $TASK_DEFINITION_NAME --profile $PROFILE --region $REGION) | |
NEW_CONTAINER_DEFS=$(echo $CURRENT_TASK_DEFINITION | jq '.taskDefinition.containerDefinitions' | jq '.[0].image='\"${NEW_ECR_NAME}\") | |
CURRENT_REV=$(echo $CURRENT_TASK_DEFINITION | jq '.taskDefinition.revision') | |
NEW_REV="$TASK_DEFINITION_NAME:$((CURRENT_REV+1))" | |
if [ -z "$NEW_REV" ] | |
then | |
printf "\nFATAL: Could not create a new revision of the task definition" | |
exit 1 | |
else | |
printf "\nRevision: $NEW_REV\n" | |
echo $NEW_CONTAINER_DEFS > ${VERSION}.json | |
fi | |
printf "\n================ Discovering how many instance of this should run" | |
DESIRED_COUNT=$(aws ecs describe-services --cluster $CLUSTER --services ${TASK_DEFINITION_NAME} --region $REGION --profile $PROFILE | jq .services[].desiredCount); ec=$? | |
if [ ${DESIRED_COUNT} = "0" ]; then | |
DESIRED_COUNT="1" | |
fi | |
case $ec in | |
0) printf "\nInstances: $DESIRED_COUNT\n";; | |
*) printf '%s\n' "FATAL: desired count failed. $DESIRED_COUNT" >> build.error ; exit 1; | |
esac | |
# Create the new task definition | |
printf "\n================ Registering the task definition" | |
NEW_TASK_DEFINITION=$(aws ecs register-task-definition --family ${TASK_DEFINITION_NAME} --region $REGION --container-definitions "$(cat ${VERSION}.json)" --profile $PROFILE); ec=$? | |
case $ec in | |
0) printf "\nRegister task: success!\n";; | |
*) printf '%s\n' "FATAL: Register task failed. $NEW_TASK_DEFINITION" >> build.error ; exit 1; | |
esac | |
# Update the service to use the latest task definition | |
printf "\n================ Updating the service with the new task definition and desired count" | |
UPDATE_SERVICE=$(aws ecs update-service --cluster $CLUSTER --service $TASK_DEFINITION_NAME --task-definition $NEW_REV --desired-count $DESIRED_COUNT --region $REGION --profile govcloud); ec=$? | |
case $ec in | |
0) printf "\nService update: success!\n";; | |
*) printf '%s\n' "FATAL: ECS update service failed. $UPDATE_SERVICE" >> build.error ; exit 1; | |
esac | |
printf "\n================ Cleaning up" | |
rm ${VERSION}.json; ec=$? | |
case $ec in | |
0) printf "\nRemoving ${VERSION}.json: success!\n"; exit 0; | |
*) printf '%s\n' "FATAL: Unable to remove ${VERSION}.json. Please manually remove it." >> build.error ; exit 1; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment