ansible:playbook詳解

不羈的羅恩發表於2021-04-19

Blog:部落格園 個人

概述

playbook是由一個或者多個play組成的列表。

主要功能是將預定義的一組主機裝扮成事先通過ansible中的task定義好的角色。task實際是呼叫ansible的一個模組,將多個play組織在一個playbook中,即可以讓它們聯合起來,將事先編排的機制執行預定義的動作。

playbook檔案是使用YAML語言編寫的。

YAML語言

官網:https://yaml.org/

YAML(Yet another Markup Language,仍是一種標記語言)是一個可讀性高的用來表達資料序列的格式。

目前很多軟體採用了此格式,如ansible、docker、k8s等。

語法說明

  • YAML 的配置檔案字尾為.yml
  • 大小寫敏感
  • 使用縮排表示層級關係
  • 縮排不允許使用tab,只允許空格
  • 縮排的空格數不重要,只要相同層級的元素左對齊即可
  • #表示註釋,從這個字元一直到行尾,都會被解析器忽略

資料結構

YAML 支援的資料結構有三種。

  • 物件:鍵值對的集合,又稱為對映(mapping)/ 雜湊(hashes) / 字典(dictionary)
  • 陣列:一組按次序排列的值,又稱為序列(sequence) / 列表(list)
  • 純量(scalars):單個的、不可再分的值

物件

物件的一組鍵值對,使用冒號:結構表示。例如:

name: 'Rohn'

Yaml 也允許另一種寫法,將所有鍵值對寫成一個行內物件。例如:

{ hash: { name: 'Steve', foo: 'bar' } }

陣列

一組連詞線-開頭的行,構成一個陣列。例如:

- Cat
- Dog
- Goldfish

純量

純量是最基本的、不可再分的值。

純量的型別:

  • 字串
  • 布林值
  • 整數
  • 浮點數
  • Null
  • 時間
  • 日期
字串
  • 字串預設不使用引號表示。
  • 如果字串之中包含空格或特殊字元,需要放在引號之中。
  • 單引號和雙引號都可以使用,雙引號不會對特殊字元轉義。
  • 單引號之中如果還有單引號,必須連續使用兩個單引號轉義。
  • 字串可以寫成多行,從第二行開始,必須有一個單空格縮排。換行符會被轉為空格。
  • 多行字串可以使用|保留換行符,也可以使用>摺疊換行。
  • +表示保留文字塊末尾的換行,-表示刪除字串末尾的換行。
  • 字串之中可以插入 HTML 標記。

核心元素

元素 說明
hosts 遠端主機列表
tasks 任務集
variables 內建變數或自定義變數,用於playbook中呼叫
templates 模板
handlers和notify handlers和notify配合使用,由特定條件觸發的操作,滿足條件則執行,否則不執行
tags 標籤

hosts

playbook中的每一個play的目的是為了讓特定主機以某個指定使用者身份執行任務。hosts用於指定要執行指定任務的主機,需事先定義在主機清單中。例如:

- hosts: websrvs:dbsrvs  # 或者,兩個組的並集
- hosts: websrvs:&dbsrvs # 與,兩個組的交集
- hosts: websrvs:!dbsrvs # 在websrvs組,但不在dbsrvs組

remote_user

可以用於host和task中。也可通過指定其通過sudo的方式在遠端主機上執行任務,其可用於play全域性或某任務;此外,甚至可以在sudo時使用sudo_user指定sudo時切換的使用者。

task列表和action元件

play的主體部分是task list。task list中有一個或者多個task,各個task按順序逐個在hosts指定的所有主機上執行、也就是所有主機完成一個task後,再開始下一個task。

task的目的是使用指定的引數執行模組,而在模組引數中可以使用變數。模組執行是冪等的,這意味著多次執行是安全的,因為其結果均一致。

每個task都應該有name,用於playbook的執行結果輸出,建議其內容能清晰地描述任務執行步驟。若未能提供name,則action的結果將用於輸出。

task格式有兩種:

  • action: module arguments
  • module: arguments # 推薦使用這種

Tips:shell模組和command的模組後面跟的是命令,而非key=value的方式。

其他元件

若有任務的狀態在執行後為changed時,可通過notify通知給相應的handlers。

shell指令碼和playbook對比

部署Nginx

Shell指令碼:

#!/bin/bash
yum -y install nginx
\cp /tmp/nginx.conf /etc/nginx/
\cp /tmp/web.conf /etc/nginx/conf.d/
systemctl enable nginx
nginx -t
systemctl start nginx

playbook實現:

---
- hosts: web_server
  remote_user: root
  tasks:
    - name: "部署nginx"
      yum: name=nginx
    - name: "複製配置檔案"
      copy: src=/tmp/nginx.conf dest=/etc/nginx/
    - name: "複製配置檔案"
      copy: src=/tmp/web.conf dest=/etc/nginc/conf.d/
    - name: "啟動nginx,並設定開機啟動"
      service: name=nginx state=started enable=yes

playbook命令

語法格式

usage: ansible-playbook [-h] [--version] [-v] [-k]
                        [--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]
                        [-c CONNECTION] [-T TIMEOUT]
                        [--ssh-common-args SSH_COMMON_ARGS]
                        [--sftp-extra-args SFTP_EXTRA_ARGS]
                        [--scp-extra-args SCP_EXTRA_ARGS]
                        [--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers]
                        [--flush-cache] [-b] [--become-method BECOME_METHOD]
                        [--become-user BECOME_USER] [-K] [-t TAGS]
                        [--skip-tags SKIP_TAGS] [-C] [--syntax-check] [-D]
                        [-i INVENTORY] [--list-hosts] [-l SUBSET]
                        [-e EXTRA_VARS] [--vault-id VAULT_IDS]
                        [--ask-vault-pass | --vault-password-file VAULT_PASSWORD_FILES]
                        [-f FORKS] [-M MODULE_PATH] [--list-tasks]
                        [--list-tags] [--step] [--start-at-task START_AT_TASK]
                        playbook [playbook ...]

精簡為:

ansible-playbook <filename.yml> ... [options]

常用引數

引數 說明
-C 只檢測可能發生的改變,並不真正執行操作
--list-hosts 列出執行任務的主機
--list-tags 列出tag
--list-taks 列出task
--limit 只針對主機列表中的主機執行
-v 顯示過程

例子

安裝MariaDB

---
#Installing MariaDB Binary Tarballs
- hosts: db_server
  remote_user: root
  gather_facts: no

  tasks:
    - name: create group
      group: name=mysql gid=27 system=yes
    - name: create user
      user: name=mysql uid=27 system=yes group=mysql shell=/sbin/nologin home=/data/mysql create_home=no
    - name: mkdir datadir
      file: path=/data/mysql owner=mysql group=mysql state=directory
    - name: unarchive package
      unarchive: src=/data/ansible/files/mariadb-10.2.27-linux-x86_64.tar.gz dest=/usr/local/ owner=root group=root
    - name: link
      file: src=/usr/local/mariadb-10.2.27-linux-x86_64 path=/usr/local/mysql state=link 
    - name: install database
      shell: chdir=/usr/local/mysql   ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql
    - name: config file
      copy: src=/data/ansible/files/my.cnf  dest=/etc/ backup=yes
    - name: service script
      shell: /bin/cp  /usr/local/mysql/support-files/mysql.server  /etc/init.d/mysqld
    - name: start service
      service: name=mysqld state=started enabled=yes
    - name: PATH variable
      copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh

變數

變數名:僅能由字母、數字和下劃線組成,且只能以字母開頭。

語法格式

var=value

例如:

db_port=3306

變數呼叫方式

"{{ variable_name }}"

變數來源

  • ansible 的 setup facts 遠端主機的所有變數都可直接呼叫;

  • 通過命令列指定變數,優先順序最高

    ansible-playbook -e var=value
    
  • 在playbook檔案中定義:

      vars:
        - var1: value1
        - var2: value2
    
  • 在獨立的變數YAML檔案中定義:

      - hosts: all
        vars_files:
          - vars.yml
    
  • /etc/ansible/hosts中定義:

    • 主機(普通)變數:主機組中主機單獨定義,優先順序高於公共變數;
    • 組(公共)變數:針對主機組中所有主機定義同一變數;
  • 在role中定義

template模板

模板是一個文字檔案,可以作為生成檔案的模板,並且模板檔案中還可以巢狀jinja語法。

jinja語言

URL:https://jinja.palletsprojects.com/en/2.11.x/

  • jinja2 語言使用字面量,有下面形式:
  • 字串:使用單引號或雙引號
  • 數字:整數,浮點數
  • 列表:[item1, item2, ...]
  • 元組:(item1, item2, ...)
  • 字典:{key1:value1, key2:value2, ...}
  • 布林型:true/false
  • 算術運算:+, -, *, /, //, %, **
  • 比較操作:==, !=, >, >=, <, <=
  • 邏輯運算:and,or,not
  • 流表示式:For,If,When

流程控制

template中也可以使用流程控制 for 迴圈和 if 條件判斷,實現動態生成檔案功能。

例如:

#temlnginx2.yml
---
- hosts: websrvs
  remote_user: root
  vars:
    nginx_vhosts:
      - 81
      - 82
      - 83
  tasks:
    - name: template config
      template: src=nginx.conf.j2 dest=/data/nginx.conf

#templates/nginx.conf2.j2
{% for vhost in  nginx_vhosts %}
server {
   listen {{ vhost }}
}
{% endfor %}

ansible-playbook -C  templnginx2.yml  --limit 10.0.0.8

#生成的結果:
server {
   listen 81   
}
server {
   listen 82   
}
server {
   listen 83   
}

例項

同步nginx配置檔案:

---
- hosts: web_server
  remote_user: root
  
  tasks:
    - name: "config"
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf

相關文章