iT邦幫忙

2025 iThome 鐵人賽

DAY 5
1
Build on AWS

30 天將工作室 SaaS 產品部署起來系列 第 5

Day5:AWS 基礎設施規劃與 VPC 網路架構

  • 分享至 

  • xImage
  •  

從容器化到雲端部署的思維轉換

昨天我們完成了基礎的容器化,今天要開始規劃 AWS 基礎設施。從接案經驗來看,很多小團隊會直接使用公有子網和預設 VPC(我基本上都這麼作,但對於 SaaS 產品,我們需要更嚴謹的網路架構設計。

為什麼不能用預設 VPC?

  • 安全考量:預設 VPC 所有子網都是公有的,資料庫直接暴露在網際網路
  • IP 衝突:預設 CIDR 範圍可能與客戶 VPN 衝突
  • 擴展限制:無法彈性調整網路結構
  • 合規要求:某些客戶要求資料庫必須在私有網路

AWS 網路服務解析

VPC (Virtual Private Cloud) 核心概念

什麼是 VPC?
VPC 是你在 AWS 雲端中的虛擬網路,完全隔離且可自訂。它提供:

  • 網路隔離:邏輯上與其他 AWS 帳戶完全分離
  • IP 地址管理:自訂 CIDR 區塊(如 10.0.0.0/16)
  • 子網劃分:可跨多個可用區域建立子網
  • 路由控制:精確控制流量如何在網路中流動

CIDR 區塊選擇策略

常見的私有 IP 範圍:
- 10.0.0.0/8    (10.0.0.0 ~ 10.255.255.255)   - 大型企業
- 172.16.0.0/12 (172.16.0.0 ~ 172.31.255.255) - 中型企業
- 192.168.0.0/16 (192.168.0.0 ~ 192.168.255.255) - 小型網路

Kyo-System 選擇:10.0.0.0/16 (65,536 個 IP)

可用區域 (Availability Zones) 策略

為什麼需要多 AZ 部署?

  • 高可用性:單一 AZ 故障不影響服務
  • 災難恢復:自動故障轉移
  • 效能優化:就近服務降低延遲
  • 合規要求:某些認證要求多 AZ 部署

台灣客戶的 AZ 選擇建議

# ap-northeast-1 (東京) - 主要選擇
ap-northeast-1a  # 主要 AZ
ap-northeast-1c  # 備援 AZ

# 原因:
# 1. 與台灣地理位置最近 (~2000km)
# 2. 延遲通常 30-50ms
# 3. 服務種類最齊全
# 4. 價格相對合理

Kyo-System 網路架構設計

三層網路架構

┌─────────────────────────────────────────────────────────────┐
│                    Internet Gateway                         │
│                    (igw-kyo-main)                          │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────┴───────────────────────────────────────┐
│                  Public Subnets                            │
├─────────────────┬─────────────────┬─────────────────────────┤
│   ALB Subnet    │   NAT Gateway   │      Bastion Host       │
│ 10.0.1.0/24     │ 10.0.2.0/24     │    (管理用途)           │
│ (AZ-1a)         │ (AZ-1a, 1c)     │                         │
└─────────────────┴─────────────────┴─────────────────────────┘
                      │
┌─────────────────────┴───────────────────────────────────────┐
│                 Private Subnets                            │
├─────────────────┬─────────────────┬─────────────────────────┤
│  App Subnet     │  App Subnet     │   Database Subnet       │
│ 10.0.10.0/24    │ 10.0.11.0/24    │   10.0.20.0/24          │
│ (AZ-1a)         │ (AZ-1c)         │   10.0.21.0/24          │
│ ECS Tasks       │ ECS Tasks       │   (AZ-1a, 1c)           │
│ ElastiCache     │ ElastiCache     │   RDS Multi-AZ          │
└─────────────────┴─────────────────┴─────────────────────────┘

網路分層說明

1. Public Subnets (公有子網)

  • 用途:面向網際網路的服務
  • 元件:Application Load Balancer (ALB)、NAT Gateway、Bastion Host
  • 路由:直接通往 Internet Gateway

2. Private Subnets - App Layer (私有子網 - 應用層)

  • 用途:應用服務和快取
  • 元件:ECS Fargate Tasks、ElastiCache
  • 路由:透過 NAT Gateway 存取網際網路

3. Private Subnets - Database Layer (私有子網 - 資料庫層)

  • 用途:資料存儲
  • 元件:RDS PostgreSQL
  • 路由:完全隔離,只能被應用層存取

AWS 基礎設施即程式碼 (IaC) 實作

為什麼選擇 AWS CDK 而非 Terraform?

AWS CDK 優勢

// CDK 的型別安全和 IDE 支援
const vpc = new ec2.Vpc(this, 'KyoVpc', {
  maxAzs: 2,
  cidr: '10.0.0.0/16',
  subnetConfiguration: [
    {
      cidrMask: 24,
      name: 'Public',
      subnetType: ec2.SubnetType.PUBLIC,
    },
    {
      cidrMask: 24,
      name: 'Private',
      subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
    }
  ]
});

與 Terraform 比較

特性 AWS CDK Terraform
學習曲線 中等(需要 TypeScript) 陡峭(HCL 語法)
型別安全 ✅ 完整支援 ❌ 有限支援
AWS 整合 ✅ 官方支援,更新最快 ✅ 社群維護
多雲端支援 ❌ 僅 AWS ✅ 支援多雲端
狀態管理 ✅ CloudFormation 託管 需要自行管理
學習投資 低(使用熟悉語言) 高(新語法)

CDK 專案結構建立

1. 初始化 CDK 專案

# 安裝 AWS CDK
npm install -g aws-cdk

# 建立 CDK 專案
mkdir kyong-saas/infra && cd kyong-saas/infra
npx cdk init app --language typescript

# 安裝必要套件
npm install @aws-cdk/aws-ec2 @aws-cdk/aws-ecs @aws-cdk/aws-rds @aws-cdk/aws-elasticache

2. CDK 專案結構

kyong-saas/infra/
├── bin/
│   └── kyo-infra.ts           # CDK App 入口點
├── lib/
│   ├── network-stack.ts       # VPC 和網路設定
│   ├── database-stack.ts      # RDS 和 ElastiCache
│   ├── compute-stack.ts       # ECS 和 Fargate
│   └── pipeline-stack.ts      # CI/CD Pipeline
├── cdk.json                   # CDK 配置
└── package.json

網路架構實作

3. VPC 和網路設定

// lib/network-stack.ts
import * as cdk from '@aws-cdk/core';
import * as ec2 from '@aws-cdk/aws-ec2';

export class NetworkStack extends cdk.Stack {
  public readonly vpc: ec2.Vpc;
  public readonly albSecurityGroup: ec2.SecurityGroup;
  public readonly ecsSecurityGroup: ec2.SecurityGroup;
  public readonly rdsSecurityGroup: ec2.SecurityGroup;

  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // VPC 建立
    this.vpc = new ec2.Vpc(this, 'KyoVpc', {
      maxAzs: 2,
      cidr: '10.0.0.0/16',
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: 'Public',
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          cidrMask: 24,
          name: 'PrivateApp',
          subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
        },
        {
          cidrMask: 24,
          name: 'PrivateDB',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        }
      ],
      natGateways: 2, // 每個 AZ 一個 NAT Gateway (高可用)
    });

    // ALB Security Group
    this.albSecurityGroup = new ec2.SecurityGroup(this, 'AlbSecurityGroup', {
      vpc: this.vpc,
      description: 'Security group for Application Load Balancer',
      allowAllOutbound: true,
    });

    // 允許來自網際網路的 HTTP/HTTPS 流量
    this.albSecurityGroup.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.tcp(80),
      'Allow HTTP traffic from anywhere'
    );

    this.albSecurityGroup.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.tcp(443),
      'Allow HTTPS traffic from anywhere'
    );

    // ECS Security Group
    this.ecsSecurityGroup = new ec2.SecurityGroup(this, 'EcsSecurityGroup', {
      vpc: this.vpc,
      description: 'Security group for ECS tasks',
      allowAllOutbound: true,
    });

    // 只允許來自 ALB 的流量
    this.ecsSecurityGroup.addIngressRule(
      this.albSecurityGroup,
      ec2.Port.tcp(3000),
      'Allow traffic from ALB'
    );

    // RDS Security Group
    this.rdsSecurityGroup = new ec2.SecurityGroup(this, 'RdsSecurityGroup', {
      vpc: this.vpc,
      description: 'Security group for RDS database',
      allowAllOutbound: false, // 資料庫不需要對外連線
    });

    // 只允許來自 ECS 的資料庫連線
    this.rdsSecurityGroup.addIngressRule(
      this.ecsSecurityGroup,
      ec2.Port.tcp(5432),
      'Allow PostgreSQL access from ECS'
    );

    // ElastiCache Security Group
    const cacheSecurityGroup = new ec2.SecurityGroup(this, 'CacheSecurityGroup', {
      vpc: this.vpc,
      description: 'Security group for ElastiCache',
      allowAllOutbound: false,
    });

    cacheSecurityGroup.addIngressRule(
      this.ecsSecurityGroup,
      ec2.Port.tcp(6379),
      'Allow Redis access from ECS'
    );

    // VPC Endpoints (節省 NAT Gateway 費用)
    this.vpc.addGatewayEndpoint('S3Endpoint', {
      service: ec2.GatewayVpcEndpointAwsService.S3,
      subnets: [{ subnetType: ec2.SubnetType.PRIVATE_WITH_NAT }],
    });

    this.vpc.addInterfaceEndpoint('ECREndpoint', {
      service: ec2.InterfaceVpcEndpointAwsService.ECR,
      subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_NAT },
    });

    // 輸出重要資源 ID 供其他 Stack 使用
    new cdk.CfnOutput(this, 'VpcId', {
      value: this.vpc.vpcId,
      exportName: 'KyoVpcId',
    });

    new cdk.CfnOutput(this, 'PrivateSubnetIds', {
      value: this.vpc.privateSubnets.map(subnet => subnet.subnetId).join(','),
      exportName: 'KyoPrivateSubnetIds',
    });
  }
}

VPC 成本最佳化策略

NAT Gateway 費用分析

NAT Gateway 費用組成

每小時費用:$0.045 USD
資料處理費:$0.045 USD/GB

月度估算 (雙 AZ):
- 固定費用:$0.045 × 24 × 30 × 2 = $64.8 USD
- 資料傳輸:$0.045 × 100GB = $4.5 USD
- 總計:約 $70 USD/月

成本最佳化選項

  1. 單一 NAT Gateway (成本優先)

    • 風險:單點故障
    • 節省:50% NAT 費用
    • 適用:開發/測試環境
  2. VPC Endpoints (推薦)

    • 減少 NAT Gateway 流量
    • AWS 服務直接存取
    • 長期成本更低
  3. NAT Instance (進階)

    • 使用 EC2 替代 NAT Gateway
    • 需要自行管理
    • 適合高流量場景

VPC Endpoints 深度配置

// 加入更多 VPC Endpoints 減少 NAT 費用
const endpoints = [
  { service: ec2.InterfaceVpcEndpointAwsService.ECR },
  { service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER },
  { service: ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS },
  { service: ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER },
  { service: ec2.InterfaceVpcEndpointAwsService.SSM },
];

endpoints.forEach((endpoint, index) => {
  this.vpc.addInterfaceEndpoint(`VpcEndpoint${index}`, {
    service: endpoint.service,
    subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_NAT },
    securityGroups: [vpcEndpointSecurityGroup],
  });
});

AWS 區域選擇與延遲最佳化

台灣服務區域選擇指南

1. ap-northeast-1 (東京) - 首選

優點:
✅ 延遲最低 (30-50ms)
✅ 服務最齊全
✅ 價格合理
✅ 合規支援佳

缺點:
❌ 天災風險 (地震)
❌ 日圓匯率波動

2. ap-southeast-1 (新加坡) - 備選

優點:
✅ 政治穩定
✅ 東南亞樞紐
✅ 延遲可接受 (60-80ms)

缺點:
❌ 某些服務較晚推出
❌ 價格稍高

3. 多區域部署考量

// 未來可考慮的多區域架構
const regions = {
  primary: 'ap-northeast-1',   // 主要服務
  secondary: 'ap-southeast-1', // 災難備援
  edge: 'ap-northeast-2',      // 韓國客戶
};

網路效能監控策略

CloudWatch 網路指標

// 重要的網路監控指標
const networkMetrics = [
  'NetworkIn',          // 網路輸入
  'NetworkOut',         // 網路輸出
  'NetworkLatency',     // 網路延遲
  'ConnectionCount',    // 連線數量
  'PacketDropCount',    // 封包遺失
];

// 建立 CloudWatch Dashboard
const dashboard = new cloudwatch.Dashboard(this, 'NetworkDashboard', {
  dashboardName: 'Kyo-Network-Monitoring',
  widgets: [
    new cloudwatch.GraphWidget({
      title: 'VPC Network Performance',
      left: [
        new cloudwatch.Metric({
          namespace: 'AWS/EC2',
          metricName: 'NetworkIn',
          statistic: 'Average',
        }),
      ],
    }),
  ],
});

今日成果

VPC 架構設計:三層網路分離,安全性最佳化
多 AZ 部署:高可用性架構規劃
Security Groups:最小權限原則實作
成本最佳化:VPC Endpoints 減少 NAT 費用
CDK 基礎設施:型別安全的 IaC 實作
監控準備:網路效能指標規劃

AWS 網路架構最佳實踐總結

  1. 安全分層:公有、私有、資料庫層嚴格分離
  2. 最小權限:Security Groups 精確控制流量
  3. 高可用性:多 AZ 部署避免單點故障
  4. 成本控制:VPC Endpoints 減少資料傳輸費用
  5. 監控完整:網路效能與安全事件監控

下一步規劃

明天(Day6)我們將建立 RDS PostgreSQL 和 ElastiCache Redis,包含:

  1. Multi-AZ RDS 部署與自動備份策略
  2. ElastiCache 叢集模式與故障轉移
  3. 資料庫安全性最佳化
  4. 效能監控與告警設定

上一篇
Day4:容器化與本地測試環境
下一篇
Day 6: 從零開始建立 AWS 環境 - 帳號申請到 CDK 部署實戰
系列文
30 天將工作室 SaaS 產品部署起來7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
滷荃
iT邦新手 5 級 ‧ 2025-09-20 06:34:24

對新手來說,region 直觀會選 ap-east-2 台北。
請教一下,為甚麼 region 不選 ap-east-2 台北呢?

之前的習慣,以前在公司使用aws時還沒有ap-east-2 台北,都是選擇東京,剛有看台北定價,確實都比東京還要低一些,感謝提醒~

滷荃 iT邦新手 5 級 ‧ 2025-09-20 20:17:54 檢舉

不過台北是不是有些服務沒有提供呢,像cognito, 不知道有沒有region支援服務的列表呢?

https://aws.amazon.com/tw/about-aws/global-infrastructure/regional-product-services/

可以從這邊來查看每個地區所支援的產品服務

我要留言

立即登入留言