cdk-cost-analyzer 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cdk-cost-analyzer-cache/metadata.json +12 -0
- package/.gitlab-ci.yml +214 -0
- package/.husky/pre-commit +12 -0
- package/.kiro/hooks/accessibility-audit.kiro.hook +18 -0
- package/.kiro/hooks/api-schema-validation.kiro.hook +21 -0
- package/.kiro/hooks/auto-test-on-save.kiro.hook +19 -0
- package/.kiro/hooks/cdk-synth-on-change.kiro.hook +20 -0
- package/.kiro/hooks/code-coverage-check.kiro.hook +14 -0
- package/.kiro/hooks/commit-message-helper.kiro.hook +14 -0
- package/.kiro/hooks/dependency-update-check.kiro.hook +14 -0
- package/.kiro/hooks/env-file-validation.kiro.hook +18 -0
- package/.kiro/hooks/lint-and-format-on-save.kiro.hook +21 -0
- package/.kiro/hooks/mcp-config-validation.kiro.hook +17 -0
- package/.kiro/hooks/mcp-server-test.kiro.hook +14 -0
- package/.kiro/hooks/performance-analysis.kiro.hook +14 -0
- package/.kiro/hooks/readme-spell-check.kiro.hook +14 -0
- package/.kiro/hooks/security-scan-on-dependency-change.kiro.hook +21 -0
- package/.kiro/hooks/translation-update.kiro.hook +18 -0
- package/.kiro/hooks/update-documentation.kiro.hook +18 -0
- package/.kiro/settings/mcp.json +20 -0
- package/.kiro/specs/cdk-cost-analyzer/design.md +620 -0
- package/.kiro/specs/cdk-cost-analyzer/requirements.md +183 -0
- package/.kiro/specs/cdk-cost-analyzer/tasks.md +357 -0
- package/.kiro/specs/github-actions-ci/design.md +281 -0
- package/.kiro/specs/github-actions-ci/requirements.md +86 -0
- package/.kiro/specs/github-actions-ci/tasks.md +115 -0
- package/.kiro/specs/nlb-calculator-test-coverage/design.md +190 -0
- package/.kiro/specs/nlb-calculator-test-coverage/requirements.md +84 -0
- package/.kiro/specs/nlb-calculator-test-coverage/tasks.md +150 -0
- package/.kiro/specs/production-readiness/design.md +1213 -0
- package/.kiro/specs/production-readiness/requirements.md +312 -0
- package/.kiro/specs/production-readiness/tasks.md +269 -0
- package/.kiro/specs/repository-cleanup/design.md +283 -0
- package/.kiro/specs/repository-cleanup/requirements.md +74 -0
- package/.kiro/specs/repository-cleanup/tasks.md +64 -0
- package/.kiro/steering/aws-cli-best-practices.md +41 -0
- package/.kiro/steering/cdk-best-practices.md +49 -0
- package/.kiro/steering/development-standards.md +54 -0
- package/.kiro/steering/docker-best-practices.md +34 -0
- package/.kiro/steering/documentation-style.md +151 -0
- package/.kiro/steering/git-best-practices.md +37 -0
- package/.kiro/steering/mcp-best-practices.md +95 -0
- package/.kiro/steering/python-best-practices.md +48 -0
- package/.kiro/steering/react-best-practices.md +44 -0
- package/.kiro/steering/security-best-practices.md +41 -0
- package/.kiro/steering/testing-best-practices.md +59 -0
- package/.kiro/steering/typescript-best-practices.md +40 -0
- package/CHANGELOG.md +49 -0
- package/CONTRIBUTING.md +258 -0
- package/LICENSE +19 -0
- package/README.md +480 -0
- package/SECURITY.md +117 -0
- package/dist/api/index.d.ts +11 -0
- package/dist/api/index.js +65 -0
- package/dist/api/types.d.ts +15 -0
- package/dist/api/types.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +262 -0
- package/dist/config/ConfigManager.d.ts +40 -0
- package/dist/config/ConfigManager.js +238 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +19 -0
- package/dist/config/types.d.ts +72 -0
- package/dist/config/types.js +15 -0
- package/dist/diff/DiffEngine.d.ts +7 -0
- package/dist/diff/DiffEngine.js +73 -0
- package/dist/diff/index.d.ts +2 -0
- package/dist/diff/index.js +21 -0
- package/dist/diff/types.d.ts +20 -0
- package/dist/diff/types.js +3 -0
- package/dist/integrations/GitLabIntegration.d.ts +7 -0
- package/dist/integrations/GitLabIntegration.js +45 -0
- package/dist/integrations/index.d.ts +2 -0
- package/dist/integrations/index.js +21 -0
- package/dist/integrations/types.d.ts +11 -0
- package/dist/integrations/types.js +13 -0
- package/dist/parser/TemplateParser.d.ts +8 -0
- package/dist/parser/TemplateParser.js +75 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.js +22 -0
- package/dist/parser/types.d.ts +30 -0
- package/dist/parser/types.js +3 -0
- package/dist/pipeline/PipelineOrchestrator.d.ts +23 -0
- package/dist/pipeline/PipelineOrchestrator.js +191 -0
- package/dist/pipeline/index.d.ts +2 -0
- package/dist/pipeline/index.js +19 -0
- package/dist/pipeline/types.d.ts +41 -0
- package/dist/pipeline/types.js +13 -0
- package/dist/pricing/CacheManager.d.ts +75 -0
- package/dist/pricing/CacheManager.js +195 -0
- package/dist/pricing/PricingClient.d.ts +17 -0
- package/dist/pricing/PricingClient.js +122 -0
- package/dist/pricing/PricingService.d.ts +16 -0
- package/dist/pricing/PricingService.js +149 -0
- package/dist/pricing/calculators/ALBCalculator.d.ts +16 -0
- package/dist/pricing/calculators/ALBCalculator.js +163 -0
- package/dist/pricing/calculators/APIGatewayCalculator.d.ts +10 -0
- package/dist/pricing/calculators/APIGatewayCalculator.js +177 -0
- package/dist/pricing/calculators/CloudFrontCalculator.d.ts +59 -0
- package/dist/pricing/calculators/CloudFrontCalculator.js +151 -0
- package/dist/pricing/calculators/DynamoDBCalculator.d.ts +9 -0
- package/dist/pricing/calculators/DynamoDBCalculator.js +146 -0
- package/dist/pricing/calculators/EC2Calculator.d.ts +7 -0
- package/dist/pricing/calculators/EC2Calculator.js +80 -0
- package/dist/pricing/calculators/ECSCalculator.d.ts +9 -0
- package/dist/pricing/calculators/ECSCalculator.js +116 -0
- package/dist/pricing/calculators/ElastiCacheCalculator.d.ts +8 -0
- package/dist/pricing/calculators/ElastiCacheCalculator.js +106 -0
- package/dist/pricing/calculators/LambdaCalculator.d.ts +13 -0
- package/dist/pricing/calculators/LambdaCalculator.js +111 -0
- package/dist/pricing/calculators/NLBCalculator.d.ts +16 -0
- package/dist/pricing/calculators/NLBCalculator.js +138 -0
- package/dist/pricing/calculators/NatGatewayCalculator.d.ts +12 -0
- package/dist/pricing/calculators/NatGatewayCalculator.js +116 -0
- package/dist/pricing/calculators/RDSCalculator.d.ts +9 -0
- package/dist/pricing/calculators/RDSCalculator.js +103 -0
- package/dist/pricing/calculators/S3Calculator.d.ts +8 -0
- package/dist/pricing/calculators/S3Calculator.js +68 -0
- package/dist/pricing/calculators/VPCEndpointCalculator.d.ts +12 -0
- package/dist/pricing/calculators/VPCEndpointCalculator.js +129 -0
- package/dist/pricing/index.d.ts +10 -0
- package/dist/pricing/index.js +37 -0
- package/dist/pricing/types.d.ts +53 -0
- package/dist/pricing/types.js +22 -0
- package/dist/releasetag.txt +1 -0
- package/dist/reporter/Reporter.d.ts +18 -0
- package/dist/reporter/Reporter.js +412 -0
- package/dist/reporter/index.d.ts +2 -0
- package/dist/reporter/index.js +21 -0
- package/dist/reporter/types.d.ts +72 -0
- package/dist/reporter/types.js +3 -0
- package/dist/synthesis/SynthesisOrchestrator.d.ts +26 -0
- package/dist/synthesis/SynthesisOrchestrator.js +243 -0
- package/dist/synthesis/index.d.ts +2 -0
- package/dist/synthesis/index.js +19 -0
- package/dist/synthesis/types.d.ts +17 -0
- package/dist/synthesis/types.js +13 -0
- package/dist/threshold/ThresholdEnforcer.d.ts +29 -0
- package/dist/threshold/ThresholdEnforcer.js +143 -0
- package/dist/threshold/index.d.ts +2 -0
- package/dist/threshold/index.js +19 -0
- package/dist/threshold/types.d.ts +15 -0
- package/dist/threshold/types.js +17 -0
- package/docs/CALCULATORS.md +820 -0
- package/docs/CI_CD.md +608 -0
- package/docs/CONFIGURATION.md +407 -0
- package/docs/DEVELOPMENT.md +387 -0
- package/docs/RELEASE.md +223 -0
- package/docs/TROUBLESHOOTING.md +847 -0
- package/examples/.cdk-cost-analyzer.yml +85 -0
- package/examples/.gitlab-ci.yml +125 -0
- package/examples/api-usage.js +26 -0
- package/examples/complex/base.json +16 -0
- package/examples/complex/target.json +29 -0
- package/examples/monorepo/.gitlab-ci.yml +251 -0
- package/examples/monorepo/README.md +341 -0
- package/examples/monorepo/package.json +27 -0
- package/examples/monorepo/packages/backend-infra/.cdk-cost-analyzer.yml +34 -0
- package/examples/monorepo/packages/backend-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/backend-infra/cdk.json +7 -0
- package/examples/monorepo/packages/backend-infra/lib/backend-stack.ts +128 -0
- package/examples/monorepo/packages/backend-infra/package.json +30 -0
- package/examples/monorepo/packages/backend-infra/tsconfig.json +11 -0
- package/examples/monorepo/packages/data-infra/.cdk-cost-analyzer.yml +38 -0
- package/examples/monorepo/packages/data-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/data-infra/cdk.json +7 -0
- package/examples/monorepo/packages/data-infra/lib/data-stack.ts +121 -0
- package/examples/monorepo/packages/data-infra/package.json +30 -0
- package/examples/monorepo/packages/data-infra/tsconfig.json +11 -0
- package/examples/monorepo/packages/frontend-infra/.cdk-cost-analyzer.yml +31 -0
- package/examples/monorepo/packages/frontend-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/frontend-infra/cdk.json +7 -0
- package/examples/monorepo/packages/frontend-infra/lib/frontend-stack.ts +60 -0
- package/examples/monorepo/packages/frontend-infra/package.json +30 -0
- package/examples/monorepo/packages/frontend-infra/tsconfig.json +11 -0
- package/examples/monorepo/tsconfig.json +35 -0
- package/examples/multi-stack/.cdk-cost-analyzer.yml +72 -0
- package/examples/multi-stack/.gitlab-ci.yml +184 -0
- package/examples/multi-stack/README.md +279 -0
- package/examples/multi-stack/bin/app.ts +36 -0
- package/examples/multi-stack/cdk.json +72 -0
- package/examples/multi-stack/lib/compute-stack.ts +128 -0
- package/examples/multi-stack/lib/networking-stack.ts +69 -0
- package/examples/multi-stack/lib/storage-stack.ts +141 -0
- package/examples/multi-stack/package-lock.json +4437 -0
- package/examples/multi-stack/package.json +42 -0
- package/examples/multi-stack/tsconfig.json +34 -0
- package/examples/simple/base.json +8 -0
- package/examples/simple/target.json +14 -0
- package/examples/single-stack/.NVP +0 -0
- package/examples/single-stack/.cdk-cost-analyzer.yml +52 -0
- package/examples/single-stack/.gitlab-ci.yml +126 -0
- package/examples/single-stack/README.md +184 -0
- package/examples/single-stack/UeK +0 -0
- package/examples/single-stack/bin/app.ts +16 -0
- package/examples/single-stack/cdk.json +72 -0
- package/examples/single-stack/lib/infrastructure-stack.ts +119 -0
- package/examples/single-stack/package-lock.json +4443 -0
- package/examples/single-stack/package.json +38 -0
- package/examples/single-stack/tsconfig.json +34 -0
- package/package.json +139 -0
- package/test-cdk-project/README-COMPUTE.md +141 -0
- package/test-cdk-project/README.md +95 -0
- package/test-cdk-project/app-with-compute.js +102 -0
- package/test-cdk-project/app.js +81 -0
- package/test-cdk-project/cdk-compute.json +3 -0
- package/test-cdk-project/cdk.context.json +7 -0
- package/test-cdk-project/cdk.json +3 -0
- package/test-cdk-project/cdk.out/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out/TestStack.template.json +115 -0
- package/test-cdk-project/cdk.out/cdk.out +1 -0
- package/test-cdk-project/cdk.out/manifest.json +503 -0
- package/test-cdk-project/cdk.out/tree.json +1 -0
- package/test-cdk-project/cdk.out.base/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out.base/TestStack.template.json +115 -0
- package/test-cdk-project/cdk.out.base/cdk.out +1 -0
- package/test-cdk-project/cdk.out.base/manifest.json +503 -0
- package/test-cdk-project/cdk.out.base/tree.json +1 -0
- package/test-cdk-project/cdk.out.target/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out.target/TestStack.template.json +183 -0
- package/test-cdk-project/cdk.out.target/cdk.out +1 -0
- package/test-cdk-project/cdk.out.target/manifest.json +521 -0
- package/test-cdk-project/cdk.out.target/tree.json +1 -0
- package/test-cdk-project/package-lock.json +422 -0
- package/test-cdk-project/package.json +17 -0
- package/tools/workflows/README.md +102 -0
- package/tools/workflows/validate-workflows.js +109 -0
- package/tools/workflows/workflow-utils.ts +181 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# Multi-Stack CDK Cost Analyzer Example
|
|
2
|
+
|
|
3
|
+
This example demonstrates how to integrate CDK Cost Analyzer into a multi-stack CDK application with separate networking, compute, and storage layers.
|
|
4
|
+
|
|
5
|
+
## Project Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
multi-stack/
|
|
9
|
+
├── bin/
|
|
10
|
+
│ └── app.ts # CDK application entry point
|
|
11
|
+
├── lib/
|
|
12
|
+
│ ├── networking-stack.ts # VPC and networking resources
|
|
13
|
+
│ ├── compute-stack.ts # ECS and compute resources
|
|
14
|
+
│ └── storage-stack.ts # RDS and storage resources
|
|
15
|
+
├── .cdk-cost-analyzer.yml # Cost analyzer configuration
|
|
16
|
+
├── .gitlab-ci.yml # GitLab CI pipeline
|
|
17
|
+
├── cdk.json # CDK configuration
|
|
18
|
+
├── package.json # Node.js dependencies
|
|
19
|
+
├── tsconfig.json # TypeScript configuration
|
|
20
|
+
└── README.md # This file
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Architecture Overview
|
|
24
|
+
|
|
25
|
+
This example creates a three-tier application infrastructure across multiple stacks:
|
|
26
|
+
|
|
27
|
+
### Networking Stack
|
|
28
|
+
- **Amazon VPC**: Virtual private cloud with public and private subnets
|
|
29
|
+
- **NAT Gateway**: Network address translation for private subnet internet access
|
|
30
|
+
- **VPC Endpoints**: Private connectivity to AWS services
|
|
31
|
+
|
|
32
|
+
### Compute Stack
|
|
33
|
+
- **Amazon ECS Cluster**: Container orchestration
|
|
34
|
+
- **Application Load Balancer**: Traffic distribution
|
|
35
|
+
- **ECS Service**: Containerized application
|
|
36
|
+
|
|
37
|
+
### Storage Stack
|
|
38
|
+
- **Amazon RDS**: PostgreSQL database
|
|
39
|
+
- **Amazon ElastiCache**: Redis cache cluster
|
|
40
|
+
- **Amazon S3**: Object storage for application data
|
|
41
|
+
|
|
42
|
+
## Why Multi-Stack?
|
|
43
|
+
|
|
44
|
+
Multi-stack architectures provide several benefits:
|
|
45
|
+
|
|
46
|
+
- **Separation of Concerns**: Network, compute, and storage managed independently
|
|
47
|
+
- **Deployment Flexibility**: Update individual layers without affecting others
|
|
48
|
+
- **Resource Limits**: Stay within CloudFormation's 500-resource limit per stack
|
|
49
|
+
- **Team Organization**: Different teams can own different stacks
|
|
50
|
+
- **Cost Tracking**: Easier to track costs per infrastructure layer
|
|
51
|
+
|
|
52
|
+
## Prerequisites
|
|
53
|
+
|
|
54
|
+
- Node.js 18 or later
|
|
55
|
+
- AWS CDK CLI: `npm install -g aws-cdk`
|
|
56
|
+
- AWS account with appropriate credentials
|
|
57
|
+
- GitLab repository with CI/CD enabled
|
|
58
|
+
|
|
59
|
+
## Setup Instructions
|
|
60
|
+
|
|
61
|
+
### 1. Install Dependencies
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
cd examples/multi-stack
|
|
65
|
+
npm install
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 2. Configure AWS Credentials
|
|
69
|
+
|
|
70
|
+
For local development:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
export AWS_ACCESS_KEY_ID=your-access-key
|
|
74
|
+
export AWS_SECRET_ACCESS_KEY=your-secret-key
|
|
75
|
+
export AWS_REGION=us-east-1
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
For GitLab CI, configure these as CI/CD variables in your GitLab project settings.
|
|
79
|
+
|
|
80
|
+
### 3. Bootstrap CDK (First Time Only)
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
cdk bootstrap aws://ACCOUNT-ID/REGION
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 4. Review Configuration
|
|
87
|
+
|
|
88
|
+
Edit `.cdk-cost-analyzer.yml` to adjust cost thresholds and usage assumptions for your needs.
|
|
89
|
+
|
|
90
|
+
## Local Development
|
|
91
|
+
|
|
92
|
+
### Synthesize All Stacks
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
cdk synth
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Deploy All Stacks
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
cdk deploy --all
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Deploy Individual Stack
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
cdk deploy NetworkingStack
|
|
108
|
+
cdk deploy ComputeStack
|
|
109
|
+
cdk deploy StorageStack
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Run Cost Analysis Locally
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Install cost analyzer
|
|
116
|
+
npm install -g cdk-cost-analyzer
|
|
117
|
+
|
|
118
|
+
# Analyze cost impact across all stacks
|
|
119
|
+
cdk-cost-analyzer pipeline \
|
|
120
|
+
--base-branch main \
|
|
121
|
+
--target-branch feature/my-changes \
|
|
122
|
+
--region us-east-1
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Understanding Multi-Stack Cost Analysis
|
|
126
|
+
|
|
127
|
+
When analyzing multi-stack applications, CDK Cost Analyzer:
|
|
128
|
+
|
|
129
|
+
1. **Identifies All Stacks**: Automatically detects all CloudFormation templates
|
|
130
|
+
2. **Per-Stack Analysis**: Calculates cost changes for each stack independently
|
|
131
|
+
3. **Aggregated Total**: Sums costs across all stacks for total impact
|
|
132
|
+
4. **Detailed Breakdown**: Shows which stack contributes most to cost changes
|
|
133
|
+
|
|
134
|
+
### Example Cost Report
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Cost Analysis Summary
|
|
138
|
+
=====================
|
|
139
|
+
|
|
140
|
+
Total Cost Delta: +$245.50/month
|
|
141
|
+
|
|
142
|
+
Per-Stack Breakdown:
|
|
143
|
+
- NetworkingStack: +$45.00/month
|
|
144
|
+
- NAT Gateway: +$32.40/month
|
|
145
|
+
- VPC Endpoints: +$12.60/month
|
|
146
|
+
|
|
147
|
+
- ComputeStack: +$150.00/month
|
|
148
|
+
- ECS Tasks: +$120.00/month
|
|
149
|
+
- Application Load Balancer: +$30.00/month
|
|
150
|
+
|
|
151
|
+
- StorageStack: +$50.50/month
|
|
152
|
+
- RDS Instance: +$35.00/month
|
|
153
|
+
- ElastiCache: +$15.50/month
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## GitLab CI/CD Integration
|
|
157
|
+
|
|
158
|
+
The `.gitlab-ci.yml` file configures automatic cost analysis for merge requests with multi-stack support.
|
|
159
|
+
|
|
160
|
+
### Pipeline Stages
|
|
161
|
+
|
|
162
|
+
1. **Build**: Install dependencies
|
|
163
|
+
2. **Test**: Run application tests
|
|
164
|
+
3. **Cost Analysis**: Analyze infrastructure cost changes across all stacks
|
|
165
|
+
4. **Deploy**: Deploy stacks to AWS (manual approval required if cost threshold exceeded)
|
|
166
|
+
|
|
167
|
+
### Cost Thresholds
|
|
168
|
+
|
|
169
|
+
The pipeline enforces cost thresholds defined in `.cdk-cost-analyzer.yml`:
|
|
170
|
+
|
|
171
|
+
- **Warning**: $100/month - Pipeline passes but displays warning
|
|
172
|
+
- **Error**: $500/month - Pipeline fails, requires manual review
|
|
173
|
+
|
|
174
|
+
Note: Thresholds apply to the total cost across all stacks.
|
|
175
|
+
|
|
176
|
+
## Customizing Usage Assumptions
|
|
177
|
+
|
|
178
|
+
Edit `.cdk-cost-analyzer.yml` to reflect your actual usage patterns:
|
|
179
|
+
|
|
180
|
+
```yaml
|
|
181
|
+
usageAssumptions:
|
|
182
|
+
natGateway:
|
|
183
|
+
dataProcessedGB: 500 # Monthly data processed through NAT Gateway
|
|
184
|
+
|
|
185
|
+
alb:
|
|
186
|
+
newConnectionsPerSecond: 50
|
|
187
|
+
activeConnectionsPerMinute: 5000
|
|
188
|
+
processedBytesGB: 1000
|
|
189
|
+
|
|
190
|
+
rds:
|
|
191
|
+
instanceClass: db.t3.medium
|
|
192
|
+
storageGB: 100
|
|
193
|
+
backupRetentionDays: 7
|
|
194
|
+
|
|
195
|
+
elasticache:
|
|
196
|
+
nodeType: cache.t3.micro
|
|
197
|
+
numNodes: 2
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Stack Dependencies
|
|
201
|
+
|
|
202
|
+
The stacks have the following dependencies:
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
NetworkingStack (base)
|
|
206
|
+
↓
|
|
207
|
+
ComputeStack (depends on VPC)
|
|
208
|
+
↓
|
|
209
|
+
StorageStack (depends on VPC and security groups)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
CDK automatically handles deployment order based on these dependencies.
|
|
213
|
+
|
|
214
|
+
## Troubleshooting
|
|
215
|
+
|
|
216
|
+
### Stack Dependency Errors
|
|
217
|
+
|
|
218
|
+
**Issue**: Deployment fails due to missing resources from other stacks
|
|
219
|
+
|
|
220
|
+
**Solution**: Ensure stacks are deployed in the correct order:
|
|
221
|
+
1. NetworkingStack first
|
|
222
|
+
2. ComputeStack second
|
|
223
|
+
3. StorageStack last
|
|
224
|
+
|
|
225
|
+
Or use `cdk deploy --all` to deploy in dependency order automatically.
|
|
226
|
+
|
|
227
|
+
### Cost Analysis Shows Unexpected Changes
|
|
228
|
+
|
|
229
|
+
**Issue**: Cost report shows changes in stacks you didn't modify
|
|
230
|
+
|
|
231
|
+
**Solution**: This is normal when:
|
|
232
|
+
- Stack dependencies cause resource updates
|
|
233
|
+
- CDK updates resource configurations automatically
|
|
234
|
+
- Cross-stack references change
|
|
235
|
+
|
|
236
|
+
Review the detailed per-stack breakdown to understand the changes.
|
|
237
|
+
|
|
238
|
+
### Pipeline Timeout
|
|
239
|
+
|
|
240
|
+
**Issue**: Cost analysis stage times out in GitLab CI
|
|
241
|
+
|
|
242
|
+
**Solution**: Multi-stack analysis takes longer. Increase timeout:
|
|
243
|
+
|
|
244
|
+
```yaml
|
|
245
|
+
cost-analysis:
|
|
246
|
+
timeout: 15m # Increase from default 1h
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Best Practices
|
|
250
|
+
|
|
251
|
+
### Stack Organization
|
|
252
|
+
|
|
253
|
+
- **Keep stacks focused**: Each stack should have a clear purpose
|
|
254
|
+
- **Minimize cross-stack references**: Reduces coupling between stacks
|
|
255
|
+
- **Use consistent naming**: Makes cost tracking easier
|
|
256
|
+
|
|
257
|
+
### Cost Management
|
|
258
|
+
|
|
259
|
+
- **Set per-stack budgets**: Track costs for each infrastructure layer
|
|
260
|
+
- **Review stack-level changes**: Understand which layer drives cost increases
|
|
261
|
+
- **Optimize expensive stacks**: Focus optimization efforts where they matter most
|
|
262
|
+
|
|
263
|
+
### Deployment Strategy
|
|
264
|
+
|
|
265
|
+
- **Deploy networking first**: Establish foundation before other resources
|
|
266
|
+
- **Test incrementally**: Deploy and test each stack before moving to the next
|
|
267
|
+
- **Use stack policies**: Protect critical resources from accidental updates
|
|
268
|
+
|
|
269
|
+
## Next Steps
|
|
270
|
+
|
|
271
|
+
- Review [Configuration Documentation](../../docs/CONFIGURATION.md) for advanced options
|
|
272
|
+
- Explore [Monorepo Example](../monorepo/) for multiple applications
|
|
273
|
+
- Check [Troubleshooting Guide](../../docs/TROUBLESHOOTING.md) for common issues
|
|
274
|
+
|
|
275
|
+
## Additional Resources
|
|
276
|
+
|
|
277
|
+
- [AWS CDK Multi-Stack Documentation](https://docs.aws.amazon.com/cdk/v2/guide/stack_how_to_create_multiple_stacks.html)
|
|
278
|
+
- [CDK Cost Analyzer Documentation](../../README.md)
|
|
279
|
+
- [GitLab CI/CD Documentation](https://docs.gitlab.com/ee/ci/)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import 'source-map-support/register';
|
|
3
|
+
import * as cdk from 'aws-cdk-lib';
|
|
4
|
+
import { NetworkingStack } from '../lib/networking-stack';
|
|
5
|
+
import { ComputeStack } from '../lib/compute-stack';
|
|
6
|
+
import { StorageStack } from '../lib/storage-stack';
|
|
7
|
+
|
|
8
|
+
const app = new cdk.App();
|
|
9
|
+
|
|
10
|
+
const env = {
|
|
11
|
+
account: process.env.CDK_DEFAULT_ACCOUNT,
|
|
12
|
+
region: process.env.CDK_DEFAULT_REGION || 'us-east-1',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Create networking stack (foundation)
|
|
16
|
+
const networkingStack = new NetworkingStack(app, 'NetworkingStack', {
|
|
17
|
+
env,
|
|
18
|
+
description: 'Multi-stack example - Networking layer (VPC, NAT Gateway, VPC Endpoints)',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Create compute stack (depends on networking)
|
|
22
|
+
const computeStack = new ComputeStack(app, 'ComputeStack', {
|
|
23
|
+
env,
|
|
24
|
+
vpc: networkingStack.vpc,
|
|
25
|
+
description: 'Multi-stack example - Compute layer (ECS, ALB)',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Create storage stack (depends on networking and compute)
|
|
29
|
+
const storageStack = new StorageStack(app, 'StorageStack', {
|
|
30
|
+
env,
|
|
31
|
+
vpc: networkingStack.vpc,
|
|
32
|
+
appSecurityGroup: computeStack.appSecurityGroup,
|
|
33
|
+
description: 'Multi-stack example - Storage layer (RDS, ElastiCache, S3)',
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
app.synth();
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app": "npx ts-node --prefer-ts-exts bin/app.ts",
|
|
3
|
+
"watch": {
|
|
4
|
+
"include": [
|
|
5
|
+
"**"
|
|
6
|
+
],
|
|
7
|
+
"exclude": [
|
|
8
|
+
"README.md",
|
|
9
|
+
"cdk*.json",
|
|
10
|
+
"**/*.d.ts",
|
|
11
|
+
"**/*.js",
|
|
12
|
+
"tsconfig.json",
|
|
13
|
+
"package*.json",
|
|
14
|
+
"yarn.lock",
|
|
15
|
+
"node_modules",
|
|
16
|
+
"test"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"context": {
|
|
20
|
+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
|
|
21
|
+
"@aws-cdk/core:checkSecretUsage": true,
|
|
22
|
+
"@aws-cdk/core:target-partitions": [
|
|
23
|
+
"aws",
|
|
24
|
+
"aws-cn"
|
|
25
|
+
],
|
|
26
|
+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
|
|
27
|
+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
|
|
28
|
+
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
|
|
29
|
+
"@aws-cdk/aws-iam:minimizePolicies": true,
|
|
30
|
+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
|
|
31
|
+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
|
|
32
|
+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
|
|
33
|
+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
|
|
34
|
+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
|
|
35
|
+
"@aws-cdk/core:enablePartitionLiterals": true,
|
|
36
|
+
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
|
|
37
|
+
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
|
|
38
|
+
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
|
|
39
|
+
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
|
|
40
|
+
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
|
|
41
|
+
"@aws-cdk/aws-route53-patters:useCertificate": true,
|
|
42
|
+
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
|
|
43
|
+
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
|
|
44
|
+
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
|
|
45
|
+
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
|
|
46
|
+
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
|
|
47
|
+
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
|
|
48
|
+
"@aws-cdk/aws-redshift:columnId": true,
|
|
49
|
+
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
|
|
50
|
+
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
|
|
51
|
+
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
|
|
52
|
+
"@aws-cdk/aws-kms:aliasNameRef": true,
|
|
53
|
+
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
|
|
54
|
+
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
|
|
55
|
+
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
|
|
56
|
+
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
|
|
57
|
+
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
|
|
58
|
+
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
|
|
59
|
+
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
|
|
60
|
+
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
|
|
61
|
+
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
|
|
62
|
+
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
|
|
63
|
+
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
|
|
64
|
+
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
|
|
65
|
+
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
|
|
66
|
+
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
|
|
67
|
+
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
|
|
68
|
+
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
|
|
69
|
+
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
|
|
70
|
+
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import * as cdk from 'aws-cdk-lib';
|
|
2
|
+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
|
|
3
|
+
import * as ecs from 'aws-cdk-lib/aws-ecs';
|
|
4
|
+
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
|
|
5
|
+
import { Construct } from 'constructs';
|
|
6
|
+
|
|
7
|
+
export interface ComputeStackProps extends cdk.StackProps {
|
|
8
|
+
vpc: ec2.IVpc;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Compute stack - Application layer
|
|
13
|
+
*
|
|
14
|
+
* Creates ECS cluster, Application Load Balancer, and containerized application
|
|
15
|
+
*/
|
|
16
|
+
export class ComputeStack extends cdk.Stack {
|
|
17
|
+
public readonly appSecurityGroup: ec2.SecurityGroup;
|
|
18
|
+
|
|
19
|
+
constructor(scope: Construct, id: string, props: ComputeStackProps) {
|
|
20
|
+
super(scope, id, props);
|
|
21
|
+
|
|
22
|
+
const { vpc } = props;
|
|
23
|
+
|
|
24
|
+
// Security group for application
|
|
25
|
+
this.appSecurityGroup = new ec2.SecurityGroup(this, 'AppSecurityGroup', {
|
|
26
|
+
vpc,
|
|
27
|
+
description: 'Security group for application containers',
|
|
28
|
+
allowAllOutbound: true,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// ECS Cluster
|
|
32
|
+
const cluster = new ecs.Cluster(this, 'Cluster', {
|
|
33
|
+
clusterName: 'multi-stack-cluster',
|
|
34
|
+
vpc,
|
|
35
|
+
containerInsights: true,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Application Load Balancer
|
|
39
|
+
const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
|
|
40
|
+
loadBalancerName: 'multi-stack-alb',
|
|
41
|
+
vpc,
|
|
42
|
+
internetFacing: true,
|
|
43
|
+
deletionProtection: false,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// ALB Target Group
|
|
47
|
+
const targetGroup = new elbv2.ApplicationTargetGroup(this, 'TargetGroup', {
|
|
48
|
+
vpc,
|
|
49
|
+
port: 80,
|
|
50
|
+
protocol: elbv2.ApplicationProtocol.HTTP,
|
|
51
|
+
targetType: elbv2.TargetType.IP,
|
|
52
|
+
healthCheck: {
|
|
53
|
+
path: '/health',
|
|
54
|
+
interval: cdk.Duration.seconds(30),
|
|
55
|
+
timeout: cdk.Duration.seconds(5),
|
|
56
|
+
healthyThresholdCount: 2,
|
|
57
|
+
unhealthyThresholdCount: 3,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// ALB Listener
|
|
62
|
+
alb.addListener('HttpListener', {
|
|
63
|
+
port: 80,
|
|
64
|
+
protocol: elbv2.ApplicationProtocol.HTTP,
|
|
65
|
+
defaultTargetGroups: [targetGroup],
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// ECS Task Definition
|
|
69
|
+
const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', {
|
|
70
|
+
memoryLimitMiB: 1024,
|
|
71
|
+
cpu: 512,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Container Definition
|
|
75
|
+
taskDefinition.addContainer('AppContainer', {
|
|
76
|
+
containerName: 'app',
|
|
77
|
+
image: ecs.ContainerImage.fromRegistry('nginx:latest'),
|
|
78
|
+
portMappings: [
|
|
79
|
+
{
|
|
80
|
+
containerPort: 80,
|
|
81
|
+
protocol: ecs.Protocol.TCP,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
logging: ecs.LogDrivers.awsLogs({
|
|
85
|
+
streamPrefix: 'app',
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// ECS Service
|
|
90
|
+
const service = new ecs.FargateService(this, 'Service', {
|
|
91
|
+
cluster,
|
|
92
|
+
taskDefinition,
|
|
93
|
+
desiredCount: 2,
|
|
94
|
+
assignPublicIp: false,
|
|
95
|
+
securityGroups: [this.appSecurityGroup],
|
|
96
|
+
vpcSubnets: {
|
|
97
|
+
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Attach service to target group
|
|
102
|
+
service.attachToApplicationTargetGroup(targetGroup);
|
|
103
|
+
|
|
104
|
+
// Allow ALB to communicate with ECS tasks
|
|
105
|
+
this.appSecurityGroup.addIngressRule(
|
|
106
|
+
ec2.Peer.securityGroupId(alb.connections.securityGroups[0].securityGroupId),
|
|
107
|
+
ec2.Port.tcp(80),
|
|
108
|
+
'Allow traffic from ALB'
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Stack outputs
|
|
112
|
+
new cdk.CfnOutput(this, 'LoadBalancerDNS', {
|
|
113
|
+
value: alb.loadBalancerDnsName,
|
|
114
|
+
description: 'Application Load Balancer DNS name',
|
|
115
|
+
exportName: 'ComputeStack-LoadBalancerDNS',
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
new cdk.CfnOutput(this, 'ClusterName', {
|
|
119
|
+
value: cluster.clusterName,
|
|
120
|
+
description: 'ECS Cluster name',
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
new cdk.CfnOutput(this, 'ServiceName', {
|
|
124
|
+
value: service.serviceName,
|
|
125
|
+
description: 'ECS Service name',
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as cdk from 'aws-cdk-lib';
|
|
2
|
+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
|
|
3
|
+
import { Construct } from 'constructs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Networking stack - Foundation layer
|
|
7
|
+
*
|
|
8
|
+
* Creates VPC with public and private subnets, NAT Gateway, and VPC Endpoints
|
|
9
|
+
*/
|
|
10
|
+
export class NetworkingStack extends cdk.Stack {
|
|
11
|
+
public readonly vpc: ec2.Vpc;
|
|
12
|
+
|
|
13
|
+
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
|
|
14
|
+
super(scope, id, props);
|
|
15
|
+
|
|
16
|
+
// VPC with public and private subnets across 2 AZs
|
|
17
|
+
this.vpc = new ec2.Vpc(this, 'Vpc', {
|
|
18
|
+
vpcName: 'multi-stack-vpc',
|
|
19
|
+
maxAzs: 2,
|
|
20
|
+
natGateways: 1, // Single NAT Gateway for cost optimization
|
|
21
|
+
subnetConfiguration: [
|
|
22
|
+
{
|
|
23
|
+
name: 'Public',
|
|
24
|
+
subnetType: ec2.SubnetType.PUBLIC,
|
|
25
|
+
cidrMask: 24,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'Private',
|
|
29
|
+
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
|
|
30
|
+
cidrMask: 24,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// VPC Endpoint for S3 (Gateway endpoint - no cost)
|
|
36
|
+
this.vpc.addGatewayEndpoint('S3Endpoint', {
|
|
37
|
+
service: ec2.GatewayVpcEndpointAwsService.S3,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// VPC Endpoint for DynamoDB (Gateway endpoint - no cost)
|
|
41
|
+
this.vpc.addGatewayEndpoint('DynamoDbEndpoint', {
|
|
42
|
+
service: ec2.GatewayVpcEndpointAwsService.DYNAMODB,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// VPC Endpoint for ECR API (Interface endpoint - has cost)
|
|
46
|
+
this.vpc.addInterfaceEndpoint('EcrApiEndpoint', {
|
|
47
|
+
service: ec2.InterfaceVpcEndpointAwsService.ECR,
|
|
48
|
+
privateDnsEnabled: true,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// VPC Endpoint for ECR Docker (Interface endpoint - has cost)
|
|
52
|
+
this.vpc.addInterfaceEndpoint('EcrDockerEndpoint', {
|
|
53
|
+
service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER,
|
|
54
|
+
privateDnsEnabled: true,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Stack outputs
|
|
58
|
+
new cdk.CfnOutput(this, 'VpcId', {
|
|
59
|
+
value: this.vpc.vpcId,
|
|
60
|
+
description: 'VPC ID',
|
|
61
|
+
exportName: 'NetworkingStack-VpcId',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
new cdk.CfnOutput(this, 'VpcCidr', {
|
|
65
|
+
value: this.vpc.vpcCidrBlock,
|
|
66
|
+
description: 'VPC CIDR block',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|