Skip to content

Commit

Permalink
Deploy to AWS - Staging - via GitHub Actions (#193)
Browse files Browse the repository at this point in the history
* Use node 20.8.1 in Docker build

* Create a .env.local to allow build to run

* Add example env

* Copy example to local env

* Adjust .env.example to be valid for Docker build

* Enable standalone output to be used with Docker image

* Authenticate with AWS and push

* Print task def

* Store only task def itself in file

* Make the docker container listen on port 80

* Add /api/health endpoint to be used by AWS LB

* Revert "Make the docker container listen on port 80"

This reverts commit 602dcc0.

* Deploy specifically to staging
  • Loading branch information
ulrikandersen authored May 1, 2024
1 parent 3cccb56 commit 9d03a59
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 19 deletions.
19 changes: 19 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
AUTH0_BASE_URL='http://dev.local:3000'
AUTH0_CLIENT_ID='Your client ID'
AUTH0_CLIENT_SECRET='Your client secret'
AUTH0_ISSUER_BASE_URL='https://shape-docs-dev.eu.auth0.com'
AUTH0_MANAGEMENT_CLIENT_ID='Your client ID'
AUTH0_MANAGEMENT_CLIENT_SECRET='Your client secret'
AUTH0_MANAGEMENT_DOMAIN='shape-docs-dev.eu.auth0.com'
AUTH0_SECRET='use [openssl rand -hex 32] to generate a 32 bytes value'
GITHUB_APP_ID=123456
GITHUB_CLIENT_ID='GitHub App client ID'
GITHUB_CLIENT_SECRET='GitHub App client secret'
GITHUB_ORGANIZATION_NAME='shapehq'
GITHUB_PRIVATE_KEY_BASE_64='base 64 encoded version of the private key'
GITHUB_WEBHOK_REPOSITORY_ALLOWLIST=''
GITHUB_WEBHOK_REPOSITORY_DISALLOWLIST=''
GITHUB_WEBHOOK_SECRET='preshared secret also put in app conf in GitHub'
NEXT_PUBLIC_SHAPE_DOCS_TITLE='Shape Docs'
REDIS_URL=''
SHAPE_DOCS_BASE_URL='https://docs.shapetools.io'
82 changes: 82 additions & 0 deletions .github/workflows/build-and-deploy-staging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: "[Staging] Build and Deploy"

on:
workflow_dispatch: {}

env:
AWS_REGION: eu-central-1
ECR_REPOSITORY: shapedocs
ECS_SERVICE: StagingApp-AppService7F8F0CA1-jCcia0OvXEXa
ECS_CLUSTER: StagingApp-EcsDefaultClusterMnL3mNNYNVPC9C1EC7A3-L9xrshUBnmqe
ECS_TASK_DEFINITION_NAME: StagingAppAppServiceTaskDef1613562E
CONTAINER_NAME: web
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_SHAPE_DOCS }}

jobs:
build:
name: Build
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install 1Password CLI
uses: 1password/install-cli-action@v1

- name: Install AWS credentials from 1Password
run: |
AWS_ACCESS_KEY_ID=$(op read "op://Shape Docs GitHub Actions/AWS GitHub Actions User/access_key_id")
AWS_SECRET_ACCESS_KEY=$(op read "op://Shape Docs GitHub Actions/AWS GitHub Actions User/secret_access_key")
echo "AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" >> $GITHUB_ENV
echo "AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" >> $GITHUB_ENV
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.0.1
with:
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

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

- name: Fetch task definition
id: fetch-task-definition
run: |
aws ecs describe-task-definition --task-definition ${{ env.ECS_TASK_DEFINITION_NAME }} --region ${{ env.AWS_REGION }} | jq .taskDefinition > task-definition.json
jq . task-definition.json
- name: Create .env.local
run: |
cp .env.example .env.local
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
# Build a docker image and push it to ECR so that it can
# be deployed to ECS
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1.2.0
with:
task-definition: task-definition.json
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.build-image.outputs.image }}

- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1.4.11
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true
16 changes: 0 additions & 16 deletions .github/workflows/build-docker-image.yml

This file was deleted.

2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:18-alpine AS base
FROM node:20.8.1-alpine AS base

# Install dependencies only when needed
FROM base AS deps
Expand Down
4 changes: 3 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ const nextConfig = {
// Allows production builds to successfully complete even if it has linting errors.
// This is only OK because we do linting as part of our CI setup.
ignoreDuringBuilds: true,
}
},
// Output standalone to be used for Docker builds.
output: 'standalone',
}

module.exports = nextConfig
5 changes: 5 additions & 0 deletions src/app/api/health/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { NextResponse } from "next/server"

export const GET = async (): Promise<NextResponse> => {
return NextResponse.json({ status: "Healthy" })
}
2 changes: 1 addition & 1 deletion src/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { withMiddlewareAuthRequired } from "@auth0/nextjs-auth0/edge"

export const config = {
matcher: "/((?!api/hooks|api/auth/logout|api/auth/forceLogout|_next/static|_next/image|images|favicon.ico).*)"
matcher: "/((?!api/hooks|api/auth/logout|api/auth/forceLogout|api/health|_next/static|_next/image|images|favicon.ico).*)"
}

export default withMiddlewareAuthRequired()

0 comments on commit 9d03a59

Please sign in to comment.