用Ansible创建和删除CloudFormation的堆栈

这是关于如何使用Ansible来创建和删除AWS CloudFormation堆栈的备忘录。简单的堆栈管理可以通过使用aws命令在shell脚本中封装来实现,但为了增强对模板输入参数和输出内容的重用性,我们使用Ansible来实现。

这里是 Ansible 的 cloudformation 模块的文档。

    cloudformation – Create or delete an AWS CloudFormation stack — Ansible Documentation

此处使用 AWS 的 Quick Start 中提供的 VPC 和 Bastion 生成堆栈。

    • VPC Architecture – AWS Quick Start

 

    Linux bastion hosts on AWS – Quick Start

除了使用DependsOn来构建新的VPC堆栈的主模板之外,Bastion Stack还有一个选项是通过调用单独的模板来传递堆栈输出作为Ansible变量。

准备

首先安装Ansible,并添加Boto以便调用AWS的API。

安装 Ansible 在 Ubuntu 上需要进行以下步骤,但在其他发行版和 macOS 上大致相同。请根据使用环境进行调整。

$ sudo apt-get install -y python-pip
$ sudo pip install -U pip
$ sudo pip install ansible==2.4.0

接下来,安装Boto并将访问密钥的信息写入配置文件(〜/.boto)。

$ sudo pip install boto3

请根据使用的帐户来配置访问密钥的信息。除了具备创建和删除 CloudFormation 的权限之外,还需要具备管理堆栈中资源的权限。在堡垒机堆栈中,需要有 IAM 角色相关的权限。

[Credentials]
aws_access_key_id = xxxxxxxxxxxxxxx
aws_secret_access_key = xxxxxxxxxxxxxxx

将Ansible的变量文件准备为group_vars/all.yml。在其中定义了允许访问跳板主机(bastion)的IP地址为remote_global_ip_addr,但请根据执行环境的网络进行必要的更改。此外,请根据需要调整区域、可用区、密钥对和堆栈名称等相关参数。

---

remote_global_ip_addr: "aaa.bbb.ccc.ddd/32"

aws_region: ap-northeast-1
aws_ec2_keypair_bastion:
  name: bastion
  private_key_file: ~/.ssh/keys/aws_bastion.pem

aws_cfn_stack_name: "Example"
aws_cfn_vpc_stack_name: "{{ aws_cfn_stack_name }}VPC"
aws_cfn_vpc_availability_zones: "ap-northeast-1b,ap-northeast-1c"
aws_cfn_vpc_qs_template_url: "https://s3.amazonaws.com/quickstart-reference/aws/vpc/latest/templates/aws-vpc.template"
aws_cfn_vpc_qs_keypair: "{{ aws_ec2_keypair_bastion.name }}"
aws_cfn_bastion_stack_name: "{{ aws_cfn_stack_name }}Bastion"
aws_cfn_bastion_qs_template_url: "https://s3.amazonaws.com/quickstart-reference/linux/bastion/latest/templates/linux-bastion.template"

为了举例,这里将其命名为 all.yml,但如果想要根据不同的清单文件进行加载,您需要适当调整文件配置和Playbook。有关清单文件配置的详细信息,请参阅 Ansible 的文档。

    Best Practices — Ansible Documentation

创建堆栈

准备一个名为 site.yml 的 Playbook。

---

- name: Create VPC and Bastion stack
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
    - name: Launch VPC network with NAT gateway
      cloudformation:
        region: "{{ aws_region }}"
        stack_name: "{{ aws_cfn_vpc_stack_name }}"
        state: "present"
        template_url: "{{ aws_cfn_vpc_qs_template_url }}"
        template_parameters:
          AvailabilityZones: "{{ aws_cfn_vpc_availability_zones }}"
          KeyPairName: "{{ aws_cfn_vpc_qs_keypair }}"
      register: _vpc
    - name: Launch bastion stack
      cloudformation:
        region: "{{ aws_region }}"
        stack_name: "{{ aws_cfn_bastion_stack_name }}"
        state: "present"
        template_url: "{{ aws_cfn_bastion_qs_template_url }}"
        template_parameters:
          VPCID: "{{ _vpc.stack_outputs.VPCID }}"
          PublicSubnet1ID: "{{ _vpc.stack_outputs.PublicSubnet1ID }}"
          PublicSubnet2ID: "{{ _vpc.stack_outputs.PublicSubnet2ID }}"
          RemoteAccessCIDR: "{{ remote_global_ip_addr }}"
          EnableTCPForwarding: "true"
          KeyPairName: "{{ aws_ec2_keypair_bastion.name }}"
      register: _bastion
    - name: Show bastion EIP
      local_action: shell echo {{ _bastion.stack_outputs.EIP1 }} > bastion

执行Playbook。如果处理成功完成,将在bastion文件中输出跳板主机的IP地址。

$ ansible-playbook site.yml

删除堆栈

准备一个名为 halt.yml 的剧本。

---

- name: Delete all stacks
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
    - name: Delete bastion stack
      cloudformation:
        region: "{{ aws_region }}"
        stack_name: "{{ aws_cfn_bastion_stack_name }}"
        state: "absent"
    - name: Delete VPC stack
      cloudformation:
        region: "{{ aws_region }}"
        stack_name: "{{ aws_cfn_vpc_stack_name }}"
        state: "absent"

执行Playbook。

$ ansible-playbook halt.yml

总结

使用Ansible创建和删除了AWS的CloudFormation堆栈。可以根据Ansible清单管理输入参数,并将堆栈的输出结果作为变量在playbook中使用,因此在需要进行其他处理时非常方便。例如,可以考虑将跳板主机的EIP追加到~/.ssh/config中。

因为Shell脚本的写法因人而异,条件下对变量的使用也比较困难,所以将其整合到诸如Ansible等配置管理工具中会很方便。

提供环境支持

如果您要使用Vagrant来安装Ansible和Boto,请按照以下步骤进行。

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-16.04"

  config.vm.provision "shell", inline: <<-SHELL
    apt-get update
    apt-get install -y python-pip
    pip install -U pip
    pip install ansible==2.4.0
    pip install boto3
  SHELL
end

可以使用 Ansible Local 来执行 Playbook。

    Ansible Local – Provisioning – Vagrant by HashiCorp
bannerAds