返回介绍

如何在 Playbooks 使用 loops?

发布于 2024-10-04 19:05:51 字数 14608 浏览 0 评论 0 收藏 0

現代 IT 人一定要知道的 Ansible 自動化組態技巧

18. 如何在 Playbooks 使用 loops?

在 Shell Script 裡,我們會使用 for 和 while 等迴圈 (loop) 來簡化重複的程式碼,而在 Ansible 我們也可用 loop 來簡化重複的任務 (Tasks)。以下凍仁將介紹常見的 loop 語法。

automate_with_ansible_practice-23.jpg ▲ 圖片來源:http://screencastsolutions.ca/looping-for-continuous-play/

標準迴圈 (Standard Loops)

首先讓我們以簡單的重複印出 3 筆訊息為例。

Shell Script

先複習一下 Shell Script 的寫法。

  1. 建立 for loop 的 Script。

    #!/bin/bash
    $ vi bash_loop.sh
    for X in 0 1 2; do
      echo Loop $X
    done
    
    • 在第 3 行,我們用了 for,並代入了 0, 1, 2 三個值到 $X 變數。
    • 在第 4 行時,則用了 echo,印出訊息和 $X 變數。
  2. 執行 Script:可以看到底下跑了 3 次的 loop。

    $ ./bash_loop.sh
    Loop 0
    Loop 1
    Loop 2
    

Ansible Playbooks

我們需透過 itemwith_items 來使用 Ansible 的 loop,其 item 為預設名,一般情況下不可修改。

在 Ansible 2.1 新增了 Loop Control 的語法,可透過 loop_controlloop_var 來自訂 item 的名字,這在多重 loop 等較複雜的環境下會有很大的幫助。1

  1. 建立 loop 的 playbook。

    $ vi playbook_loop.yml
    ---
    - name: a basic loop with playbook
      hosts: localhost
      tasks:
        - name: print loop message
          debug:
            msg: "Loop {{ item }}"
          with_items:
            - 0
            - 1
            - 2
    

    註:rawendraw 是為了相容 GitBook 所增加的語法,您可能會在某平台上看到它,請忽略之。

    • 在第 7, 8 行裡,我們用了 debug module 來印出訊息,並定義 item
    • 在第 9 ~ 12 行裡,則用了 with_items 將 0, 1, 2 的值傳入 item
  2. 執行 Playbook:可以看到 print loop message task 跑了 3 次的 loop。

    $ ansible-playbook playbook_loop.yml
    
    PLAY [a basic loop with playbook] *********************************************
    
    TASK [setup] *******************************************************************
    ok: [localhost]
    
    TASK [print loop message] ******************************************************
    ok: [localhost] => (item=0) => {
        "item": 0,
        "msg": "Loop 0"
    }
    ok: [localhost] => (item=1) => {
        "item": 1,
        "msg": "Loop 1"
    }
    ok: [localhost] => (item=2) => {
        "item": 2,
        "msg": "Loop 2"
    }
    
    PLAY RECAP *********************************************************************
    localhost                  : ok=2    changed=0    unreachable=0failed=0
    
  3. 凍仁常用此手法來安裝多個套件,接著以建立 chusiang/ansible-jupyter Docker image 的 setup_jupyter.yml 為例。 2

    $ vi setup_jupyter_yml
    01 ---
    02 - hosts: localhost
    03
    04   vars:
    05     # Same package on GNU/Linux.
    06     same_packages:
    07       - bash
    08       - bash-completion
    09       - ca-certificates
    10       - curl
    11       - git
    12       - openssl
    13
    14     # Alpine Linux.
    15     apk_packages:
    16       - openssh-client
    17       - vim
    18
    19     # Debian, Ubuntu.
    20     apt_packages: "{{ apk_packages }}"
    21     ...
    22
    23   tasks:
    24     # General Linux.
    25     - name: install same packages
    26       package: name={{ item }} state=present
    27       with_items: "{{ same_packages }}"
    28       when:
    29         - same_packages is defined
    30         - ansible_pkg_mgr != "portage"
    31
    32     # Alpine Linux.
    33     - name: install apk packages
    34       apk: name={{ item }} state=present
    35       with_items: "{{ apk_packages }}"
    36       when:
    37         - apk_packages is defined
    38         - ansible_pkg_mgr == "apk"
    39
    40     # Debian, Ubuntu.
    41     - name: install apt packages
    42       apt: name={{ item }} state=present
    43       with_items: "{{ apt_packages }}"
    44       when:
    45         - apt_packages is defined
    46         - ansible_pkg_mgr == "apt"
    47     ...
    

    註:rawendraw 是為了相容 GitBook 所增加的語法,您可能會在某平台上看到它,請忽略之。

    • 在第 6, 15, 20 行裡,分別宣告 same_packages, apk_packagesapt_packages 變數,並傳入了幾個套件名稱。
    • 在第 26, 27, 34, 35, 42, 43 行裡,定義了 item,並將 same_packages 變數傳入。換句話說就是 install same packages task 會安裝 same_packages 定義的所有套件。
    • 由於此例中 apk, apt 的套件名稱皆相同,故在第 20 行用了 apt_packages: "" 的手法讓 apt_packages = apk_packages

進階迴圈 (Advanced Loops)

如有數個變數需求,可用 item.first, item.second 類似屬性的方式定義 items。

  1. 建立擁有兩個 item 屬性的 loop 的 playbook。

    $ vi playbook_loop_adv1.yml
    ---
    - name: a advanced loop with playbook
      hosts: localhost
      tasks:
        - name: print loop message
          debug:
            msg: "Loop {{ item.num }}: {{ item.str }}"
          with_items:
            - { num: '0', str: 'automate' }
            - { num: '1', str: 'with' }
            - { num: '2', str: 'ansible' }
    

    註:rawendraw 是為了相容 GitBook 所增加的語法,您可能會在某平台上看到它,請忽略之。

  2. 執行 Playbook:這次除了跑 3 次 loop 以外,還代入 numstr 屬性的 items。

    $ ansible-playbook playbook_loop_adv1.yml
    
    PLAY [a advanced loop with playbook] *******************************************
    
    TASK [setup] *******************************************************************
    ok: [localhost]
    
    TASK [print loop message] ******************************************************
    ok: [localhost] => (item={u'num': u'0', u'str': u'automate'}) => {
        "item": {
            "num": "0",
            "str": "automate"
        },
        "msg": "Loop 0: automate"
    }
    ok: [localhost] => (item={u'num': u'1', u'str': u'with'}) => {
        "item": {
            "num": "1",
            "str": "with"
        },
        "msg": "Loop 1: with"
    }
    ok: [localhost] => (item={u'num': u'2', u'str': u'ansible'}) => {
        "item": {
            "num": "2",
            "str": "ansible"
        },
        "msg": "Loop 2: ansible"
    }
    
    PLAY RECAP *********************************************************************
    localhost                  : ok=2    changed=0    unreachable=0    failed=0
    
  3. 這部份在新增多個使用者、多個軟連結 (soft link) 時都會用到。

    $ vi playbook_loop_adv2.yml
    ---
    - name: a advanced loop with playbook
      hosts: localhost
      tasks:
        - name: create multiple soft link
          file:
            src: "~/vcs/4.docs/automate-with-ansible/lab/ch18/{{ item.src }}"
            dest: "/tmp/{{ item.dest }}"
            state: link
          with_items:
            - { src: 'playbook_loop.yml', dest: 'loop0.yml' }
            - { src: 'playbook_loop_adv1.yml', dest: 'loop1.yml' }
            - { src: 'playbook_loop_adv2.yml', dest: 'loop2.yml' }
    
    # vim: ft=ansible :
    

    註:rawendraw 是為了相容 GitBook 所增加的語法,您可能會在某平台上看到它,請忽略之。

    • 第 8 行的 src絕對路徑會因環境而有變動,還請特別留意一下。

後語

以個人經驗而言,掌握這兩個技巧就可以解決大多的迴圈需求!若想深入了解這部份,請研讀官方的 Loops | Ansible Documentation 文件 3

相關連結

1. 更多 Loop Control 的介紹請參考 https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#loop-control
2. 在友人的提醒下補了行號以利閱讀,若想複製該範例,請直接上 GitHub 取用。
3. 凍仁從 Ansible 1.9 開始踏入 Ansible 的世界,在 Ansible 2.0 之後新增的 loop 語法凍仁至今 (2016.12.18) 還未完全使用過。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文