ansible:playbook詳解

Blog:部落格園 個人

概述

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

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

playbook文件是使用YAML語言編寫的。

YAML語言

官網://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://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