Skip to content

[TM-1273] AWS Deployment #5

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

Merged
merged 31 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
fab68e6
[TM-1273] Configuration for creating a docker image for the user serv…
roguenet Oct 9, 2024
f380dc4
[TM-1273] WIP action definition for building and pushing the docker i…
roguenet Oct 9, 2024
029a847
[TM-1273] Pull env from repo secrets.
roguenet Oct 15, 2024
84af076
[TM-1273] Default to port 80 for prod deployments.
roguenet Oct 15, 2024
b2d0358
[TM-1273] Try setting the node env differently.
roguenet Oct 15, 2024
9f62d18
[TM-1273] Don't colorize messages in prod, it makes the output hard t…
roguenet Oct 16, 2024
b035846
[TM-1273] Make this file user service specific.
roguenet Oct 16, 2024
03c94de
[TM-1273] Encode the service name in the repository
roguenet Oct 16, 2024
8c43ac2
[TM-1273] Implement a health check endpoint.
roguenet Oct 16, 2024
aa7b668
[TM-1273] CDK definition for the user service fargate deployment.
roguenet Oct 16, 2024
142bb46
[TM-1273] Don't specify NODE_ENV for the whole task
roguenet Oct 16, 2024
40e86b3
[TM-1312] CDK deployment working.
roguenet Oct 17, 2024
4ef5a19
[TM-1273] Add a tag for easy identification
roguenet Oct 21, 2024
29d2d85
[TM-1273] Isolate the log stream by env
roguenet Oct 21, 2024
8b582af
[TM-1273] use the Github Environments feature.
roguenet Oct 21, 2024
d658614
[TM-1273] add the DB security group for the env.
roguenet Oct 21, 2024
3c5dd15
[TM-1273] Add deployment script for github to deploy the gateway.
roguenet Oct 22, 2024
af2c0b9
[TM-1273] see if the env is getting set up correctly.
roguenet Oct 22, 2024
79475fd
[TM-1273] Remove debug logging.
roguenet Oct 22, 2024
8cbddff
[TM-1273] Make the API Gateway deploy better env aware
roguenet Oct 22, 2024
5f7cf47
[TM-1273] Use specific imports.
roguenet Oct 22, 2024
329376d
[TM-1273] Isolate the stack name by env
roguenet Oct 22, 2024
8097e11
[TM-1273] Get local dev working again.
roguenet Oct 22, 2024
b3f5f1b
[TM-1273] No reason to minify this local-only build.
roguenet Oct 22, 2024
e3d053f
[TM-1273] Turns out this is supposed to be versioned.
roguenet Oct 22, 2024
0c03663
[TM-1273] Minor README update.
roguenet Oct 22, 2024
3db5ba4
[TM-1273] Update to the latest CDK
roguenet Oct 22, 2024
d4af4c2
[TM-1273] Use the built version of the lambda
roguenet Oct 22, 2024
7d2b6f0
[TM-1273] Don't allow OPTIONS to leak through to the service.
roguenet Oct 22, 2024
68b4ff8
[TM-1273] Fix PR actions flow.
roguenet Oct 22, 2024
0d96c71
[TM-1273] Allow customizing the architecture to match the host machine.
roguenet Oct 22, 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
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
tmp
.vscode
47 changes: 47 additions & 0 deletions .github/workflows/deploy-api-gateway.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Api Gateway Deploy

on:
workflow_dispatch:
inputs:
env:
description: 'Deployment target environment'
type: choice
required: true
options:
- dev
- test
- staging
- prod

permissions:
id-token: write
contents: read

env:
NODE_ENV: production
AWS_REGION: eu-west-1
AWS_ROLE_TO_ASSUME: arn:aws:iam::603634817705:role/terramatch-microservices-github-actions
AWS_ROLE_SESSION_NAME: terramatch-microservices-cicd-api-gateway
PHP_PROXY_TARGET: ${{ vars.PHP_PROXY_TARGET }}

jobs:
main:
runs-on: ubuntu-latest
environment: ${{ inputs.env }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.0.2
with:
role-to-assume: ${{ env.AWS_ROLE_TO_ASSUME }}
role-session-name: ${{ env.AWS_ROLE_SESSION_NAME }}
aws-region: ${{ env.AWS_REGION }}

- name: CDK Deploy
id: cdk-deploy
run: |
cd apps/api-gateway
NODE_ENV=development npm i
TM_ENV=${{ inputs.env }} npx --yes cdk deploy --require-approval never
65 changes: 65 additions & 0 deletions .github/workflows/deploy-user-service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: User Service Deploy

on:
workflow_dispatch:
inputs:
env:
description: 'Deployment target environment'
type: choice
required: true
options:
- dev
- test
- staging
- prod

permissions:
id-token: write
contents: read

env:
AWS_REGION: eu-west-1
AWS_ROLE_TO_ASSUME: arn:aws:iam::603634817705:role/terramatch-microservices-github-actions
AWS_ROLE_SESSION_NAME: terramatch-microservices-cicd-user-service
ECR_REPOSITORY: terramatch-microservices/user-service-${{ inputs.env }}
ECR_REGISTRY: 603634817705.dkr.ecr.eu-west-1.amazonaws.com
IMAGE_TAG: ${{ github.sha }}

jobs:
main:
runs-on: ubuntu-latest
environment: ${{ inputs.env }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.0.2
with:
role-to-assume: ${{ env.AWS_ROLE_TO_ASSUME }}
role-session-name: ${{ env.AWS_ROLE_SESSION_NAME }}
aws-region: ${{ env.AWS_REGION }}

- name: Login to AWS
id: AWS
uses: aws-actions/amazon-ecr-login@v1

- name: Build, tag, and push images to Amazon ECR
id: build-images
run: |
echo "${{ vars.ENV }}" > .env
echo "DB_PASSWORD=\"${{ secrets.DB_PASSWORD }}\"" >> .env
: # Don't build the base image with NODE_ENV because it'll limit the packages that are installed
docker build -t terramatch-microservices-base:nx-base .
USER_SERVICE_IMAGE=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker build --build-arg NODE_ENV=production --build-arg BUILD_FLAG=--prod -f apps/user-service/Dockerfile -t $USER_SERVICE_IMAGE .
docker push $USER_SERVICE_IMAGE
echo "image=$USER_SERVICE_IMAGE"

- name: Launch new task definition
id: launch
run: |
cd apps/user-service/stack
npm i
IMAGE_TAG=$IMAGE_TAG TM_ENV=${{ inputs.env }} npx --yes cdk deploy --require-approval never

14 changes: 7 additions & 7 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,11 @@ jobs:
with:
fetch-depth: 0

- uses: KengoTODA/actions-setup-docker-compose@v1
with:
version: '2.29.1'

# This enables task distribution via Nx Cloud
# Run this command as early as possible, before dependencies are installed
# Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun
- run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="build"

- run: docker-compose up -d

# Cache node_modules
- uses: actions/setup-node@v4
with:
Expand All @@ -43,6 +37,12 @@ jobs:
# cacheable. Since the codebase is currently small, we can get away without distribution, but once
# it grows, we'll want to look into what it will take to make the api gateway build cacheable and remove
# NX_CLOUD_DISTRIBUTED_EXECUTION=false from this command.
- run: NX_CLOUD_DISTRIBUTED_EXECUTION=false npx nx affected -t lint build
- run: NX_CLOUD_DISTRIBUTED_EXECUTION=false ARCH=X86 npx nx affected -t lint build

- uses: KengoTODA/actions-setup-docker-compose@v1
with:
version: '2.29.1'

- run: docker-compose up -d

- run: NX_CLOUD_DISTRIBUTED_EXECUTION=false npx nx run-many -t test --coverage --passWithNoTests
1 change: 1 addition & 0 deletions .nxignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
apps/*/stack
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM node:lts-alpine3.19 as builder
ARG NODE_ENV
ARG BUILD_FLAG

WORKDIR /app/builder
COPY . .
RUN npm i
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ Repository for the Microservices API backend of the TerraMatch service
* The ApiGateway does not hot-reload and needs to be re-built when there are changes:
* `nx build api-gateway` or `nx run-many -t build` (to build all apps)
* This will build the local proxy Lambda function and the CDK Stack
* Note: The architecture for the local lambda proxy defaults to ARM_64. This will be the fastest options on ARM-based Macs
(M1, etc), but will be much slower on X86 (AMD/Intel) based machine. If you're on an X86 machine, pass the architecture in
an environment variable when building the api gateway: `ARCH=X86 nx build api-gateway`.
* To run all services:
* `nx run-many -t serve`
* Note: the first time this runs, the gateway will take quite awhile to start. It'll be faster on subsequent starts.
Expand All @@ -22,8 +25,12 @@ Repository for the Microservices API backend of the TerraMatch service
* `NEXT_PUBLIC_API_BASE_URL='http://localhost:4000'`

# Deployment
TBD. The ApiGateway has been tested to be at least functional on AWS. Tooling around deployment will be
handled in a future ticket.
Deployment is handled via manual trigger of GitHub actions. There is one for each service, and one for the ApiGateway. The
ApiGateway only needs to be redeployed if its code changes; it does not need to be redeployed for updates to individual services
to take effect.

Once this project is live in production, we can explore continuous deployment to at least staging and prod envs on the staging
and main branches.

# Database work
For now, Laravel is the source of truth for all things related to the DB schema. As such, TypeORM is not allowed to modify the
Expand Down
18 changes: 3 additions & 15 deletions apps/api-gateway/bin/api-gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,6 @@ import * as cdk from 'aws-cdk-lib';
import { ApiGatewayStack } from '../lib/api-gateway-stack';

const app = new cdk.App();
new ApiGatewayStack(app, 'ApiGatewayStack', {
/* If you don't specify 'env', this stack will be environment-agnostic.
* Account/Region-dependent features and context lookups will not work,
* but a single synthesized template can be deployed anywhere. */

/* Uncomment the next line to specialize this stack for the AWS Account
* and Region that are implied by the current CLI configuration. */
// env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },

/* Uncomment the next line if you know exactly what Account and Region you
* want to deploy the stack to. */
// env: { account: '123456789012', region: 'us-east-1' },

/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
});
new ApiGatewayStack(app, `ApiGatewayStack-${process.env.TM_ENV ?? 'local'}`, {
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
71 changes: 71 additions & 0 deletions apps/api-gateway/cdk.context.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"vpc-provider:account=603634817705:filter.vpc-id=vpc-0beac5973796d96b1:region=eu-west-1:returnAsymmetricSubnets=true": {
"vpcId": "vpc-0beac5973796d96b1",
"vpcCidrBlock": "10.0.0.0/16",
"ownerAccountId": "603634817705",
"availabilityZones": [],
"subnetGroups": [
{
"name": "Private",
"type": "Private",
"subnets": [
{
"subnetId": "subnet-065992a829eb772a3",
"cidr": "10.0.128.0/20",
"availabilityZone": "eu-west-1a",
"routeTableId": "rtb-07f85b7827c451bc9"
},
{
"subnetId": "subnet-0f48d0681051fa49a",
"cidr": "10.0.144.0/20",
"availabilityZone": "eu-west-1b",
"routeTableId": "rtb-06afefb0f592f11d6"
}
]
},
{
"name": "Public",
"type": "Public",
"subnets": [
{
"subnetId": "subnet-0a099d863485e6c39",
"cidr": "10.0.0.0/20",
"availabilityZone": "eu-west-1a",
"routeTableId": "rtb-001c321e760157b3b"
},
{
"subnetId": "subnet-0a91312f58b03ad3f",
"cidr": "10.0.16.0/20",
"availabilityZone": "eu-west-1b",
"routeTableId": "rtb-001c321e760157b3b"
}
]
}
]
},
"load-balancer:account=603634817705:loadBalancerTags.0.key=service:loadBalancerTags.0.value=user-service-test:loadBalancerType=application:region=eu-west-1": {
"loadBalancerArn": "arn:aws:elasticloadbalancing:eu-west-1:603634817705:loadbalancer/app/user-service-test/e1ee1ce635080238",
"loadBalancerCanonicalHostedZoneId": "Z32O12XQLNTSW2",
"loadBalancerDnsName": "internal-user-service-test-1863479300.eu-west-1.elb.amazonaws.com",
"vpcId": "vpc-0beac5973796d96b1",
"securityGroupIds": [
"sg-06a4b12aa14e529be"
],
"ipAddressType": "ipv4"
},
"security-group:account=603634817705:region=eu-west-1:securityGroupId=sg-06a4b12aa14e529be": {
"securityGroupId": "sg-06a4b12aa14e529be",
"allowAllOutbound": false
},
"security-group:account=603634817705:region=eu-west-1:securityGroupName=default:vpcId=vpc-0beac5973796d96b1": {
"securityGroupId": "sg-0fcff87239114297b",
"allowAllOutbound": false
},
"load-balancer-listener:account=603634817705:loadBalancerTags.0.key=service:loadBalancerTags.0.value=user-service-test:loadBalancerType=application:region=eu-west-1": {
"listenerArn": "arn:aws:elasticloadbalancing:eu-west-1:603634817705:listener/app/user-service-test/e1ee1ce635080238/069ab4638dd50686",
"listenerPort": 80,
"securityGroupIds": [
"sg-06a4b12aa14e529be"
]
}
}
Loading