【问题标题】:Export with name ExRole is already exported by stack Root-role名称为 ExRole 的导出已由堆栈 Root-role 导出
【发布时间】:2020-08-06 03:38:02
【问题描述】:

我想重用这个模板,但是当我使用嵌套堆栈创建这个模板时,它会给出错误Export with name ExRole is already exported by stack Root-role。如何提高模板的可重用性。这样我就可以在 Prod、dev 和其他环境中部署相同的模板。我尝试在角色名称中使用环境变量,但如何在输出中使用它,如果输出要在下一个模板中使用,语法应该是什么?

角色:

---
AWSTemplateFormatVersion: 2010-09-09 
Parameters:
  Env:
    Type: String
Resources:
  ExRole:
      Type: 'AWS::IAM::Role'
      Properties:
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                Service:
                  - ecs-tasks.amazonaws.com
              Action:
                - 'sts:AssumeRole'
        Path: /
        RoleName: !Sub "excutionrole-${Env}"
        ManagedPolicyArns:
          - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
        Policies: 
          - PolicyName: AccessECR
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: Allow
                  Action: 
                    - ecr:BatchGetImage
                    - ecr:GetAuthorizationToken
                    - ecr:GetDownloadUrlForLayer 
                  Resource: '*'

  ContainerInstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'               
        Statement:
          - Effect: Allow
            Principal: 
                Service: 
                    - ec2.amazonaws.com
            Action: 
                - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
      Path: '/'
      RoleName: !Sub "ContainerInstanceRole-${Env}"
  

  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties: 
      Roles: 
        - !Ref ContainerInstanceRole      

Outputs:
  
  ExRole:
    Description: Task excution role
    Value: !Ref ExRole
    Export:
        Name: "ExRole"
  InstanceProfile:
    Description: profile for container instances
    Value: !Ref InstanceProfile
    Export:
        Name: "InstanceProfile"            

任务:

---
AWSTemplateFormatVersion: 2010-09-09 
Parameters:
    ExRole:
      Type: String
    RDS:
      Type: String
 
    DBUSER:
      Type: String
      Default: mysqldb

    DBPASSWORD:
      Type: String
      Default: 1234123a 
    
    DBNAME:
      Type: String
      Default: mysqldb 
Resources:
    Task:
        Type: AWS::ECS::TaskDefinition
        Properties:
            Family: wordpress 
            Cpu: 1 vCPU
            ExecutionRoleArn: !Ref ExRole
            Memory: 1 GB
            NetworkMode: bridge
            RequiresCompatibilities:
                - EC2
            TaskRoleArn: !Ref ExRole
            ContainerDefinitions: 
              - Essential: true
                Image: wordpress:latest
                Name: wordpress
                PortMappings:  
                  - ContainerPort: 80
                    HostPort: 0
                    Protocol: tcp 
                Environment:
                  - Name: WORDPRESS_DB_HOST
                    Value: !Ref RDS 
                  - Name: WORDPRESS_DB_USER
                    Value: !Ref DBUSER 
                  - Name: WORDPRESS_DB_PASSWORD
                    Value: !Ref DBPASSWORD
                  - Name: WORDPRESS_DB_NAME
                    Value: !Ref DBNAME
    
Outputs:
  Task:
    Description: Contains all the task specifications
    Value: !Ref Task
    Export:
      Name: "Task"

根:

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  

  role:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub "https://${bucketname}.s3.us-east-2.amazonaws.com${bucketpath}/role.yml"
      Parameters:  
        Env: !Ref Env

【问题讨论】:

    标签: amazon-web-services amazon-cloudformation amazon-iam


    【解决方案1】:

    通常当人们使用输出时,如果模板在同一个父堆栈中被多次使用,他们会在导出前加上一个变量(例如堆栈名称)以使其唯一。

    这可以使用sub intrinsic function 来完成,如下例所示

    Outputs:
      ExRole:
        Description: Task excution role
        Value: !Ref ExRole
        Export:
            Name: !Sub "${AWS::StackName}-ExRole"
      InstanceProfile:
        Description: profile for container instances
        Value: !Ref InstanceProfile
        Export:
            Name: !Sub "${AWS::StackName}-InstanceProfile"
    

    然后您需要将此堆栈 ID 值作为参数传递到需要引用此文件的嵌套堆栈中。这将再次使用 sub 内在函数来引用导出名称。

    要在ImportValue 内部函数中获取此值,您可以像下面这样引用它,为此您需要将堆栈名称作为参数传递给堆栈:

    Fn::ImportValue: !Sub "${NestedStack}-ExRole"
    

    如果您从父堆栈调用另一个堆栈,则可以忽略导出,而是使用 GetAtt 内部函数将输出传递到下一个堆栈。

    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  
    
      role:
        Type: AWS::CloudFormation::Stack
        Properties:
          TemplateURL: !Sub "https://${bucketname}.s3.us-east-2.amazonaws.com${bucketpath}/role.yml"
          Parameters:  
            Env: !Ref Env
            
      dbStack:
        Type: AWS::CloudFormation::Stack
        Properties:
          TemplateURL: !Sub "https://${bucketname}.s3.us-east-2.amazonaws.com${bucketpath}/db.yml"
          Parameters:  
            Role: !GetAtt role.Outputs.ExRole
    

    你也可以使用Fn::GetAtt: [role, Outputs.ExRole] also valid syntax的语法。

    【讨论】:

    • 我在使用角色模板输出的问题中添加了另一个模板,将输出提取到另一个模板的语法是什么?
    • 添加了 2 个示例,一个用于独立堆栈,一个用于嵌套堆栈。如果您使用的是嵌套堆栈,您实际上可以忽略导出 :)
    • 我在问题中添加了根模板,我实际上是从根模板传递输出,我不明白的是,如果我想从根传递值我将如何传递它像这样? !GetAtt MyStack.Outputs.${AWS::StackName}-ExRole 语法是什么?
    • 这应该意味着从根堆栈假设具有角色的堆栈是名为role 的堆栈,您将作为参数引用。您将不再需要使用导出。这用于在不属于同一嵌套堆栈的 CloudFormation 堆栈之间提供全局变量 :)
    • 一个CIDR作为参数只能是String。如果当你将它作为字符串时它失败了,它会给出什么错误?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-21
    相关资源
    最近更新 更多