【问题标题】:Creating n new instances in AWS EC2 VPC and then configuring them在 AWS EC2 VPC 中创建 n 个新实例,然后配置它们
【发布时间】:2020-03-18 13:00:19
【问题描述】:

我很难完成看似相当标准的任务,所以我希望有人能帮助我。我疯狂地用谷歌搜索了这个,大多数示例不在 VPC 中,或者使用了不推荐使用的结构,这使得它们在我的用例中错误或无法使用。

这是我的目标:

  1. 我想在我的 VPC 中启动一大堆新实例(相同的 下面的代码有 3 个,但可能是 100 个)
  2. 我想等待那些实例复活
  3. 然后我想配置这些实例(SSH 进入它们,更改 主机名,启用某些服务等)

现在我大概可以在 2 个任务中做到这一点。我可以在 1 个剧本中创建实例。等他们安定下来。然后运行第二个剧本来配置它们。这可能就是我现在要做的,因为我想动起来——但必须有一个一次性的答案。

这是我目前所拥有的一本剧本

---
- hosts: localhost
  connection: local
  gather_facts: False
  tasks:
    - name: Provision Lunch
      with_items:
        - hostname: eggroll1
        - hostname: eggroll2
        - hostname: eggroll3
      ec2:
        region: us-east-1
        key_name: eggfooyong
        vpc_subnet_id: subnet-8675309
        instance_type: t2.micro
        image: ami-8675309
        wait: true
        group_id: sg-8675309
        exact_count: 1
        count_tag:
          Name: "{{ item.hostname }}"
        instance_tags:
          Name: "{{ item.hostname }}"
          role:   "supper"
          ansibleowned: "True"
      register: ec2

    - name: Wait for SSH to come up
      wait_for: host={{ item.private_ip }} port=22 delay=60 timeout=900 state=started
      with_items: '{{ec2.instances}}'

    - name: Update hostname on instances
      hostname: name={{ item.private_ip }}
      with_items: '{{ec2.instances}}'

那是行不通的。我得到的是

TASK [Wait for SSH to come up] *************************************************
[DEPRECATION WARNING]: Skipping task due to undefined Error, in the future this will be a fatal error.. This feature will be removed in a future release. Deprecation warnings can be disabled by setting
deprecation_warnings=False in ansible.cfg.

TASK [Update hostname on instances] ********************************************
[DEPRECATION WARNING]: Skipping task due to undefined Error, in the future this will be a fatal error.. This feature will be removed in a future release. Deprecation warnings can be disabled by setting
deprecation_warnings=False in ansible.cfg.

这让我很难过。现在这是我最新的那本剧本的化身。但是我尝试使用我在互联网上找到的每个示例来重写它。他们中的大多数都有 with_items 以不同的方式编写,但 ansible 告诉我这种方式已被贬低,然后失败了。

到目前为止,ansible 既有趣又简单,但这让我想把笔记本电脑扔到街对面。

有什么建议吗?我应该使用 register 和 with_items 吗?使用这样的东西会更好吗:

add_host: hostname={{item.public_ip}} groupname=deploy

相反?我很乐意在这里重写。我将在 2 个剧本中编写此内容,并希望得到建议。

谢谢!

****编辑**** 现在它刚刚开始感到破碎或严重改变。我用谷歌搜索了几十个示例,它们的编写方式都相同,并且都因相同的错误而失败。这是我现在的简单剧本:

---
- hosts: localhost
  connection: local
  gather_facts: False
  vars:
    builderstart: 93
    builderend: 94
  tasks:
    - name: Provision Lunch
      ec2:
        region: us-east-1
        key_name: dakey
        vpc_subnet_id: subnet-8675309
        instance_type: t2.micro
        image: ami-8675309
        wait: True
        group_id: sg-OU812
        exact_count: 1
        count_tag:
          Name: "{{ item }}"
        instance_tags:
          Name: "{{ item }}"
          role:   "dostuff"
          extracheese: "True"
      register: ec2
      with_sequence: start="{{builderstart}}" end="{{builderend}}" format=builder%03d


    - name: the newies
      debug: msg="{{ item }}"
      with_items: "{{ ec2.instances }}"

真的再简单不过了。不管我怎么写,不管我怎么改变它,我都会得到同样的基本错误:

[弃用警告]:由于未定义的错误而跳过任务,在 未来这将是一个致命错误。:'dict object' 没有属性 '实例'。

所以看起来是 with_items: "{{ ec2.instances }}" 行导致了错误。

我使用 debug 打印出 ec2 并且该错误看起来准确。看起来结构改变了我。看起来 ec2 现在包含一个字典,其中结果作为另一个字典对象的键,并且该实例是该字典中的键。但我找不到一种理智的方式来访问数据。

不管怎样,我已经尝试在 2.0.1、2.0.2 和 2.2 中访问它,但在每种情况下我都遇到了同样的问题。

你们其他人是在使用 1.9 还是其他版本?我在任何地方都找不到有效的例子。这很令人沮丧。

再次感谢您的帮助。

【问题讨论】:

  • 你需要使用“可变基础设施”范式吗?一种选择是使用 Packer 提前配置您的 AMI。您甚至可以让 Packer 为您执行 Ansible 剧本。然后您可以直接启动 AMI。关于您的 Ansible 错误,不确定。
  • 嗯,您的问题在于您使用 EC2 模块的方式
  • 您可以使用自动缩放组来添加 ec2,然后对配置进行 ansible 完成
  • 我想到了这一点,但我尽量不在我的解决方案中嵌入太多 AWS 服务,因为我不确定我们是否会在一年后仍然存在。我试图在我的方法中与云无关。不过谢谢。

标签: amazon-web-services amazon-ec2 ansible amazon-vpc


【解决方案1】:

不要这样:
- name: Provision Lunch with_items: - hostname: eggroll1 - hostname: eggroll2 - hostname: eggroll3 ec2: region: us-east-1

因为通过使用它,您可以在您的项目中刷新来自 ec2 的所有信息。
您收到以下输出:

TASK [Launch instance] *********************************************************
changed: [localhost] => (item={u'hostname': u'eggroll1'})
changed: [localhost] => (item={u'hostname': u'eggroll2'})

但是项目应该是这样的:

changed: [localhost] => (item={u'kernel': None, u'root_device_type': u'ebs', u'private_dns_name': u'ip-172-31-29-85.ec2.internal', u'public_ip': u'54.208.138.217', u'private_ip': u'172.31.29.85', u'id': u'i-003b63636e7ffc27c', u'ebs_optimized': False, u'state': u'running', u'virtualization_type': u'hvm', u'architecture': u'x86_64', u'ramdisk': None, u'block_device_mapping': {u'/dev/sda1': {u'status': u'attached', u'delete_on_termination': True, u'volume_id': u'vol-37581295'}}, u'key_name': u'eggfooyong', u'image_id': u'ami-fce3c696', u'tenancy': u'default', u'groups': {u'sg-aabbcc34': u'ssh'}, u'public_dns_name': u'ec2-54-208-138-217.compute-1.amazonaws.com', u'state_code': 16, u'tags': {u'ansibleowned': u'True', u'role': u'supper'}, u'placement': u'us-east-1d', u'ami_launch_index': u'1', u'dns_name': u'ec2-54-208-138-217.compute-1.amazonaws.com', u'region': u'us-east-1', u'launch_time': u'2016-04-19T08:19:16.000Z', u'instance_type': u't2.micro', u'root_device_name': u'/dev/sda1', u'hypervisor': u'xen'})

尝试使用以下代码

- name: Create a sandbox instance
  hosts: localhost
  gather_facts: False
  vars:
    keypair: eggfooyong
    instance_type: t2.micro
    security_group: ssh
    image: ami-8675309
    region: us-east-1
    subnet: subnet-8675309
    instance_names:
      - eggroll1
      - eggroll2
  tasks:
    - name: Launch instance
      ec2:
        key_name: "{{ keypair }}"
        group: "{{ security_group }}"
        instance_type: "{{ instance_type }}"
        image: "{{ image }}"
        wait: true
        region: "{{ region }}"
        vpc_subnet_id: "{{ subnet }}"
        assign_public_ip: no
        count: "{{ instance_names | length }}"
      register: ec2

    - name: tag instances
      ec2_tag:
        resource: '{{ item.0.id }}'
        region: '{{ region }}'
        tags:        
          Name: '{{ item.1 }}'
          role:   "supper"
          ansibleowned: "True"
      with_together:
        - '{{ ec2.instances }}'
        - '{{ instance_names }}'

    - name: Wait for SSH to come up
      wait_for: host={{ private_ip }} port=22 delay=60 timeout=320 state=started
      with_items: '{{ ec2.instances }}'

假设您的 ansible 主机位于 VPC 内部

【讨论】:

  • Ansible 主机位于我的 VPC 中 - 这看起来很有希望,并且与我在自己的搜索中找到的任何东西都非常不同。我会试一试,然后告诉你。谢谢!
  • @ericwoodworth 进展如何?
  • 被其他东西猛烈抨击。我将 2 个 ansible 剧本拼凑在一起完成工作,然后按顺序运行它们。这足以让人们工作,但我将在明天或周末重写它。这里的建议看起来很有希望,我一定会留下跟进。
  • 你好 - 我回来了,这似乎不起作用。我在网上看到过一百个这样的例子,但都失败了。
  • 奇怪,因为我检查过它并且它有效。你可以运行我的代码并显示输出吗?
【解决方案2】:

为了实现这个目标,我写了一个非常小的过滤器插件get_ec2_info

创建一个名为filter_plugins的目录

创建一个插件文件get_ec2_info.py,内容如下:

from jinja2.utils import soft_unicode

class FilterModule(object):

    def filters(self):
        return {
            'get_ec2_info': get_ec2_info,
        }

def get_ec2_info(list, ec2_key):

    ec2_info = []
    for item in list:
        for ec2 in item['instances']:
            ec2_info.append(ec2[ec2_key])
    return ec2_info

然后你可以在你的剧本中使用它:

---
- hosts: localhost
  connection: local
  gather_facts: False
  tasks:
    - name: Provision Lunch
      ec2:
        region: us-east-1
        key_name: eggfooyong
        vpc_subnet_id: subnet-8675309
        instance_type: t2.micro
        image: ami-8675309
        wait: true
        group_id: sg-8675309
        exact_count: 1
        count_tag:
          Name: "{{ item.hostname }}"
        instance_tags:
          Name: "{{ item.hostname }}"
          role:   "supper"
          ansibleowned: "True"
      register: ec2
      with_items:
        - hostname: eggroll1
        - hostname: eggroll2
        - hostname: eggroll3
   - name: Create SSH Group to login dynamically to EC2 Instance(s)
     add_host: 
       hostname: "{{ item }}"
       groupname: my_ec2_servers
     with_items: "{{ ec2.results | get_ec2_info('public_ip') }}"

   - name: Wait for SSH to come up on EC2 Instance(s)
     wait_for:
       host: "{{ item }}" 
       port: 22 
       state: started
     with_items: "{{ ec2.results | get_ec2_info('public_ip') }}" 

# CALL THE DYNAMIC GROUP IN THE SAME PLAYBOOK
- hosts: my_ec2_servers
  become: yes 
  remote_user: ubuntu
  gather_facts: yes
  tasks:
    - name: DO YOUR TASKS HERE

额外信息:

  • 使用 ansible 2.0.1.0
  • 假设您正在启动 ubuntu 实例,如果没有,则更改 remote_user: ubuntu 中的值
    • 假设 ssh 密钥配置正确

请查阅这些 github 存储库以获得更多帮助:

【讨论】:

  • 所以这看起来很有趣。看起来你正在处理我看到的额外的信息抽象层。您还将获得 ec2.results,其中包含您真正想要的信息。我会检查你的过滤器。当你第一次写这篇文章时,我不明白我遇到的问题足以看到你在做什么。现在我想我做到了,这对我来说更有意义。
  • @ericwoodworth,您还可以查看提供的 github 参考以获取完整示例
【解决方案3】:

我认为这对调试很有帮助。

https://www.middlewareinventory.com/blog/ansible-dict-object-has-no-attribute-stdout-or-stderr-how-to-resolve/

ec2 寄存器是 dict 类型。它有一个密钥results

results 键有很多元素,包括dictlist,如下所示:

{
    "msg": {
        "results": [
            {
                "invocation": {
                },
                "instances": [],
                "changed": false,
                "tagged_instances": [
                    {
                    }
                ],
                "instance_ids": null,
                "failed": false,
                "item": [
                ],
                "ansible_loop_var": "item"
            }
        ],
        "msg": "All items completed",
        "changed": false
    },
    "_ansible_verbose_always": true,
    "_ansible_no_log": false,
    "changed": false
}

因此,您可以使用 . 获取所需的数据,例如,item.changed 具有 false 布尔值。

- debug:
    msg: "{{ item.changed }}"
  loop: "{{ ec2.results }}"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-26
    • 2017-12-14
    • 2015-07-22
    • 2020-06-13
    相关资源
    最近更新 更多