-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from nickpettican/infra-as-code
Infrastructure as code
- Loading branch information
Showing
16 changed files
with
5,828 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
cd server && npm run qc; | ||
cd ..; | ||
cd client && npm run qc; | ||
cd client && npm run qc; | ||
cd ..; | ||
cd infra && npm run qc; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
*.js | ||
!jest.config.js | ||
*.d.ts | ||
node_modules | ||
|
||
# CDK asset staging directory | ||
.cdk.staging | ||
cdk.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
*.ts | ||
!*.d.ts | ||
|
||
# CDK asset staging directory | ||
.cdk.staging | ||
cdk.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"semi": true, | ||
"singleQuote": false, | ||
"printWidth": 80, | ||
"trailingComma": "none", | ||
"tabWidth": 4 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
# Infrastructure Setup | ||
|
||
This directory contains the AWS CDK infrastructure code for the Offering Bowl platform. The infrastructure is designed to be cost-effective while maintaining scalability, using AWS free tier resources where possible. | ||
|
||
## Architecture Overview | ||
|
||
This is the current architecture for stage 1 (prototype). | ||
|
||
- **Frontend**: Served from S3 through CloudFront (static website hosting) | ||
- **Backend**: Single t2.micro EC2 instance running two Docker containers for the API | ||
- **Database**: DynamoDB tables with on-demand pricing | ||
- **Load Balancing**: Application Load Balancer (free tier eligible) | ||
|
||
## Directory Structure | ||
|
||
``` | ||
infra/ | ||
├── bin/ | ||
│ └── app.ts # CDK app entry point | ||
├── lib/ | ||
│ ├── constructs/ | ||
│ │ └── database.ts # DynamoDB tables construct | ||
│ └── stacks/ | ||
│ └── main-stack.ts # Main infrastructure stack | ||
└── README.md | ||
``` | ||
|
||
## Development Setup | ||
|
||
### Prerequisites | ||
|
||
1. AWS CLI installed and configured | ||
2. Node.js and npm installed | ||
3. AWS CDK CLI installed (`npm install -g aws-cdk`) | ||
4. Docker installed for local development | ||
|
||
### Database Tables | ||
|
||
The following DynamoDB tables are defined in `constructs/database.ts`: | ||
|
||
- Users (with role-index GSI) | ||
- Settings (with userId-index GSI) | ||
- Profile (with userId-index GSI) | ||
- Activities (with userId-index GSI) | ||
- Contracts (with patronId-monasticId-index GSI) | ||
- Posts (with monasticId-index GSI) | ||
- Receipts (with contractId-index GSI) | ||
- Media | ||
|
||
## Testing and Staging | ||
|
||
### Development/Testing Workflow | ||
|
||
You can safely deploy and tear down the infrastructure for testing: | ||
|
||
1. Deploy staging environment: | ||
|
||
```bash | ||
cdk deploy StagingStack | ||
``` | ||
|
||
2. Test the infrastructure | ||
|
||
3. Tear down when done: | ||
|
||
```bash | ||
cdk destroy StagingStack | ||
``` | ||
|
||
### Environment Management | ||
|
||
The infrastructure supports multiple environments: | ||
|
||
- **Staging**: For testing infrastructure changes | ||
|
||
- Uses `RemovalPolicy.DESTROY` for easy cleanup | ||
- Same setup as production but allows easy teardown | ||
- Perfect for testing autoscaling configurations | ||
|
||
- **Production**: Live environment | ||
|
||
- Uses `RemovalPolicy.RETAIN` for data protection | ||
- More restricted security settings | ||
- Changes require careful planning | ||
|
||
### Scaling Scenarios | ||
|
||
The infrastructure is designed to evolve with your needs: | ||
|
||
1. **Initial Setup** (Current) | ||
|
||
- Single t2.micro EC2 instance | ||
- Two Docker containers with ALB | ||
- Perfect for prototype/MVP phase | ||
|
||
2. **Autoscaling Ready** | ||
|
||
- When high usage notifications arrive: | ||
- Infrastructure code for autoscaling is prepared | ||
- Can switch from single EC2 to autoscaling group | ||
- Allows testing autoscaling in staging first | ||
|
||
### Migration Process | ||
|
||
When ready to implement autoscaling: | ||
|
||
1. Test in staging: | ||
|
||
- Deploy autoscaling configuration | ||
- Verify scaling behaviors | ||
- Test monitoring and alerts | ||
- Practice rollback procedures | ||
|
||
2. Production migration: | ||
|
||
- Take snapshot of production EC2 for AMI | ||
- Deploy autoscaling infrastructure | ||
- Gradually move traffic over | ||
- Maintain single EC2 until migration complete | ||
|
||
### Monitoring and Alerts | ||
|
||
The infrastructure includes CloudWatch alarms for: | ||
|
||
- CPU Usage (>80% threshold) | ||
- Request Count (>1000/minute threshold) | ||
- Notifications sent to configured email addresses | ||
|
||
This helps identify when to consider scaling up the infrastructure. | ||
|
||
Remember to accept the initial SNS subscription email to receive alerts. | ||
|
||
## Deployment | ||
|
||
### First Time Setup | ||
|
||
1. Install dependencies: | ||
|
||
```bash | ||
cd infra | ||
npm install | ||
``` | ||
|
||
2. Bootstrap CDK (first time only): | ||
|
||
```bash | ||
cdk bootstrap | ||
``` | ||
|
||
### Deploying to Production | ||
|
||
Deploy the entire stack: | ||
|
||
```bash | ||
cdk deploy | ||
``` | ||
|
||
This will: | ||
|
||
1. Create/update all DynamoDB tables | ||
2. Set up the EC2 instance with Docker | ||
3. Configure the Application Load Balancer | ||
4. Set up S3 and CloudFront for the frontend | ||
|
||
### Cost Optimization | ||
|
||
The infrastructure is designed to use AWS free tier resources: | ||
|
||
- EC2: t2.micro instance (750 hours/month free for 12 months) | ||
- Application Load Balancer (750 hours/month free for 12 months) | ||
- DynamoDB: On-demand pricing (minimal costs for low traffic) | ||
- S3/CloudFront: Pay as you go (minimal for small applications) | ||
|
||
### Future Scaling | ||
|
||
When ready to scale beyond free tier: | ||
|
||
1. Migrate to ECS for better container orchestration | ||
2. Add auto-scaling groups for EC2 instances | ||
3. Implement CloudWatch alarms for scaling triggers | ||
|
||
## Troubleshooting | ||
|
||
### Common Issues | ||
|
||
1. DynamoDB Tables not creating locally: | ||
|
||
- Check Docker logs: `docker compose logs dynamodb-local` | ||
- Verify port mappings in docker-compose.yml | ||
|
||
2. EC2 instance not starting: | ||
|
||
- Check instance logs in AWS Console | ||
- Verify security group settings | ||
|
||
### Useful Commands | ||
|
||
```bash | ||
# List deployed stacks | ||
cdk ls | ||
|
||
# Compare deployed stack with current state | ||
cdk diff | ||
|
||
# Destroy stack (careful in production!) | ||
cdk destroy | ||
|
||
# Check DynamoDB tables locally | ||
aws dynamodb list-tables --endpoint-url http://localhost:8000 | ||
``` | ||
|
||
#### Other useful commands | ||
|
||
- `npm run build` compile typescript to js | ||
- `npm run watch` watch for changes and compile | ||
- `npm run test` perform the jest unit tests | ||
- `npx cdk deploy` deploy this stack to your default AWS account/region | ||
- `npx cdk diff` compare deployed stack with current state | ||
- `npx cdk synth` emits the synthesized CloudFormation template | ||
|
||
## Security | ||
|
||
- EC2 instance role has minimal required permissions | ||
- DynamoDB tables use encryption at rest | ||
- CloudFront uses HTTPS only | ||
- Security groups restrict access appropriately | ||
|
||
## Contributing | ||
|
||
1. Create a feature branch | ||
2. Make infrastructure changes | ||
3. Run `cdk diff` to verify changes | ||
4. Submit a pull request | ||
|
||
For significant infrastructure changes, please update this README and provide context in the PR. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#!/usr/bin/env node | ||
import * as cdk from "aws-cdk-lib"; | ||
import * as ec2 from "aws-cdk-lib/aws-ec2"; | ||
import { InfraStack } from "../lib/stacks/main-stack"; | ||
|
||
const app = new cdk.App(); | ||
|
||
// Development/Staging stack | ||
new InfraStack(app, "StagingStack", { | ||
env: { | ||
account: process.env.CDK_DEFAULT_ACCOUNT, | ||
region: process.env.CDK_DEFAULT_REGION | ||
}, | ||
stagingConfig: { | ||
removalPolicy: cdk.RemovalPolicy.DESTROY, // For easy cleanup | ||
instanceType: ec2.InstanceType.of( | ||
ec2.InstanceClass.T2, | ||
ec2.InstanceSize.MICRO | ||
) | ||
} | ||
}); | ||
|
||
// Production stack | ||
new InfraStack(app, "ProductionStack", { | ||
env: { | ||
account: process.env.CDK_DEFAULT_ACCOUNT, | ||
region: "us-east-1" | ||
}, | ||
productionConfig: { | ||
removalPolicy: cdk.RemovalPolicy.RETAIN, | ||
instanceType: ec2.InstanceType.of( | ||
ec2.InstanceClass.T2, | ||
ec2.InstanceSize.MICRO | ||
) | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
{ | ||
"app": "npx ts-node --prefer-ts-exts bin/infra.ts", | ||
"watch": { | ||
"include": ["**"], | ||
"exclude": [ | ||
"README.md", | ||
"cdk*.json", | ||
"**/*.d.ts", | ||
"**/*.js", | ||
"tsconfig.json", | ||
"package*.json", | ||
"yarn.lock", | ||
"node_modules", | ||
"test" | ||
] | ||
}, | ||
"context": { | ||
"@aws-cdk/aws-lambda:recognizeLayerVersion": true, | ||
"@aws-cdk/core:checkSecretUsage": true, | ||
"@aws-cdk/core:target-partitions": ["aws", "aws-cn"], | ||
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, | ||
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, | ||
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, | ||
"@aws-cdk/aws-iam:minimizePolicies": true, | ||
"@aws-cdk/core:validateSnapshotRemovalPolicy": true, | ||
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, | ||
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, | ||
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, | ||
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true, | ||
"@aws-cdk/core:enablePartitionLiterals": true, | ||
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, | ||
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, | ||
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, | ||
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, | ||
"@aws-cdk/aws-route53-patters:useCertificate": true, | ||
"@aws-cdk/customresources:installLatestAwsSdkDefault": false, | ||
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, | ||
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, | ||
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, | ||
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, | ||
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, | ||
"@aws-cdk/aws-redshift:columnId": true, | ||
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, | ||
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, | ||
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, | ||
"@aws-cdk/aws-kms:aliasNameRef": true, | ||
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, | ||
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true, | ||
"@aws-cdk/aws-efs:denyAnonymousAccess": true, | ||
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, | ||
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, | ||
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, | ||
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, | ||
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, | ||
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, | ||
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, | ||
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, | ||
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, | ||
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, | ||
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, | ||
"@aws-cdk/aws-eks:nodegroupNameAttribute": true, | ||
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, | ||
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, | ||
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, | ||
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false, | ||
"@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true, | ||
"@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true, | ||
"@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true, | ||
"@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true, | ||
"@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true, | ||
"@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true, | ||
"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true, | ||
"@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module.exports = { | ||
testEnvironment: "node", | ||
roots: ["<rootDir>/test"], | ||
testMatch: ["**/*.test.ts"], | ||
transform: { | ||
"^.+\\.tsx?$": "ts-jest" | ||
}, | ||
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"] | ||
}; |
Oops, something went wrong.