Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add workflows to deploy AWS infrastructure with OpenTofu and to deploy Docker #69

Merged
merged 70 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
1725f27
Add .env file containing staging and production tags
smokestacklightnin Oct 22, 2024
968af5c
Add AWS account ID from environment variable
smokestacklightnin Oct 22, 2024
a1e882c
Add action to configure aws credentials
smokestacklightnin Oct 22, 2024
ac30f4e
debug uncomment tags trigger
smokestacklightnin Oct 22, 2024
47e5969
Add iam oidc provider
smokestacklightnin Oct 22, 2024
78d69e3
Add docker buildx action
smokestacklightnin Oct 22, 2024
1943228
Add login to amazon ecr action
smokestacklightnin Oct 22, 2024
2615bd4
Add matrix to build and push dashboard and api
smokestacklightnin Oct 23, 2024
c09eef6
Update docker install script for ec2 initialization
smokestacklightnin Oct 24, 2024
6543706
Add empty docker-up.yml
smokestacklightnin Oct 24, 2024
7e56e93
Add checkout action
smokestacklightnin Oct 24, 2024
1cd9a24
Get version tag
smokestacklightnin Oct 24, 2024
76e55fe
Pass environment config from caller
smokestacklightnin Oct 24, 2024
6cc1441
Update versions of actions
smokestacklightnin Oct 25, 2024
b1048c0
Correctly call reusable workflow
smokestacklightnin Oct 25, 2024
82f1edd
Fix set environment variable
smokestacklightnin Oct 25, 2024
cde3477
Write basic ssh command
smokestacklightnin Oct 25, 2024
2c2a392
Add docker compose file and run docker compose on host
smokestacklightnin Oct 25, 2024
33f8c44
Fix release tag
smokestacklightnin Oct 25, 2024
88e9979
Log in to ECR
smokestacklightnin Oct 25, 2024
9b9a196
Add quotation marks
smokestacklightnin Oct 25, 2024
4e02bbb
Change order
smokestacklightnin Oct 25, 2024
20a5d51
Remove newlines
smokestacklightnin Oct 25, 2024
9011882
Add more quotes
smokestacklightnin Oct 25, 2024
450b879
Run different ssh commands for different development environments
smokestacklightnin Oct 25, 2024
06d6909
Remove unnecessary file
smokestacklightnin Oct 25, 2024
30ed1cc
Clean up build-docker.yml
smokestacklightnin Oct 26, 2024
9fa56bc
Clean up deploy-docker.yml
smokestacklightnin Oct 26, 2024
f376c45
Always restart containers
smokestacklightnin Oct 26, 2024
5df6802
Dynamically set host uri
smokestacklightnin Oct 26, 2024
ef2b2af
Clean up use of environment variable
smokestacklightnin Oct 26, 2024
b0dd557
Inherit secrets
smokestacklightnin Oct 26, 2024
806616f
Prune old artifacts
smokestacklightnin Oct 26, 2024
7e2b0da
Use `\` to get rid of long lines
smokestacklightnin Oct 28, 2024
c783940
Remove comment about `choice` trigger
smokestacklightnin Oct 29, 2024
e2a2d74
Remove unnecessary get version tag step
smokestacklightnin Oct 29, 2024
4429767
Add "Check for image tag" step and only build Docker images if tag is…
smokestacklightnin Oct 29, 2024
fcbb990
Move deprecated files to `deprecated` directory
smokestacklightnin Oct 29, 2024
5ca3f21
Only trigger on successful merges to `main` branch or workflow dispatch
smokestacklightnin Oct 29, 2024
2025029
Checkout code
smokestacklightnin Oct 25, 2024
b78acff
Configure aws credentials
smokestacklightnin Oct 25, 2024
cd5fdcb
Setup OpenTofu
smokestacklightnin Oct 26, 2024
8d0d05a
Add push trigger
smokestacklightnin Oct 26, 2024
434d150
Check for changes in OpenTofu modules
smokestacklightnin Oct 26, 2024
88d3542
Initialize and apply tofu for shared, staging, and production
smokestacklightnin Oct 26, 2024
dc870e3
Run staging and production deployment jobs in parallel
smokestacklightnin Oct 29, 2024
8cc9733
Set working directory more elegantly
smokestacklightnin Oct 29, 2024
d151b83
Add plan step
smokestacklightnin Oct 29, 2024
a6a609c
Add AWS account ID environment variable for OpenTofu to read
smokestacklightnin Oct 29, 2024
c9711d1
Fix typo for `AWS_REGION`
smokestacklightnin Oct 29, 2024
41c5f7a
Add permissions
smokestacklightnin Oct 29, 2024
89afd1b
Move deprecated workflows to `deprecated` directory
smokestacklightnin Oct 29, 2024
e7755ac
Add s3 permissions for troubleshooting
smokestacklightnin Oct 29, 2024
c5eaf30
Add more permissions for troubleshooting
smokestacklightnin Oct 29, 2024
1830426
Debug: add all possible permissions
smokestacklightnin Oct 29, 2024
d0c40cb
Fix typos
smokestacklightnin Oct 30, 2024
3aa608d
Change policy to reflect manual changes
smokestacklightnin Oct 30, 2024
83d9d55
Add missing `needs` section
smokestacklightnin Oct 30, 2024
30c075a
Change inputs to secrets
smokestacklightnin Oct 30, 2024
eb420bc
Deploy docker after deploying aws infrastructure with OpenTofu if Ope…
smokestacklightnin Oct 30, 2024
34ccbd3
Remove push trigger
smokestacklightnin Oct 30, 2024
90627a8
Don't deploy docker on pull request if infrastructure was changed
smokestacklightnin Oct 30, 2024
d851251
Add push trigger for development feedback and only apply OpenTofu if …
smokestacklightnin Oct 31, 2024
d28a7ca
Apply exact plan from plan step
smokestacklightnin Oct 31, 2024
2db3e44
Add ability to deploy OpenTofu with `workflow_dispatch` trigger
smokestacklightnin Oct 31, 2024
42690e3
Don't trigger on pushes to `main`
smokestacklightnin Oct 31, 2024
7effc71
Update push trigger
smokestacklightnin Oct 31, 2024
295c9eb
Add Let'sEncrypt config to `docker-compose.yaml`
smokestacklightnin Oct 31, 2024
d0623f5
Add config for public key
smokestacklightnin Oct 31, 2024
3ec76b6
try fix pre-commit
leej3 Oct 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading