在 Cloudformation 中使用 Qa、Dev 和 Prod 作为环境

Use Qa, Dev and Prod as an environement in Cloudformation

我已经创建了这个嵌套堆栈。我想用 {prod, dev, qa} 环境实现相同的堆栈。就像我想建立同一个堆栈,但它们之间没有任何名称冲突。我想在三个不同的环境中部署相同的堆栈,我需要做哪些更改才能实现它

根目录:

---
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  bucketname:
    Type: String
    Description: Path to the bucket
    Default: webserver
  bucketpath:
    Type: String
    Description: Path to the bucket
    Default: /env #/mysql
  Env:
    Type: String
    Description: Select the appropriate environment
    AllowedValues:
      - dev
      - test
      - uat
      - prod
  Cidr:
    Type: String
    Description: Cidr for vpc
  
  Publicsubnet1:
    Type: String
    Description: public subnet 1

  Publicsubnet2:
    Type: String
    Description: public subnet 2
  
  Privatesubnet1:
    Type: String
    Description: Private subnet 1

  Privatesubnet2:
    Type: String
    Description: Private subnet 2


Resources:
      Vpcstack:
        Type: AWS::CloudFormation::Stack
        Properties:
          TemplateURL: !Sub "https://${bucketname}.s3.us-east-2.amazonaws.com${bucketpath}/vpc.yml"
          Parameters:  
            Env: Ref: Env
            Cidr: !Ref Cidr
            Publicsubnet1: !Ref Publicsubnet1
            Publicsubnet2: !Ref Publicsubnet2
            Privatesubnet1: !Ref Privatesubnet1
            Privatesubnet2: !Ref Privatesubnet2  

Vpc:

---
    AWSTemplateFormatVersion: 2010-09-09
    Parameters:
      Cidr:
        Type: String
        Description: Cidr for vpc
      
      Publicsubnet1:
        Type: String
        Description: public subnet 1
    
      Publicsubnet2:
        Type: String
        Description: public subnet 2
      
      Privatesubnet1:
        Type: String
        Description: Private subnet 1
    
      Privatesubnet2:
        Type: String
        Description: Private subnet 2
      
      Env:
        Type: String
        Description: Select the appropriate environment
    
    Resources:
    
      VPC:
        Type: AWS::EC2::VPC
        Properties:
          CidrBlock: !Ref Cidr
          EnableDnsSupport: true
          EnableDnsHostnames: true
          InstanceTenancy: default
      InternetGateway:
        Type: AWS::EC2::InternetGateway
      VPCGatewayAttachment:
        Type: AWS::EC2::VPCGatewayAttachment
        Properties:
          VpcId: !Ref VPC
          InternetGatewayId: !Ref InternetGateway
      SubnetA:
        Type: AWS::EC2::Subnet
        Properties:
          AvailabilityZone: us-east-2a
          VpcId: !Ref VPC
          CidrBlock: !Ref Publicsubnet1
          MapPublicIpOnLaunch: true
      SubnetB:
        Type: AWS::EC2::Subnet
        Properties:
          AvailabilityZone: us-east-2b
          VpcId: !Ref VPC
          CidrBlock: !Ref Publicsubnet2
          MapPublicIpOnLaunch: true
      SubnetC:
        Type: AWS::EC2::Subnet
        Properties:
          AvailabilityZone: us-east-2a
          VpcId: !Ref VPC
          CidrBlock: !Ref Privatesubnet1
          MapPublicIpOnLaunch: false
      SubnetD:
        Type: AWS::EC2::Subnet
        Properties:
          AvailabilityZone: us-east-2b
          VpcId: !Ref VPC
          CidrBlock: !Ref Privatesubnet2
          MapPublicIpOnLaunch: false
      RouteTable:
        Type: AWS::EC2::RouteTable
        Properties:
          VpcId: !Ref VPC
      RouteTable2:
        Type: AWS::EC2::RouteTable
        Properties:
          VpcId: !Ref VPC
      InternetRoute:
        Type: AWS::EC2::Route
        DependsOn: VPCGatewayAttachment
        Properties:
          DestinationCidrBlock: 0.0.0.0/0
          GatewayId: !Ref InternetGateway
          RouteTableId: !Ref RouteTable
      SubnetARouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
          RouteTableId: !Ref RouteTable
          SubnetId: !Ref SubnetA
      SubnetBRouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
          RouteTableId: !Ref RouteTable
          SubnetId: !Ref SubnetB
      SubnetCRouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
          RouteTableId: !Ref RouteTable2
          SubnetId: !Ref SubnetC
    
      SubnetDRouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
          RouteTableId: !Ref RouteTable2
          SubnetId: !Ref SubnetD
      SecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
          GroupName: "Internet Group"
          GroupDescription: "SSH traffic in, all traffic out."
          VpcId: !Ref VPC
          SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: "22"
              ToPort: "22"
              CidrIp: 0.0.0.0/0
          SecurityGroupEgress:
            - IpProtocol: -1
              CidrIp: 0.0.0.0/0
      NAT:
        Type: AWS::EC2::NatGateway
        Properties:
          AllocationId:
            Fn::GetAtt:
              - EIP
              - AllocationId
          SubnetId:
            Ref: SubnetA
          Tags:
            - Key: Name
              Value: !Sub "nat-${Env}"
      EIP:
        DependsOn: VPCGatewayAttachment
        Type: AWS::EC2::EIP
        Properties:
          Domain: VPC
      Route:
        Type: AWS::EC2::Route
        Properties:
          RouteTableId:
            Ref: RouteTable2
          DestinationCidrBlock: 0.0.0.0/0
          NatGatewayId:
            Ref: NAT
    Outputs:
      VpcID:
        Description: VPC id
        Value: !Ref VPC
        Export:
          Name: "VpcID"
      SubnetA:
        Description: public subnet
        Value: !Ref SubnetA
        Export:
          Name: "SubnetA"
      SubnetB:
        Description: public subnet 2
        Value: !Ref SubnetB
        Export:
          Name: "SubnetB"
      SubnetC:
        Description: priavte subnet
        Value: !Ref SubnetC
        Export:
          Name: "SubnetC"
      SubnetD:
        Description: private subnet 2
        Value: !Ref SubnetD
        Export:
          Name: "SubnetD"
    

CF 堆栈由 stack-name 标识。您所要做的就是在部署 CF 模板时指定此 stack-name。

aws cloudformation deploy --stack-name <value> --template-file <value> ...

如果您指定现有堆栈的名称,该堆栈将被更新。如果您指定一个新名称,您将从给定模板创建一个新堆栈。

您可以通过每次选择新的堆栈名称从单个模板创建任意数量的堆栈。您无需担心命名冲突,因为给定堆栈中的每个资源名称都是根据不同的堆栈名称唯一标识的。

aws cloudformation deploy --stack-name dev --template-file the-same-template.yaml ...
aws cloudformation deploy --stack-name test --template-file the-same-template.yaml ...
aws cloudformation deploy --stack-name uat --template-file the-same-template.yaml ...
aws cloudformation deploy --stack-name prod --template-file the-same-template.yaml ...

这将创建 4 个独立的堆栈(开发、测试、uat、生产)。

请注意,由于您正在对 IP 地址范围进行硬编码,因此这些堆栈中的资源将无法相互通信,因为网络重叠(这可能正是您想要的),但如果出于某种原因您需要这些资源通信,您还需要为 CIDR 块(VPC、子网)创建 Parameters

您可以通过将环境添加到 top-level 堆栈名称来为 top-level 堆栈指定不同的名称。您可以在创建堆栈时通过控制台或以编程方式执行此操作。

然后,当每个 top-level environment-specific 堆栈运行时,它将创建必要的嵌套堆栈,而不会出现名称冲突。您将无法控制 nested 堆栈的堆栈名称,但您可以使用输出获取名称。

查看以下内容:

You can add output values from a nested stack within the containing template. You use the GetAtt function with the nested stack's logical name and the name of the output value in the nested stack in the format Outputs.NestedStackOutputName.

  • CloudFormation nested stack name

如果您需要为不同的环境使用不同的资源值,那么您可以使用mappings 来指定与所选环境相对应的设置。这是一个映射示例:

Mappings:
  EnvTypeMap:
    prod:
      vpc: vpc-a6842gb0
      subnet: subnet-hjk23553
    dev:
      vpc: vpc-b7742gb0
      subnet: subnet-abc23553
    qa:
      vpc: vpc-c2542gb0
      subnet: subnet-uio23553

然后要引用这些映射值之一,您可以这样做:

VpcId: 
  Fn::FindInMap:
    - EnvTypeMap
    - Ref: Env
    - vpc