在 Ansible 新開機器時,運用 add_host 於執行時期立即加進 in-memory inventory 的方法

最近在評估 GCP,不能免俗地要嘗試使用 Ansible 自動開 GCE 機器、設定組態,遇到一個之前在 AWS EC2 上印象中沒有遇過的問題。

一般來說,我們會先在 localhost 上用 gce module 透過 GCP API 發出建立機器的操作命令,大概會像這樣(註:這邊大量借用了 Ansible 這頁的範例):

- name: Create instance(s)
  hosts: localhost
  gather_facts: no
  connection: local

  vars:
    machine_type: n1-standard-1
    image: 'ubuntu-1604-xenial-v20170811'
    service_account_email: unique-id@developer.gserviceaccount.com
    credentials_file: /path/to/project.json
    project_id: project-id

  tasks:
    - name: Launch instances
      gce:
          instance_names: running_man
          machine_type: "{{ machine_type }}"
          image: "{{ image }}"
          service_account_email: "{{ service_account_email }}"
          credentials_file: "{{ credentials_file }}"
          project_id: "{{ project_id }}"
          tags: consumer_server

然後在機器建起來之後,我直覺會利用 Dynamic Inventory 透過 tag 之類的資源定位方式,把開好的機器找出來:

- name: Provision instance(s)
  hosts: tag_consumer_server
  # 以下省略

但是可能是 GCE dynamic inventory script (gce.py) 預設的 cache 時效問題,我在這步常常需要「踩發」好幾次才能成功得出機器列表。

我找了一下網上的討論,才發現我沒有看到 Ansible 的 GCE 範例文件裡有個眉眉角角的地方,叫做 add_host:

---
- name: Create instance(s)
# 中略
# ...
  tasks:
    - name: Launch instances
      gce:
          instance_names: dev
          machine_type: "{{ machine_type }}"
          image: "{{ image }}"
          service_account_email: "{{ service_account_email }}"
          credentials_file: "{{ credentials_file }}"
          project_id: "{{ project_id }}"
          tags: webserver
      register: gce

    - name: Wait for SSH to come up
      wait_for: host={{ item.public_ip }} port=22 delay=10 timeout=60
      with_items: "{{ gce.instance_data }}"

    - name: Add host to groupname
      add_host: hostname={{ item.public_ip }} groupname=new_instances
      with_items: "{{ gce.instance_data }}"

當我們處理好機器開設時,可以設一個 register,讓接下來的 tasks 去捕捉這個 task 的處理結果。

在 ‘Wait for SSH to come up’ 我們就先使用 wait_for module 先偵測 SSH port (22) 是否起來了,來判斷這台機器是否「大致上可用」(因為 Ansible 主要原理還是靠 SSH 去遠端下一些控制命令)。如果是,我們接下來在 ‘Add host to groupname’ 就用 add_host 把這台跑起來的機器加進 in-memory inventory 當中一個叫做 new_instances 的 group,於是接下來我們就可以直接利用這份 inventory 列表來對這台(些)機器進行各種組態設定:

- name: Manage new instances
  hosts: new_instances
  connection: ssh
  become: True
  tasks:
    - name: Install essential packages
      apt:
        name: "{{ item }}"
        state: present
      with_items:
        - 'redis-tools'
        - 'ruby2.3'

這個 add_host 看起來不管用在哪家雲端服務業者都可以,因此還可以省去多 call 一次 API 重抓 inventory 的工。又學到了一課。

CC BY-SA 4.0 This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Leave a Reply

Your email address will not be published. Required fields are marked *