服务
关于
CloudProse博客
开发人员经验

Ansible&复杂工作流的CloudFormation

您的YML中包含YAML。您的YAML中包含YML。 Ansible和CloudFormation为AWS自动化提供了不同的方法
迈克尔·巴尼(Michael Barney)Trek10
迈克尔·巴尼 | 2019年8月7日

CloudFormation StackSets入门

​ 如果您不熟悉CloudFormation StackSet,我强烈建议您查看 文档中的高级概念。 CloudFormation堆栈集提供了将CloudFormation堆栈部署到多个区域或多个帐户的功能。当您要以标准化方式跨帐户或区域启动模板,或者出于高可用性或灾难恢复的原因要将应用程序部署到多个区域时,这将非常有用。 ​ There are many more reasons to use stacksets, but unfortunately, the only way to use them with Cloudformation is through the console or the API. There's no AWS::CloudFormation::StackSet CloudFormation resource or any native code-defined way to declare stacksets, like other AWS resources. You certainly don't want to have to write custom stackset orchestration scripts to manage stacksets, and you don't want to do it manually (because you follow best practices, and 所有). So this is where Ansiblecomes in to save the day! ​

AnsiblePrimer

​ 也许您从未使用过Ansible。您为什么要通过Terraform或其他替代方法学习Ansible?好吧,在不将此博客文章介绍到各种部署机制的优缺点的情况下,Ansible是简单,可扩展的,并且非常容易上手。 ​ 最终,Ansible是一个工具,可以帮助您自动化任务并管理基础架构的配置。它不存储两次执行之间的状态,您只需要准确描述您想要的内容,其余的由Ansible处理。 ​ 如何安装Ansible? ​

pipx install ansible

请注意,我们建议使用 pipx 减少将软件包安装到全局/系统python环境中。 ​ 现在您已经安装了它,如何使用Ansible? ​ 您可以在YAML文件中定义Ansible“剧本”,该文件由一对多的“剧本”组成。每个播放包含一个任务列表,这些任务是您要做的事情(执行命令,安装软件包,部署AWS基础设施等)。要在Ansible中执行任何操作,您需要使用Ansible模块。您可以获得模块列表 这里。您甚至可以编写自己的。 ​ 这是获取AWS Canonical ID的示例剧本: ​

---
- hosts: localhost # Use 'localhost' since we're not executing this configuration against a remote server, instead we're just executing the playbook
  tasks: # A list of Ansibletasks
    - name: My Debug Task # Each task has a `name`
      debug: # Each task has a module, like `debug` or `command`
        msg: AnsibleFTW
    - name: Get canonical user ID
      command: aws s3api list-buckets --query Owner.ID --output text
      register: s3_list_buckets_command # Register the output of the `command` module to this variable name
    - name: Log Canonical ID
      debug:
        msg: '{{ s3_list_buckets_command.stdout }}' # This is how you can reference those variables later on in your playbooks

​ 定义的YAML是一个数组,其中数组的每个元素都是一个“播放”,从而使整个YAML文件成为一个“播放簿”。要执行该剧本,您只需要运行: ​

$ ansible-playbook my-playbook.yml
PLAY [localhost] ****************************************************************************************************************
​
TASK [My Debug Task] ************************************************************************************************************
ok: [localhost] => {
    "msg": "AnsibleFTW"
}
​
TASK [Get canonical user ID] ****************************************************************************************************
changed: [localhost]
​
TASK [Log Canonical ID] *********************************************************************************************************
ok: [localhost] => {
    "msg": "1234567812345678123456781234567812345678123456781234567812345678"
}
​
PLAY RECAP **********************************************************************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

​ 如您所见,我们获得了两个调试日志,一个包含我们的静态消息,另一个具有我们的AWS Canonical ID。我们还将获得有关剧本执行的更多详细信息。 ​

在代码中定义StackSet

​ 到目前为止,我们所做的一切都适用于每本剧本,但现在让我们讨论将其应用于CloudFormation StackSets。我们将需要使用 cloudformation_stack_set 模块。通过该模块,您可以定义要部署到的帐户和区域的列表,CloudFormation的ARN角色(在执行更改集,堆栈集容错能力和其他堆栈集配置属性时要承担的角色)。 ​ This Ansibleplaybook defines a CloudFormation StackSet to be deployed to 3 accounts, each in one region. When executed, it'll pull in the ./template.yaml file and deploy it across 所有 three accounts and in the single region configured. ​

---
- hosts: localhost
  connection: local
  gather_facts: false
  tasks:
    - name: Deploy CloudTrail To All Accounts
      cloudformation_stack_set:
        name: cloudtrail
        description: CloudTrail Setup
        state: present
        template_body: '{{ lookup("file", "./template.yaml") }}'
        accounts:
          - '123123123123'
          - '231231231231'
          - '312312312312'
        regions:
          - us-east-1

笔记: 我们使用`lookup()`函数在运行时提取模板,并调用`file`插件。您可以获取插件列表 这里。一些值得注意的是分别通过env用于查找环境变量,aws_ssm和aws_secret分别从AWS SSM和Secrets Manager中提取值。


跨区域堆栈

​ 现在想象您要在代码中设置跨区域复制。您需要在一个区域中创建一个cloudformation堆栈,在另一个区域中创建另一个堆栈,并且需要将一个堆栈的输出连接到另一个堆栈的参数(即复制存储桶名称)。嵌套堆栈,CloudFormation导入和导出以及SSM参数都是区域性的。要处理引用跨区域值,您将必须编写脚本以在区域A中部署一个堆栈,查询输出,并将其作为在区域B中部署的堆栈的参数提供。但是,借助ansible,我们可以在几行yaml中将其定义为配置,并节省了很多时间来解决跨区域云形成堆栈的问题。 ​ 我们有用于复制存储桶的模板: ​

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  ReplicationBucket:
    Type: AWS::S3::Bucket
    Properties:
      VersioningConfiguration:
        Status: Enabled
Outputs:
  ReplicationBucketName:
    Description: The name of the replication bucket
    Value: !Ref ReplicationBucket

​ 另一个用于实际存储桶的模板: ​

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  ReplicationBucket:
    Type: String
    Description: The name of the replication bucket
Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      VersioningConfiguration:
        Status: Enabled
      ReplicationConfiguration:
        Role: !GetAtt BucketReplicationRole.Arn
        Rules:
          - Status: Enabled
            Prefix: ''
            Destination:
              Account: !Ref AWS::AccountId
              Bucket: !Sub arn:aws:s3:::${ReplicationBucket}
  BucketReplicationRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: s3.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: BucketReplication
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: s3:*
                Resource: '*'

​ 因此,我们的ansible将如下所示: ​

- hosts: localhost
  gather_facts: false
  tasks:
    - name: Bucket replication stack
      cloudformation:
        region: us-east-2 # us-east-2 is where the main bucket will be replicated
        stack_name: bucket-replication
        state: present
        template_body: '{{ lookup("file", "./replication.yaml") }}'
      register: replication_stack
    - name: Bucket stack
      cloudformation:
        region: us-east-1 # us-east-1 is where our main bucket will be located
        stack_name: bucket
        state: present
        template_body: '{{ lookup("file", "./template.yaml") }}'
        template_parameters:
          ReplicationBucket: "{{ replication_stack.stack_outputs.ReplicationBucketName }}"

​ 由于Ansible不与特定的AWS区域绑定,因此它可以处理区域资源之间的跨区域关系。 ​ 这就是使Ansible在AWS CloudFormation和基础架构流程世界中如此强大的原因。您可以根据需要建立资源关系:跨区域,跨帐户甚至是CloudFormation实例。 Ansible为您提供了使CloudBaseation自动化的基础设施自动化工具。如果您想了解更多有关将基础架构作为代码的信息,请在CloudProse博客上查看我们在CloudFormation上的其他一些帖子。跟着我们 @ Trek10Inc 了解有关作为代码,无服务器和AWS的基础架构的更多技巧。 Collapse

作者
迈克尔·巴尼(Michael Barney)Trek10
迈克尔·巴尼

DevOps工程师

Michael的职业生涯始于无服务器世界,他刚从大学毕业就加入了Trek10团队-真正的无服务器本地人。