Skip to content

Commit

Permalink
Add workflows to deploy AWS infrastructure with OpenTofu and to deplo…
Browse files Browse the repository at this point in the history
…y Docker (#69)
  • Loading branch information
smokestacklightnin authored Oct 31, 2024
1 parent 3a65859 commit b10acaf
Show file tree
Hide file tree
Showing 25 changed files with 531 additions and 20 deletions.
75 changes: 75 additions & 0 deletions .github/workflows/build-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Docker Build Workflow

on:
workflow_call:
inputs:
deployment:
required: true
type: string
aws_region:
description: 'AWS region'
type: string
required: false
default: 'us-east-1'

jobs:
build:
runs-on: ubuntu-latest
services:
registry:
image: registry:2
ports:
- 5000:5000
steps:
- name: Checkout code
uses: actions/[email protected]

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ inputs.aws_region }}
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/github-actions-role-shared

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: network=host

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2

- name: Compute image tag
id: compute-image-tag
run: |
short_sha=$(git rev-parse --short ${{ github.sha }})
echo "tag=${{ steps.login-ecr.outputs.registry }}/${{ inputs.deployment }}-shared:$short_sha" >> $GITHUB_OUTPUT
echo "short_sha=$short_sha" >> $GITHUB_OUTPUT
- name: Check for image tag
id: check-image-tag
run: |
found_tag=$(aws ecr list-images --repository-name ${{ inputs.deployment }}-shared --region ${{ inputs.aws_region }} --query 'imageIds[*].imageTag' | grep -q "${{ steps.compute-image-tag.outputs.short_sha }}"; echo $?)
echo "found_tag=$found_tag" >> $GITHUB_OUTPUT
- name: Build base Docker image
# only build if the image tag doesn't exist
if: steps.check-image-tag.outputs.found_tag == 1
uses: docker/build-push-action@v6
with:
context: .
push: true
file: Dockerfile.base
tags: localhost:5000/osm/osm_base

- name: Build and push Docker image
# only build if the image tag doesn't exist
if: steps.check-image-tag.outputs.found_tag == 1
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.compute-image-tag.outputs.tag }}
file: web/${{ inputs.deployment }}/Dockerfile
build-args: |
BASE_IMAGE=localhost:5000/osm/osm_base
93 changes: 93 additions & 0 deletions .github/workflows/deploy-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: Push to Docker image to AWS ECR and deploy to AWS EC2

on:
workflow_dispatch:
inputs:
development-environment:
description: Development environment to deploy to.
required: true
default: staging
type: choice
options:
- staging
- production
pull_request:
branches:
- main
types:
- closed
paths-ignore:
- 'web/deploy/terraform/**'
workflow_call:
inputs:
development-environment:
description: Development environment to deploy to. Usually `staging` or `production`
required: true
default: staging
type: string

permissions:
id-token: write
contents: read

jobs:
set-development-environment:
runs-on: ubuntu-latest
name: Set development environment
outputs:
development-environment: ${{ steps.set-development-environment.outputs.development-environment }}
steps:
- name: Set development environment
id: set-development-environment
run: |
if [[ "${{ github.event_name }}" == 'pull_request' || "${{ inputs.development-environment }}" == 'staging' ]]; then
echo "development-environment=staging" >> $GITHUB_OUTPUT
else
echo "development-environment=production" >> $GITHUB_OUTPUT
fi
cat "$GITHUB_OUTPUT"
cat "$GITHUB_OUTPUT" | grep 'development-environment'
infrastructure-modified:
runs-on: ubuntu-latest
name: Check for modified infrastructure
outputs:
modified-files: ${{ steps.set-output.outputs.modified-files }}
steps:
- uses: actions/checkout@v4
name: Checkout repository

- name: Get modified infrastructure configuration
id: infrastructure-modified
uses: tj-actions/changed-files@v45
with:
files: |
web/deploy/terraform/**
- name: Set modified output
id: set-output
env:
MODIFIED_FILES: ${{ steps.infrastructure-modified.outputs.any_modified }}
run: |
echo "modified-files=${MODIFIED_FILES}" >> $GITHUB_OUTPUT
build-and-push:
needs: [infrastructure-modified, set-development-environment]
strategy:
matrix:
deployment: ["api", "dashboard"]
uses: ./.github/workflows/build-docker.yml
if: ( (github.event_name == 'pull_request' && github.event.pull_request.merged == true && needs.infrastructure-modified.outputs.modified-files != 'true' && needs.set-development-environment.result == 'success') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'workflow_call') )
secrets: inherit
with:
deployment: ${{ matrix.deployment }}

docker-up:
needs: [build-and-push, set-development-environment, infrastructure-modified]
if: ${{ always() && !cancelled() && needs.build-and-push.result == 'success' && ( (github.event_name == 'pull_request' && github.event.pull_request.merged == 'true' && needs.infrastructure-modified.outputs.modified-files != 'true') || (github.event_name == 'workflow_dispatch') || (github.event_name == 'push') || (github.event_name == 'workflow_call') )}}
name: Deploy and run Docker images on EC2
uses: ./.github/workflows/docker-up.yml
secrets: inherit
with:
development-environment: ${{ needs.set-development-environment.outputs.development-environment }}

130 changes: 130 additions & 0 deletions .github/workflows/deploy-opentofu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: Deploy OpenTofu

on:
push:
branches:
- '**'
- '!main'
paths:
- 'web/deploy/terraform/**'
workflow_dispatch:
inputs:
development-environment:
description: Development environment to deploy to.
required: true
default: staging
type: choice
options:
- staging
- production
pull_request:
branches:
- main
types:
- closed
paths:
- 'web/deploy/terraform/**'
env:
working_directory_parent: ./web/deploy/terraform
TF_VAR_AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}

permissions:
id-token: write
contents: read

jobs:
set-development-environment:
runs-on: ubuntu-latest
name: Set development environment
outputs:
development-environment: ${{ steps.set-development-environment.outputs.development-environment }}
steps:
- name: Set development environment
id: set-development-environment
run: |
if [[ "${{ github.event_name }}" == 'workflow_dispatch' && "${{ inputs.development-environment }}" == 'production' ]]; then
echo 'development-environment=production' >> "$GITHUB_OUTPUT"
else
echo 'development-environment=staging' >> "$GITHUB_OUTPUT"
fi
cat "$GITHUB_OUTPUT"
cat "$GITHUB_OUTPUT" | grep 'development-environment'
deploy-shared-resources:
needs: [set-development-environment]
if: ${{ always() && !cancelled() && needs.set-development-environment.result == 'success' && needs.set-development-environment.outputs.development-environment == 'staging' }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/[email protected]

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ secrets.AWS_REGION }}
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/github-actions-role-shared

- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1

- name: Initialize shared resources
working-directory: ${{ env.working_directory_parent }}/shared
run: |
tofu init
- name: Plan resources
working-directory: ${{ env.working_directory_parent }}/shared
run: |
tofu plan -no-color -detailed-exitcode -out=tfplan
continue-on-error: true

- name: Deploy shared resources
if: ${{ github.event_name != 'push' }}
working-directory: ${{ env.working_directory_parent }}/shared
run: |
tofu apply -no-color -auto-approve tfplan
deploy-environments:
needs: [deploy-shared-resources, set-development-environment]
runs-on: ubuntu-latest
if: ${{ always() && !cancelled() && (needs.deploy-shared-resources.result == 'success' || (needs.deploy-shared-resources.result == 'skipped' && github.event_name == 'workflow_dispatch')) }}
env:
TF_VAR_PUBLIC_KEY: ${{ secrets.SSH_PUBLIC_KEY }}
steps:
- name: Checkout code
uses: actions/[email protected]

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ secrets.AWS_REGION }}
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/github-actions-role-shared

- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1

- name: Initialize resources
working-directory: ${{ env.working_directory_parent }}/${{ needs.set-development-environment.outputs.development-environment }}
run: |
tofu init
- name: Plan resources
working-directory: ${{ env.working_directory_parent }}/${{ needs.set-development-environment.outputs.development-environment }}
run: |
tofu plan -no-color -detailed-exitcode -out=tfplan
continue-on-error: true

- name: Deploy resources
if: ${{ github.event_name != 'push' }}
working-directory: ${{ env.working_directory_parent }}/${{ needs.set-development-environment.outputs.development-environment }}
run: |
tofu apply -no-color -auto-approve tfplan
deploy-docker:
needs: [deploy-environments, set-development-environment]
if: ${{ always() && !cancelled() && needs.deploy-environments.result == 'success' && github.event_name != 'push' }}
name: Push and deploy Docker images to EC2
uses: ./.github/workflows/deploy-docker.yml
secrets: inherit
with:
development-environment: ${{ needs.set-development-environment.outputs.development-environment }}
File renamed without changes.
77 changes: 77 additions & 0 deletions .github/workflows/docker-up.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Execute `docker compose up`

on:
workflow_call:
inputs:
development-environment:
description: Development environment to deploy to. Usually `staging` or `production`
required: true
default: staging
type: string

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/[email protected]

- name: Get image tag
run: |
echo "RELEASE_TAG=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV
- name: Set host URI
env:
SSH_PROD_HOST: ${{ secrets.SSH_PROD_HOST }}
SSH_STAGE_HOST: ${{ secrets.SSH_STAGE_HOST }}
run: |
if [[ ${{ inputs.development-environment }} == 'production' ]]; then
echo "HOST_URI=${SSH_PROD_HOST}" >> $GITHUB_ENV
else
echo "HOST_URI=${SSH_STAGE_HOST}" >> $GITHUB_ENV
fi
- name: Configure SSH
env:
PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
DEPLOY_USERNAME: ${{ secrets.DEPLOYMENT_USERNAME }}
run: |
mkdir -p ~/.ssh/
echo "$PRIVATE_KEY" > ~/.ssh/aws
chmod 600 ~/.ssh/aws
cat >>~/.ssh/config <<END
Host ${{ inputs.development-environment }}
HostName ${HOST_URI}
User ${DEPLOY_USERNAME}
IdentityFile ~/.ssh/aws
StrictHostKeyChecking no
END
- name: Log in to ECR
env:
AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
AWS_REGION: ${{ secrets.AWS_REGION }}
run: |
ssh ${{ inputs.development-environment }} "aws ecr get-login-password --region ${AWS_REGION} | \
docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
- name: Run `docker compose up` on remote staging host
env:
AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
AWS_REGION: ${{ secrets.AWS_REGION }}
MONGODB_URI: ${{ secrets.MONGODB_URI }}
LETSENCRYPT_ADMIN_EMAIL: ${{ secrets.LETSENCRYPT_ADMIN_EMAIL }}
run: |
ssh ${{ inputs.development-environment }} \
MONGODB_URI="${MONGODB_URI}" \
HOST_URI="${HOST_URI}" \
RELEASE_TAG="${RELEASE_TAG}" \
AWS_ACCOUNT_ID="${AWS_ACCOUNT_ID}" \
AWS_REGION="${AWS_REGION}" \
LETSENCRYPT_ADMIN_EMAIL=${LETSENCRYPT_ADMIN_EMAIL} \
docker compose -f - up -d < ./web/deploy/docker-compose.yaml
- name: Prune Docker artifacts
run: |
ssh ${{ inputs.development-environment }} docker system prune -af --filter "until=24h"
3 changes: 3 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- uses: opentofu/setup-opentofu@v1
- name: Install tflint
run: curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash
- uses: pre-commit/[email protected]
tox-tests:
runs-on: ubuntu-latest
Expand Down
Loading

0 comments on commit b10acaf

Please sign in to comment.