Amazon ec2 Ansible:尝试一次在多个区域中创建多个EC2实例

Amazon ec2 Ansible:尝试一次在多个区域中创建多个EC2实例,amazon-ec2,ansible,ansible-playbook,Amazon Ec2,Ansible,Ansible Playbook,我正在尝试创建一个AWS EC2 ansible剧本: 1) 首先在以下三个区域分别分配一个VPC: 美国西部1号、亚太东北1号和欧盟西部1号 2) 查找每个区域的最新ubuntu AMI(ec2_AMI_搜索) 3) 然后使用1)和2)中发现的结果, 使用最新的ubuntu AMI为每个区域创建一个EC2实例(针对该区域) 可用区为us-west-1a、ap-northeast-1a 和eu-west-1a 对于Ansible,我对第1)步和第2)步没有问题,这两步很简单: >

我正在尝试创建一个AWS EC2 ansible剧本:

1) 首先在以下三个区域分别分配一个VPC: 美国西部1号、亚太东北1号和欧盟西部1号

2) 查找每个区域的最新ubuntu AMI(ec2_AMI_搜索)

3) 然后使用1)和2)中发现的结果, 使用最新的ubuntu AMI为每个区域创建一个EC2实例(针对该区域) 可用区为us-west-1a、ap-northeast-1a 和eu-west-1a

对于Ansible,我对第1)步和第2)步没有问题,这两步很简单:

> 

  tasks:
  - name: create a vpc
    ec2_vpc:
      state: present
      region: "{{ item.region }}"
      internet_gateway: True
      resource_tags: { env: production}
      cidr_block: 10.0.0.0/16
      subnets:
        - cidr: 10.0.0.0/24
          az: "{{ item.az }}"
          resource_tags:
            env: production
            tier: public
      route_tables:
        - subnets:
          - 10.0.0.0/24
          routes:
          - dest: 0.0.0.0/0
            gw: igw
    with_items:
      - region: us-west-1
        az: us-west-1a
      - region: ap-northeast-1
        az: ap-northeast-1a
      - region: eu-west-1
        az: eu-west-1a
...
  - name: Get the ubuntu trusty AMI
    ec2_ami_search: distro=ubuntu release=trusty virt=hvm region={{ item }}
    with_items:
      - us-west-1
      - ap-northeast-1
      - eu-west-1
    register: ubuntu_image
...
>
以及使用调试模块输出的ubuntu_image变量:

TASK: [print out ubuntu images] *********************************************** 
ok: [localhost] => {
    "ubuntu_image": {
        "changed": false, 
        "msg": "All items completed", 
        "results": [
            {
                "aki": null, 
                "ami": "ami-b33dccf7", 
                "ari": null, 
                "changed": false, 
                "invocation": {
                    "module_args": "distro=ubuntu release=trusty virt=hvm region=us-west-1", 
                    "module_name": "ec2_ami_search"
                }, 
                "item": "us-west-1", 
                "serial": "20150629", 
                "tag": "release"
            }, 
            {
                "aki": null, 
                "ami": "ami-9e5cff9e", 
                "ari": null, 
                "changed": false, 
                "invocation": {
                    "module_args": "distro=ubuntu release=trusty virt=hvm region=ap-northeast-1", 
                    "module_name": "ec2_ami_search"
                }, 
                "item": "ap-northeast-1", 
                "serial": "20150629", 
                "tag": "release"
            }, 
            {
                "aki": null, 
                "ami": "ami-7c4b0a0b", 
                "ari": null, 
                "changed": false, 
                "invocation": {
                    "module_args": "distro=ubuntu release=trusty virt=hvm region=eu-west-1", 
                    "module_name": "ec2_ami_search"
                }, 
                "item": "eu-west-1", 
                "serial": "20150629", 
                "tag": "release"
            }
        ]
    }
}
但是,我不知道如何执行步骤3) 从ubuntu_图像寄存器变量获取结果 然后确定给定EC2实例所属的3个AMI和子网中的哪一个。 请参见下文,作为解决方法,我手动硬编码了ami和子网值 我只是从上面的ubuntu_图像打印输出中得到:

  - name: start the instances
    ec2:
      image: "{{ item.ami }}"  # MANUALLY HARDCODED
      region: "{{ item.region }}"
      instance_type: "{{ instance_type }}"
      assign_public_ip: True
      key_name: "{{ item.name }}"
      group: ["http deployment", "ssh deployment", "outbound deployment"]
      instance_tags: { Name: "{{ item.name }}", type: ss, env: production}
      exact_count: "{{ count }}"
      count_tag: {  Name: "{{ item.name }}" }
      vpc_subnet_id: "{{ item.subnet }}" #MANUALLY HARDCODED
      wait: yes
    register: ec2
    with_items:
      - region: us-west-1
        name: ss12
        ami: ami-b33dccf7  # MANUALLY HARDCODED
        subnet: subnet-35a22550  # MANUALLY HARDCODED
      - region: ap-northeast-1
        name: ss21
        ami: ami-9e5cff9e  # MANUALLY HARDCODED
        subnet: subnet-88c47dff  # MANUALLY HARDCODED
      - region: eu-west-1
        name: ss32
        ami: ami-7c4b0a0b  # MANUALLY HARDCODED
        subnet: subnet-23f59554  # MANUALLY HARDCODED
当ami/子网硬编码工作时,您能为我想出一个解决方案来避免这种ami/子网硬编码吗?
我试图将set_fact弄乱,但没有用,因为我无法使它成为“region-to-ami”值映射的字典

请记住,
Ansible
是一个“可插入”系统,因此很容易为自己定制它。有时,它甚至比使用“本机”模块寻找解决方案更容易、更快

在您的情况下,您可以轻松编写自己的自定义
查找\u插件
,用于搜索正确的
子网

例如:

  • 在主文件夹中创建一个名为
    lookup\u plugins
    的文件夹
  • 创建一个名为
    ansible.cfg
  • lookup\u plugins
    中创建名为
    subnets.py的文件

    import boto.vpc
    class LookupModule(object):
        def __init__(self, basedir=None, **kwargs):
            self.basedir = basedir
            self.plugin_name = 'subnets'
        def run(self, regions, variable=None, **kwargs):
            if not isinstance(regions, list):
                regions = [regions]
            for region in regions:
                return [boto.vpc.connect_to_region(region).get_all_subnets()[0].id]
    
    上面的简单代码将查找给定区域中的子网。当然,您可以根据需要自定义它

    然后在您的playbook中引用此插件以查找正确的子网:

    例如:

    - hosts: localhost
      gather_facts: no
      tasks:
        - name: Start instance
          debug: msg="Starting instance {{ item.ami }} in {{ item.region }} in {{ item.subnet }}"
          with_items:
            - region: us-west-1
              name: ss12
              ami: ami-b33dccf7  
              subnet: "{{ lookup('subnets', 'us-west-1') }}"
            - region: ap-northeast-1
              name: ss21
              ami: ami-9e5cff9e  
              subnet: "{{ lookup('subnets', 'ap-northeast-1') }}"
            - region: eu-west-1
              name: ss32
              ami: ami-7c4b0a0b 
              subnet: "{{ lookup('subnets', 'ap-northeast-1') }}"
    

    在您的情况下,您可能需要引用正确的
    AMI
    和相关的
    区域
    ,如果您仍然想在没有其他模块帮助的情况下执行此操作,您可以计算服务器和子网长度的模“%”:

    "{{subnets[item.0 | int % subnets | length | int].aws_ec2_subnets}}"
    
    示例代码

    变量:

    任务:

    我就是这样做的。 launchNodes.yml只是一个带有一些标记的简单ec2

    - debug:
        msg: "launching {{ nodeCount }} nodes in these subnets {{ec2SubnetIds}}"
    
    - name: clear finalSubnetList
      set_fact:
        finalSubnetList: []
    
    - name: build final list
      set_fact:
        finalSubnetList: "{{ finalSubnetList }} + [ '{{ ec2SubnetIds[ ( ec2subnet|int % ec2SubnetIds|length)|int ] }}' ]"
      with_sequence: count={{nodeCount}}  
      loop_control:
        loop_var: ec2subnet
    
    - debug:
        msg: "finalSubnetList {{finalSubnetList}} "
    
    - include_tasks: launchNodes.yml
          ec2SubnetId="{{ finalSubnetList[index|int -1] }}"
          nodeCount=1
      with_sequence: count="{{ finalSubnetList|length }}"
      loop_control:
        loop_var: index
    
    subnets:
      - {zone: "us-east-1a", aws_ec2_subnets: 'subnet-123'}
      - {zone: "us-east-1b", aws_ec2_subnets: 'subnet-456'}
      - {zone: "us-east-1d", aws_ec2_subnets: 'subnet-789'}
    
    server_list:
      - server1
      - server2
      - server3
    
    - name: Create new ec2 instance
      ec2:
        profile: "{{aws_profile}}"
        key_name: "{{aws_key_name}}"
        group_id: "{{aws_security_group}}"
        instance_type: "{{aws_instance_type}}"
        image: "{{aws_ami}}"
        region: "{{region}}"
        exact_count: "1"
        #instance_profile_name: none
        wait: yes
        wait_timeout: 500
        volumes: "{{volumes}}"
        monitoring: no
        vpc_subnet_id: "{{subnets[item.0 | int % subnets | length | int].aws_ec2_subnets}}"
        assign_public_ip: no
        tenancy: default
        termination_protection: yes
        instance_tags:
          App: "{{app_name}}"
          Environment: "{{environment_type}}"
          Platform: "{{platform_name}}"
          Name: "{{item.1}}"
        count_tag:
          App: "{{app_name}}"
          Environment: "{{environment_type}}"
          Platform: "{{platform_name}}"
          Name: "{{item.1}}"
      register: ec2_new_instance
      with_indexed_items:
        - "{{server_list}}"
    
    - debug:
        msg: "launching {{ nodeCount }} nodes in these subnets {{ec2SubnetIds}}"
    
    - name: clear finalSubnetList
      set_fact:
        finalSubnetList: []
    
    - name: build final list
      set_fact:
        finalSubnetList: "{{ finalSubnetList }} + [ '{{ ec2SubnetIds[ ( ec2subnet|int % ec2SubnetIds|length)|int ] }}' ]"
      with_sequence: count={{nodeCount}}  
      loop_control:
        loop_var: ec2subnet
    
    - debug:
        msg: "finalSubnetList {{finalSubnetList}} "
    
    - include_tasks: launchNodes.yml
          ec2SubnetId="{{ finalSubnetList[index|int -1] }}"
          nodeCount=1
      with_sequence: count="{{ finalSubnetList|length }}"
      loop_control:
        loop_var: index