Skip to content

Commit

Permalink
Add github actions for deploying AWS ECS envs
Browse files Browse the repository at this point in the history
  • Loading branch information
willscripted committed Jan 30, 2025
1 parent be3b2c8 commit 30f9bc8
Show file tree
Hide file tree
Showing 9 changed files with 426 additions and 34 deletions.
101 changes: 101 additions & 0 deletions .github/workflows/callable-build-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: "Task: Build"
on:
workflow_call:
inputs:
override_sha:
description: 'Optionally force checkout of a specific sha'
default: ''
type: string
push:
description: 'To push or not to push'
required: true
type: boolean
outputs:
container_image_digest:
description: "The sha256 digest of the built container image"
value: ${{ jobs.docker.outputs.digest }}

permissions:
packages: write
contents: read
attestations: write
id-token: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
docker:
runs-on: ubuntu-24.04
outputs:
digest: ${{ steps.push.outputs.digest }}
steps:
- uses: actions/checkout@v4
if: ${{ inputs.override_sha != '' }}
with:
fetch-depth: 1
ref: ${{ inputs.override_sha }}

- uses: actions/checkout@v4
if: ${{ inputs.override_sha == '' }}
with:
fetch-depth: 1

- name: Configuration
id: config
run: |
REPOSITORY_OWNER=$(tr "[:upper:]" "[:lower:]" <<< "${{ github.repository_owner }}")
echo "REPOSITORY_OWNER=${REPOSITORY_OWNER}" >> "$GITHUB_OUTPUT"
REPOSITORY_NAME=$(tr "[:upper:]" "[:lower:]" <<< "${{ github.event.repository.name }}")
echo "REPOSITORY_NAME=${REPOSITORY_NAME}" >> "$GITHUB_OUTPUT"
TARGET_IMAGE="ghcr.io/${REPOSITORY_OWNER}/${REPOSITORY_NAME}"
echo "TARGET_IMAGE=${TARGET_IMAGE}" >> "$GITHUB_OUTPUT"
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ steps.config.outputs.REPOSITORY_OWNER }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
context: workflow
images: ${{ steps.config.outputs.TARGET_IMAGE }}
tags: |-
${{ inputs.override_sha == '' && 'type=ref,event=branch' || '' }}
${{ inputs.override_sha == '' && 'type=ref,event=tag' || '' }}
${{ inputs.override_sha == '' && 'type=ref,event=pr' || '' }}
${{ inputs.override_sha == '' && '# skip raw sha' || format('type=raw,value=sha-{0}', inputs.override_sha) }}
labels: |-
${{ inputs.override_sha != '' && 'org.opencontainers.image.version=unknown' }}
${{ inputs.override_sha != '' && format('org.opencontainers.image.revision={0}', inputs.override_sha) }}
flavor: |
latest=false
- name: Build and push Docker image
id: push
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: ${{ inputs.push }}
platforms: "linux/amd64"
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

- name: Generate artifact attestation
uses: actions/attest-build-provenance@v2
if: ${{ inputs.push }}
with:
subject-name: ${{ steps.config.outputs.TARGET_IMAGE }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: ${{ inputs.push }}
79 changes: 79 additions & 0 deletions .github/workflows/callable-deploy-ecs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: "Task: Deploy"
on:
workflow_call:
inputs:
env:
description: Target environment of deployment. (stg, prod)
required: true
type: string
container_digest:
description: 'The container sha256 digest to deploy'
required: true
type: string

permissions:
contents: 'read'
id-token: 'write'

concurrency:
group: ${{ inputs.env }}
cancel-in-progress: false

jobs:
deploy:
name: dashboard
runs-on: ubuntu-24.04
environment: ${{ inputs.env }}
steps:
- uses: actions/checkout@v4

- name: Configuration
id: config
run: |
REPOSITORY_OWNER=$(tr "[:upper:]" "[:lower:]" <<< "${{ github.repository_owner }}")
echo "REPOSITORY_OWNER=${REPOSITORY_OWNER}" >> "$GITHUB_OUTPUT"
REPOSITORY_NAME=$(tr "[:upper:]" "[:lower:]" <<< "${{ github.event.repository.name }}")
echo "REPOSITORY_NAME=${REPOSITORY_NAME}" >> "$GITHUB_OUTPUT"
TARGET_IMAGE="ghcr.io/${REPOSITORY_OWNER}/${REPOSITORY_NAME}"
echo "TARGET_IMAGE=${TARGET_IMAGE}" >> "$GITHUB_OUTPUT"
TARGET_IMAGE_W_DIGEST="${TARGET_IMAGE}@${{ inputs.container_digest }}"
echo "TARGET_IMAGE_W_DIGEST=${TARGET_IMAGE_W_DIGEST}" >> "$GITHUB_OUTPUT"
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.IAM_ROLE_ARN }}
aws-region: us-east-2

- name: Download task definition
run: |
aws ecs describe-task-definition \
--task-definition ${{ vars.ECS_TASK_DEF_FAMILY }} \
--query taskDefinition \
> task.json
# Remove Ignored Properties
echo "$( jq 'del(.compatibilities)' task.json )" > task.json
echo "$( jq 'del(.taskDefinitionArn)' task.json )" > task.json
echo "$( jq 'del(.requiresAttributes)' task.json )" > task.json
echo "$( jq 'del(.revision)' task.json )" > task.json
echo "$( jq 'del(.status)' task.json )" > task.json
echo "$( jq 'del(.registeredAt)' task.json )" > task.json
echo "$( jq 'del(.registeredBy)' task.json )" > task.json
# Update Image
echo "$( jq --arg image "${{ steps.config.outputs.TARGET_IMAGE_W_DIGEST }}" '.containerDefinitions |= map((select(.name == "dashboard") | .image) |= $image)' task.json )" > task.json
cat task.json
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v2
with:
task-definition: task.json
service: ${{ vars.ECS_SERVICE }}
cluster: ${{ vars.ECS_CLUSTER }}
wait-for-service-stability: true
90 changes: 90 additions & 0 deletions .github/workflows/manual-deploy-sha.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: 'Manual Deploy: Git Sha'
on:
workflow_dispatch:
inputs:
sha:
type: string
required: true
description: Git sha (long format) to build and deploy
env:
type: environment
default: stg

concurrency:
group: ${{ github.workflow }}-${{ inputs.sha }}
cancel-in-progress: false

jobs:
# This job builds a new container and deploys it to the target environment. It
# is unsafe to deploy such arbitrary builds directly to production without
# first trialing them in lower environments.

validate:
name: "Validate Inputs"
runs-on: ubuntu-24.04
steps:
- name: Verify not production
if: ${{ inputs.env == 'prod' }}
run: |
cat << EOF
#---------------------------------------------------------------------------------
# ERROR: Cannot deploy arbitrary sha to production
#---------------------------------------------------------------------------------
#
# DETAILS:
#
# This job builds a new container and deploys it to the target environment. It
# is unsafe to deploy such arbitrary builds directly to production without
# first trialing them in lower environments.
#
# WORKAROUND:
#
# If you truely must release a specific sha,
#
# 1) Use this workflow to build and deploy the sha to staging
# 2) Deploy the assigned tag from that deployment using the
# "Manual Deploy: Docker Tag" workflow
# Note: You must cite a DOCKER tag
# Which should look like "sha-9e14d6f3da3c3c3f7ea73b74dec8c931365745e4"
#
#---------------------------------------------------------------------------------
EOF
exit 1
- name: Verify sha is hex
run: |
if [[ ! "${{ inputs.sha }}" =~ ^[0-9A-Fa-f]+$ ]]; then
echo "sha must be hexidecimal"; exit 1
fi
length=$(expr length "${{ inputs.sha }}")
if [ "$length" != "40" ]; then
echo "sha must be all 40 characters"; exit 1
fi
- uses: actions/checkout@v4
with:
ref: ${{ inputs.sha }}

- name: Verify commit exists
run: |
git cat-file commit ${{ inputs.sha }}
build-docker:
name: "Build"
uses: ./.github/workflows/callable-build-docker.yml
secrets: inherit
with:
override_sha: ${{ inputs.sha }}
push: true
needs:
- validate

deploy-ecs:
name: "Deploy container to ECS"
uses: ./.github/workflows/callable-deploy-ecs.yml
secrets: inherit
with:
env: ${{ inputs.env }}
container_digest: ${{ needs.build-docker.outputs.container_image_digest }}
needs:
- build-docker
76 changes: 76 additions & 0 deletions .github/workflows/manual-deploy-tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: 'Manual Deploy: Docker Tag'
on:
workflow_dispatch:
inputs:
tag:
type: string
required: true
description: Tag of the DOCKER image to deploy
env:
type: environment
default: stg

concurrency:
group: ${{ github.workflow }}-${{ inputs.env }}
cancel-in-progress: false

jobs:

locate:
name: Find Target Image
runs-on: ubuntu-24.04
outputs:
digest: ${{ steps.inspect.outputs.digest }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Configuration
id: config
run: |
REPOSITORY_OWNER=$(tr "[:upper:]" "[:lower:]" <<< "${{ github.repository_owner }}")
echo "REPOSITORY_OWNER=${REPOSITORY_OWNER}" >> "$GITHUB_OUTPUT"
REPOSITORY_NAME=$(tr "[:upper:]" "[:lower:]" <<< "${{ github.event.repository.name }}")
echo "REPOSITORY_NAME=${REPOSITORY_NAME}" >> "$GITHUB_OUTPUT"
TARGET_IMAGE="ghcr.io/${REPOSITORY_OWNER}/${REPOSITORY_NAME}"
echo "TARGET_IMAGE=${TARGET_IMAGE}" >> "$GITHUB_OUTPUT"
TARGET_IMAGE_W_TAG="${TARGET_IMAGE}:${{ inputs.tag }}"
echo "TARGET_IMAGE_W_TAG=${TARGET_IMAGE_W_TAG}" >> "$GITHUB_OUTPUT"
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Pull target tag & inspect
id: inspect
run: |
set -e
docker pull ${{ steps.config.outputs.TARGET_IMAGE_W_TAG }}
checksum=$(
docker inspect ${{ steps.config.outputs.TARGET_IMAGE_W_TAG }} \
| jq '.[].RepoDigests.[]' \
| tr -d '"' \
| sed 's/^.*@//'
)
echo "digest=${checksum}" >> "$GITHUB_OUTPUT"
deploy:
name: "Deploy"
uses: ./.github/workflows/callable-deploy-ecs.yml
secrets: inherit
with:
env: ${{ inputs.env }}
container_digest: ${{ needs.locate.outputs.digest }}
needs:
- locate
29 changes: 29 additions & 0 deletions .github/workflows/on-merge-to-master.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: On Branch Update (master)
on:
push:
branches:
- master
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

jobs:

build-docker:
name: "Build"
uses: ./.github/workflows/callable-build-docker.yml
secrets: inherit
with:
push: true

deploy-env-stg:
name: "Deploy Staging"
uses: ./.github/workflows/callable-deploy-ecs.yml
secrets: inherit
with:
env: stg
container_digest: ${{ needs.build-docker.outputs.container_image_digest }}
needs:
- build-docker
Loading

0 comments on commit 30f9bc8

Please sign in to comment.