Ansible--playbook的使用

2021年09月09日 阅读数:106
这篇文章主要向大家介绍Ansible--playbook的使用,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

1、什么是playbooks
playbooks是ansible的脚本、如同shell脚本同样,它是控制远程主机的一系列命令的集合,经过YAML语言编写。执行一些简单的任务,咱们可使用ad-hoc命令就能够解决,对于一些较复杂的任务,ad-hoc就不能胜任了,这时候playbooks就派上用场了,在playbooks中能够编排有序的执行过程,甚至能够在多组机器间来回有序的执行特定的步骤,而且能够同步或异步发起任务。html

2、YAML语法
一、文件开始符mysql

1
---

二、数组linux

1
2
3
- name
- hosts
- user

三、字典nginx

1
2
name: restart apache
service: name=httpd state=restarted

字典与字典的嵌套:git

1
2
3
vars:
   http_port: 80
   max_clients: 200

字典与数组的嵌套:github

1
2
3
4
5
6
7
8
9
tasks:
   - name: ensure apache is at the latest version
     yum: pkg=httpd state=latest
   - name: write the apache config  file
     template: src= /srv/httpd .j2 dest= /etc/httpd .conf
     notify:
     - restart apache
   - name: ensure apache is running
     service: name=httpd state=started

此外,Ansible 使用 "{{ var }}"来引用变量.,若是一个值以 "{" 开头, YAML 将认为它是一个字典, 因此咱们必须引用它, 像这样:foo: "{{ variable }}"web

3、playbooks的基本用法
最基本的playbook分为四部分:sql

  • 定义主机和用户shell

1
2
hosts
users
  • 定义 playbook 执行须要的变量apache

1
variable
  • 定义任务

1
tasks
  • 定义响应事件

1
handlers

简单示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
- name: Install apache
   hosts: webservers
   user: root
   gather_facts:  false
   vars:
     http_port: 80
     max_clients: 200
   tasks:
   - name: ensure apache is at the latest version
     yum: pkg=httpd state=latest
   - name: write the apache config  file
     template: src= /srv/httpd .j2 dest= /etc/httpd .conf
     notify:
     - restart apache
   - name: ensure apache is running
     service: name=httpd state=started
   handlers:
     - name: restart apache
       service: name=httpd state=restarted

说明:

  • name参数对此playbook实现的功能的概述,执行时会输出name变量值。

  • hosts参数指定了在哪些主机上执行playbook

  • user参数指定在远程主机上使用什么用户执行任务

  • gather_facts参数指定了下面任务执行前,是否先执行setup模块获取远程主机相关信息,这些信息在task中能够做为变量使用

  • vars参数指定了变量

  • task参数指定了任务,这里有3个任务。name参数是对具体任务的描述,在执行过程当中会输出

  • handlers参数指定一个响应事件,当template: src=/srv/httpd.j2 dest=/etc/httpd.conf这个任务执行状态是changed时才会触发。

 一、主机和用户

key 含 义
hosts 为主机的IP,或者主机组名,或者关键字all
user 在远程以哪一个用户身份执行。
become 切换成其它用户身份执行,值为yes或者no
become_method 与became一块儿用,指能够为‘sudo’/’su’/’pbrun’/’pfexec’/’doas’
become_user 与bacome一块儿用,能够是root或者其它用户名

通常用法:

1
2
3
---
- hosts: webserver, [all]
   user: root

还能够在每一个 task 中,定义远程执行用户

1
2
3
4
5
6
7
---
- hosts: webserver
   user: root
   tasks:
   - name:  test   connection
     ping :
     remote_user: root

也支持 sudo 方法,在 task中一样支持,在sudo须要密码时,能够加上选项 –ask-sudo-pass

1
2
3
4
5
6
7
8
---
- hosts: all
   user:  test
   sudo :  yes
   task:
     - service: name=nginx state=started
       sudo :  yes
       sudo_user: root

二、任务列表
tasks 是从上到下顺序执行,若是中间发生错误,整个 playbook 便会中断。
每个 task 是对module的一次调用,一般会带有特定参数,参数可使用变量。
每个 task 有一个 name 属性,name 值会在命令行中输出,以提示用户,若是没有定义,aciton 的值会做为输出信息来标记task。

语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
tasks:
   - name:  make   sure apache is running
     service: name=httpd state=running
//   若是参数过长,可使用空格或者缩进分隔为多行
tasks:
   - name: copy ansible inventory  file   to client
     copy: src= /etc/ansible/hosts   dest= /etc/ansible/hosts
           owner=root group=root mode=0644
//   或者使用 yaml 的字典做为参数
tasks:
   - name: copy ansible inventory  file   to client
     copy:
       src:  /etc/ansible/hosts
       dest:  /etc/ansible/hosts
       owner: root
       group: root
       mode: 0644
//   大部分的模块都是使用 `key-value` 这种格式的,其中有两个比较特殊, command   和 shell 模块。
tasks:
   - name: disable selinux
     command :  /sbin/setenforce   0
tasks:
   - name: run this  command   and ignore the result
     shell:  /usr/bin/command   ||  /bin/true
tasks:
   - name: run some  command   and ignore the reslut
     shell:  /usr/bin/somecommadn
     ignore_error: True

执行状态:
task中每一个action会调用一个module,在module中会去检查当前系统状态是否须要从新执行。
若是本次执行了,那么action会获得返回值changed
若是不须要执行,那么action获得返回值ok

三、响应事件
每一个主流的编程语言都会有event机制,那么handler就是playbook的event。
Handlers里面的每个handler,也是对module的一次调用。而handlers与tasks不一样,tasks会默认的按定义顺序执行每个task,handlers则不会,它须要在tasks中被调用,才有可能被执行。Tasks中的任务都是有状态的,changed或者ok。 在Ansible中,只在task的执行状态为changed的时候,才会执行该task调用的handler,这也是handler与普通的event机制不一样的地方。
什么状况下使用handlers呢?
若是你在tasks中修改了apache的配置文件。须要重起apache。此外还安装了apache的插件。那么还须要重起apache。像这样的应该场景中,重启apache就能够设计成一个handler。

特性:

  • 一个handler最多只执行一次

在全部的任务里表执行以后执行,若是有多个task notify同一个handler,那么只执行一次。
在下面的例子里apache只执行一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
- hosts: lb
   remote_user: root
   vars:
       random_number1:  "{{ 10000 | random }}"
       random_number2:  "{{ 10000000000 | random }}"
   tasks:
   - name: Copy the  /etc/hosts   to  /tmp/hosts .{{ random_number1 }}
     copy: src= /etc/hosts   dest= /tmp/hosts .{{ random_number1 }}
     notify:
       - call  in   every action
   - name: Copy the  /etc/hosts   to  /tmp/hosts .{{ random_number2 }}
     copy: src= /etc/hosts   dest= /tmp/hosts .{{ random_number2 }}
     notify:
       - call  in   every action
 
   handlers:
   - name: call  in   every action
     debug: msg= "call in every action, but execute only one time"
  • action是Changed ,才会执行handler

只有当TASKS种的action的执行状态是changed时,才会触发notify handler的执行。
下面的脚本执行两次,执行结果是不一样的:
第一次执行是,tasks的状态都是changed,会触发两个handler
第二次执行是,
第一个task的状态是OK,那么不会触发handlers"call by /tmp/hosts",
第二个task的状态是changed,触发了handler"call by /tmp/hosts.random_number"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 示例代码
---
- hosts: lb
   remote_user: root
   vars:
       random_number:  "{{ 10000 | random }}"
   tasks:
   - name: Copy the  /etc/hosts   to  /tmp/hosts
     copy: src= /etc/hosts   dest= /tmp/hosts
     notify:
       - call by  /tmp/hosts
   - name: Copy the  /etc/hosts   to  /tmp/hosts .{{ random_number }}
     copy: src= /etc/hosts   dest= /tmp/hosts .{{ random_number }}
     notify:
       - call by  /tmp/hosts .random_number
 
   handlers:
   - name: call by  /tmp/hosts
     debug: msg= "call first time"
   - name: call by  /tmp/hosts .random_number
     debug: msg= "call by /tmp/hosts.random_number"
  • 按Handler的定义顺序执行

andlers是按照在handlers中定义个顺序执行的,而不是安装notify的顺序执行的。
下面的例子定义的顺序是1>2>3,notify的顺序是3>2>1,实际执行顺序:1>2>3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
---
- hosts: lb
   remote_user: root
   gather_facts: no
   vars:
       random_number1:  "{{ 10000 | random }}"
       random_number2:  "{{ 10000000000 | random }}"
   tasks:
   - name: Copy the  /etc/hosts   to  /tmp/hosts .{{ random_number1 }}
     copy: src= /etc/hosts   dest= /tmp/hosts .{{ random_number1 }}
     notify:
       - define the 3nd handler
   - name: Copy the  /etc/hosts   to  /tmp/hosts .{{ random_number2 }}
     copy: src= /etc/hosts   dest= /tmp/hosts .{{ random_number2 }}
     notify:
       - define the 2nd handler
       - define the 1nd handler
 
   handlers:
   - name: define the 1nd handler
     debug: msg= "define the 1nd handler"
   - name: define the 2nd handler
     debug: msg= "define the 2nd handler"
   - name: define the 3nd handler
     debug: msg= "define the 3nd handler"

四、变量
playbook中经常使用变量的几种状况:

  • 用户自定义的变量

用户能够在Playbook中,经过vars关键字自定义变量,使用时用{{ }}引用以来便可。
示例:

1
2
3
4
5
6
7
8
---
- hosts: web
   vars:
     http_port: 80
   remote_user: root
   tasks:
   - name: insert firewalld rule  for   httpd
     firewalld: port={{ http_port }} /tcp   permanent= true   state=enabled immediate= yes
  • 把变量放在单独的文件中

当变量比较多的时候,或者变量须要在多个playbook中重用的时候,能够把变量放到一个单独的文件中。经过关键字var_files把文件中定义的变量引入playbook中,使用变量的方法和在本文件中定义的变量相同。

1
2
3
4
5
6
7
8
9
10
- hosts: web
   remote_user: root
   vars_files:
       - vars /server_vars .yml
   tasks:
   - name: insert firewalld rule  for   httpd
     firewalld: port={{ http_port }} /tcp   permanent= true   state=enabled immediate= yes
 
#cat vars/server_vars.yml
http_port: 80

定义复杂的变量
当变量的值不是简单的字符串或者数字,而是一个字典,语法以下

1
2
3
foo:
   field1: one
   field2: two

访问复杂变量中的子属性,能够利用中括号或者点号:

1
2
3
foo[ 'field1' ]
foo.field1
  • 系统变量(facts)

ansible会经过module setup来收集主机的系统信息,这些收集到的系统信息叫作facts,这些facts信息能够直接以变量的形式使用。
有哪些facts变量能够引用呢?在命令行上经过调用setup module命令能够查看:

1
$ ansible all -m setup -u root

系统变量在playbook中能够直接使用:

1
2
3
4
5
6
7
8
9
10
11
12
---
- hosts: all
   user: root
   tasks:
   - name:  echo   system
     shell:  echo   {{ ansible_os_family }}
   - name  install   ntp on Debian linux
     apt: name=git state=installed
     when: ansible_os_family ==  "Debian"
   - name  install   ntp on redhat linux
     yum: name=git state=present
     when: ansible_os_family ==  "RedHat"

对于复杂的、多层级的facts变量,能够经过下面的两种方式的任意一种访问复杂的变量中的子属性:
中括号:

1
{{ ansible_ens3[ "ipv4" ][ "address" ] }}

点号:

1
{{ ansible_ens3.ipv4.address }}

关系facts变量,一旦关闭以后就不用调用了。关闭方法:

1
2
- hosts: webserver
   gather_facts: no
  • 注册变量

把task的执行结果也能够做为一个变量值。这个时候就须要用到“注册变量”,将执行结果注册到一个变量中,待后面的action使用。

1
2
3
4
5
6
7
8
9
---
- hosts: web
   tasks:
      - shell:  ls
        register: result
        ignore_errors: True
      - shell:  echo   "{{ result.stdout }}"
        when: result.rc == 5
      - debug: msg= "{{ result.stdout }}"

注册变量常常和debug module一块儿使用,这样能够获得更多action的输出信息,帮助用户调试。

  • 命令行中传递的变量

为了使Playbook更灵活、通用性更强,容许用户在执行的时候传入变量的值,这个时候就须要用到“额外变量”。
定义命令行变量
在test.yml文件里,hosts和user都定义为变量,须要从命令行传递变量值。

1
2
3
4
5
---
- hosts:  '{{ hosts }}'
   remote_user:  '{{ user }}'
   tasks:
   ...

在命令行里面传值得的方法:

1
ansible-playbook testyml --extra-vars  "hosts=web user=root"

还能够用json格式传递参数:

1
ansible-playbook  test .yml --extra-vars  "{'hosts':'vm-rhel7-1', 'user':'root'}"

还能够将参数放在文件里面:

1