Ansible的Playbook快速入门指南

                                              作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

目录

一.Playbook概述

1.什么是Playbook

在ansible中,比较简单的任务,我们可以直接调用单个模块来完成,但遇到比较复杂的场景,需要调用大量模块才能完成一个需求,或者多个任务间有依赖的时候,使用单条命令就特别不方便,这种情况下我们就需要Playbook剧本来实现。

Playbook字面意思是剧本,演员按照剧本来演戏,运维人员编写Playbook剧本内容,而后ansible按照我们编写的剧本去执行任务。

2.模块(module)和剧本(playbook)的区别

- Playbook是对多个AD-Hoc(module)的一种编排组合的实现方式;

- Playbook能控制任务执行的先后顺序;

- Playbook可以持久保存到文件从而方便多次调用运行,而Ad-Hoc(module)只能临时运行;

- Playbook适合复杂的重复性的任务,而Ad-Hoc(module)适合做快速简单的一次性任务;


温馨提示:
	AD-Hoc指的是使用模块的一种方式,比如: " ansible -m '模块名称' -a '参数信息' "

3.playbook文件规范

playbook文件规范:
	- 扩展名称为yaml或者yml;
	- 第一行使用"---"表示yaml的开始,一般不写,如果多个yaml文件合并才会使用此标识;
	- 使用"#"作为注释;
	- 大小写敏感;
	- 缩进符要统一,用空格键缩进,不要用tab;
	- 缩进空格数量不重要,但是,相同层级的左边缩进,要对齐,保持一致;
	- 使用"- "表示单个列表项目;
	- 使用": "表示一个键值对;
	- 使用"{}"表示一个键值表;
	- 一个name只能有一个task;

4.Playbook的组成

Playbook是由一个或多个"play"组成的列表,Playbook的主要功能在于,将多个play组织在一个Playbook文件中,让多台预定义的主机按照Playbook中编排的内容完成一系列复杂的功能。

一个Playbook至少要包含hosts和tasks两部分,主要由以下几部分组成:
	- hosts:
		指定要执行任务的远程主机,其值可以是通配符,主机或组。
		但一定要在主机清单中定义过的(/etc/ansible/hosts),可以用-i选项指定自定义的主机清单文件。
		
	- tasks:
		定义要在远程主机上执行的任务列表。
		各任务按顺序在hosts中指定主机上执行,即所有主机当做完当前任务,才会开始下一个任务。
		task的模式是执行指定模块,后面跟上预定的参数,参数中可以使用变量,模块的执行是幂等的。
		这意味着多次执行是安全的,因为其结果均一致。
		如果在执行过程中发生错误,则会全部回滚(包括前面已执行成功的)。
		每个task都应该定义name,用于执行结果的输出,如果没有指定name,则action的结果将用于输出。

	- remote_user:
		指定任务在远程主机上执行时,所使用的用户,可以是任意用户。
		也可以sudo,但前提是用户是存在的,可以不写,默认root。
		
	- tags:
		定义哪些代码内容可与被忽略,就是用tags跳过部分代码。
		标记应用于任务或包含的任务,这允许从命令行中选择任务的子集。
		
	- notify|handlers:
		一般配合使用,可以达到一种触发调用高度效果,类似于函数调用或触发器。
		
	- gather_facts:
		默认会自动调用的模块。
		获取远程主机的一些信息,可以在下面的任务重使用,相当于构造函数,可以禁用。
		
	- environment:
		定义Playbook运行时需要使用的变量,有多种定义方式。
		一个被转换为环境变量的字典,在执行时为任务提供。这只能与模块一起使用。
		任何其他类型的插件、Ansible本身及其配置都不支持此功能,它只是为负责执行任务的代码设置变量。
		这不是传递机密数据的推荐方式。
		
所有组成可以参考官方文档:
https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html

5.playbook示例

	1.编写配置文件
[root@worker232 ~]# cat ping.yaml 
- hosts: all
  remote_user: root
  tasks:
  - name: t1
    ping:
  - name: t2
    shell: "ifconfig"
[root@worker232 ~]# 

	
	2.加载Playbook示例
[root@worker232 ~]# ansible-playbook ping.yaml 


PLAY [all] ***********************************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************************
ok: [10.0.0.232]
ok: [10.0.0.233]
ok: [10.0.0.231]

TASK [t1] ************************************************************************************************************************************************
ok: [10.0.0.232]
ok: [10.0.0.233]
ok: [10.0.0.231]

TASK [t2] ************************************************************************************************************************************************
changed: [10.0.0.233]
changed: [10.0.0.231]
changed: [10.0.0.232]

PLAY RECAP ***********************************************************************************************************************************************
10.0.0.231                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
10.0.0.232                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
10.0.0.233                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@worker232 ~]# 

二.YAML语言

1.什么是YAML

yaml是"Yet Another Markup Language"的简称,YAML是一种人性化的数据序列化。

和HTML,XML,JSON类似,又是一款标记性语言,但你看它官网还会很傲娇的说" YAML Ain't Markup Language"。

YAML是一个可读性高的用来表达资料序列的格式,是目前比较流行的配置文件格式,很多新的项目或者软件都采用yaml文件来保存配置信息,比如ubuntu,ansible,docker,kubernetes,ElasticStack等。

官网地址:
	https://yaml.org

2.YAML的数据类型及特点

数据类型 描述 示例
scalar(标量) 单个的,不可再分的值。
包括但不限于字符串,布尔值,整数,浮点数,时间,日期,Null等。
name: "Jason Yin"
age: 18
object(对象) 键值对的集合,又称为字典(dictionary)|哈希(hashes)|映射(mapping) labels:
apps: xiuxian
version: v1
array(数组) 一组按次序排列的值,又称为列表(list)|序列(sequence) command:
- tail
- -f
- /etc/hosts
YAML中的数据类型如上表所示。

YAML语言特点:
    - yaml的可读性好;
    - yaml和脚本语言交互性强;
    - yaml使用实现语言的数据类型;
    - yaml有一个一致的信息模型;
    - yaml易于实现;
    - yaml可以基于流来处理;
    - yaml表达能力强,扩展性好;

三.ansible-playbook命令

1.ansible-playbook命令格式

1.1 语法格式

ansible-playbook [options] <filename.yaml> 

常见的选项[options]:
	--syntax-check|--syntax
		语法检查。
	-C|--check:
		执行模拟,只检测可能会发生的改变,但不真正执行操作。
	-i|--inventory|--inventory-file:
		指定主机清单文件。
	-l|--limit:
		单位指定主机列表去执行。
	-k|--ask-pass:
		远程连接密码。
	-T|--timeout:
		连接超时时长,默认10s。
	-e|--extra-vars:
		定义变量。
	--become-user:
		指定用户执行。
	--flush-cache:
		刷新facts。
	--list-hosts:
		列出所有主机。
	--list-tags:
		列出Playbook中所有tag。
	-skip-tags:
    	跳过指定tags。
    -t|--tags:
    	只执行特定tag对应的task。
    --start-at-task:
    	从指定task开始执行。
    --list-tasks:
    	列出Playbook中所有task。
    -v|--verbose:
    	显示详细信息,最多可以写5个v。

1.2 ansible-playbook选项示例

	1.编写主机清单文件
[root@worker232 ~]# cat /etc/ansible/hosts 
[k8s]
10.0.0.23[1:3]

[k8s:vars]
ansible_ssh_password=1
[root@worker232 ~]# 


	2.查看主机列表
[root@worker232 ~]# ansible-playbook --list-hosts demo.yaml 

playbook: demo.yaml

  play #1 (all): all	TAGS: []
    pattern: ['all']
    hosts (3):
      10.0.0.233
      10.0.0.232
      10.0.0.231
[root@worker232 ~]# 


	3.检查配置文件语法
[root@worker232 ~]# ansible-playbook --syntax -vvvvv demo.yaml 
ansible-playbook [core 2.12.0]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible-playbook
  python version = 3.10.12 (main, Nov  6 2024, 20:22:13) [GCC 11.4.0]
  jinja version = 3.0.3
  libyaml = True
Using /etc/ansible/ansible.cfg as config file
setting up inventory plugins
host_list declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
script declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
auto declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Parsed /etc/ansible/hosts inventory source with ini plugin
1 plays in demo.yaml

playbook: demo.yaml
[root@worker232 ~]# 

2.ansible-playbook执行结果

2.1 编写剧本

[root@worker232 ~]# cat demo.yaml 
  # 指定主机分组【支持主机的匹配模式】
- hosts: all
  # 不收集主机信息,以提升运行速度
  gather_facts: no
  # 定义远程执行的用户,如果不写,默认就是root用户。
  # 如果在主机清单中定义了"ansible_ssh_user"参数则无视此配置,下同。
  remote_user: root
  # 定义任务列表
  tasks:
    # 定义任务的名称
  - name: t1 
    # 具体的模块和参数
    command: id
    # 指定模块的执行用户,会覆盖掉上面的root用户
    remote_user: yinzhengjie
    # 对于查询类任务,我们就不让他改变系统
    changed_when: false
  - name: t2
    shell: "echo 10+20|bc"
    changed_when: false
  - name: t3
    copy: 'content=#!/usr/bin/python3.10\n\nprint("杰哥讲运维")\nprint("https://www.cnblogs.com/yinzhengjie") dest=/tmp/yinzhengjie.py'
[root@worker232 ~]# 

2.2 运行剧本

[root@worker232 ~]# ansible-playbook demo.yaml  -l 10.0.0.231 -v
Using /etc/ansible/ansible.cfg as config file

PLAY [all] ***********************************************************************************************************************************************

TASK [t1] ************************************************************************************************************************************************
ok: [10.0.0.231] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "cmd": ["id"], "delta": "0:00:00.003250", "end": "2025-01-12 08:53:55.392259", "msg": "", "rc": 0, "start": "2025-01-12 08:53:55.389009", "stderr": "", "stderr_lines": [], "stdout": "uid=1000(yinzhengjie) gid=1000(yinzhengjie) groups=1000(yinzhengjie),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd)", "stdout_lines": ["uid=1000(yinzhengjie) gid=1000(yinzhengjie) groups=1000(yinzhengjie),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd)"]}

TASK [t2] ************************************************************************************************************************************************
ok: [10.0.0.231] => {"changed": false, "cmd": "echo 10+20|bc", "delta": "0:00:00.003885", "end": "2025-01-12 08:53:55.626574", "msg": "", "rc": 0, "start": "2025-01-12 08:53:55.622689", "stderr": "", "stderr_lines": [], "stdout": "30", "stdout_lines": ["30"]}

TASK [t3] ************************************************************************************************************************************************
changed: [10.0.0.231] => {"changed": true, "checksum": "2ff8189035b80ea1a00758c53d6adb24eae663bf", "dest": "/tmp/yinzhengjie.py", "gid": 0, "group": "root", "md5sum": "9c969b0ba5be0a78c437540b16be8243", "mode": "0644", "owner": "root", "size": 92, "src": "/tmp/ansible-tmp-1736643235.0918655-37397-238348265580265/source", "state": "file", "uid": 0}

PLAY RECAP ***********************************************************************************************************************************************
10.0.0.231                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[root@worker232 ~]# 



PLAY RECAP执行结果说明:
	ok=3
    	3个task执行成功。
    changed=1
    	1个task导致了系统状态发生了变化。
    unreachable=0
    	0个task不可达。
    failed=0
    	0个task执行失败。
    skipped=0
    	0个task被跳过。
    rescued=0
    	0个task被拒绝。
    ignored=0  
    	0个task被忽略。

3.ansible-vault文件加密解密

3.1 创建新文件剧本【文件不能存在】

[root@worker232 ~]# ansible-vault create yinzhengjie.yaml
New Vault password: 
Confirm New Vault password: 
[root@worker232 ~]# 
[root@worker232 ~]# file yinzhengjie.yaml 
yinzhengjie.yaml: Ansible Vault, version 1.1, encryption AES256
[root@worker232 ~]# 
[root@worker232 ~]# cat yinzhengjie.yaml  # 无法查看文件内容
$ANSIBLE_VAULT;1.1;AES256
65373965353531316232383462303362313735326632333664353038656164623539663337373934
6164383661333862643366386665626664663632393838370a303532623834613264393730636665
63643134393263663835333666656138383132373636353130353134386532303837333535323838
3932636564663661350a643261313265636333326161373365363762646639663764383238306464
6261
[root@worker232 ~]# 

3.2 解密剧本文件内容

[root@worker232 ~]# ansible-vault view yinzhengjie.yaml
Vault password: # 输入密码后才能查看
- hosts: all
  tasks:
  - name: t1
    shell: id
[root@worker232 ~]# 

3.3 编辑加密剧本文件

[root@worker232 ~]# ansible-vault edit yinzhengjie.yaml 
Vault password:   # 编辑时也需要输入密码

3.4 执行加密剧本文件

[root@worker232 ~]# echo 1 > /tmp/pwd.log
[root@worker232 ~]# ansible-playbook --vault-password-file /tmp/pwd.log yinzhengjie.yaml 

3.5 删除密码保护

[root@worker232 ~]# file yinzhengjie.yaml 
yinzhengjie.yaml: Ansible Vault, version 1.1, encryption AES256
[root@worker232 ~]# 
[root@worker232 ~]# ansible-vault decrypt yinzhengjie.yaml
Vault password: 
Decryption successful
[root@worker232 ~]# 
[root@worker232 ~]# file yinzhengjie.yaml 
yinzhengjie.yaml: ASCII text
[root@worker232 ~]#

四.Playbook案例

1.创建用户和组

	1.编写剧本
[root@worker232 yinzhengjie]# cat bigdata_user.yaml 
- hosts: 10.0.0.231
  gather_facts: no
  tasks:
  - name: create hadoop group
    group: name=hadoop system=yes gid=666
  - name: create hdfs user
    user: name=hdfs system=yes group=hadoop uid=777 shell=/sbin/nologin home=/home/hdfs create_home=no
[root@worker232 yinzhengjie]# 

	
	2.检查剧本语法
[root@worker232 yinzhengjie]# ansible-playbook --syntax-check bigdata_user.yaml 

playbook: bigdata_user.yaml
[root@worker232 yinzhengjie]# 


	3.执行剧本
[root@worker232 yinzhengjie]# ansible-playbook -l 10.0.0.231 bigdata_user.yaml  


	4.远程服务器验证用户
[root@master231 ~]# id hdfs
uid=777(hdfs) gid=666(hadoop) groups=666(hadoop)
[root@master231 ~]# 
[root@master231 ~]# getent passwd hdfs
hdfs:x:777:666::/home/hdfs:/sbin/nologin
[root@master231 ~]# 
[root@master231 ~]# ll /home/
total 20
drwxr-xr-x  5 root        root         4096 Jan 10 00:28 ./
drwxr-xr-x 20 root        root         4096 Jan 11 12:14 ../
drwxr-x---  3        2026         2026 4096 Jan 10 00:28 hanpaopao/
drwxrwxrwx  4        1002 jasonyin2020 4096 Jan  5 23:53 jasonyin2020/
drwxr-x---  6 yinzhengjie yinzhengjie  4096 Jan  5 22:47 yinzhengjie/
[root@master231 ~]# 

2.安装nginx服务

	1.编写剧本
[root@worker232 yinzhengjie]# cat install_nginx.yaml 
- hosts: 10.0.0.233
  gather_facts: no
  tasks:
  - name: install nginx
    apt:
      name: nginx=1.18.0-6ubuntu14.5 
      state: present

  - name: set nginx index page
    copy:
      src: ./blog.txt
      # dest: /usr/share/nginx/html/index.html
      # 我的Ubuntu22.04 LTS系统安装nginx默认站点放在了/var/www/html
      dest: /var/www/html/index.html

  - name: restart nginx service
    service:
      name: nginx
      state: restarted
      enabled: yes
[root@worker232 yinzhengjie]# 
	
	2.准备测试页面
[root@worker232 yinzhengjie]# echo https://www.cnblogs.com/yinzhengjie > blog.txt
[root@worker232 yinzhengjie]# 
[root@worker232 yinzhengjie]# cat blog.txt 
https://www.cnblogs.com/yinzhengjie
[root@worker232 yinzhengjie]# 


	3.运行剧本
[root@worker232 yinzhengjie]# ansible-playbook -l 10.0.0.233 install_nginx.yaml 


	4.访问测试
[root@worker232 yinzhengjie]# curl 10.0.0.233
https://www.cnblogs.com/yinzhengjie
[root@worker232 yinzhengjie]# 

3.其他案例

有了上面的知识点,就可以完成我留的课堂作业了。

比如完成zookeeper,kafka,ElasticSearch,Prometheus,Ceph,K8S等集群的一键部署。

五.Playbook中的nofify和handlers

1.nofify和handlers概述

handlers本质上就是任务列表(task list),也定义了一系列task,每个task中同样调用指定模块执行操作。

只不过handlers中定义的task,不会主动执行,需要配合notify,让notify通知相应的handlers中的task,该task才会执行。

在Playbook中,如果有task执行失败,那整个Playbook也执行失败,即便有部分task执行成功,这部分task对饮高度handlers也不会被执行,force_handlers保证的是已成功执行的task对应的handlers一定会被执行。

nofify配合handlers,可以实现在特定条件下触发某些操作,例如服务器重启 ,服务重载等场景。


温馨提示:
	- 1.如果多个task通知了相同的handlers,此handlers仅会在所有task结束后运行一次;
	- 2.只有notify对应的task发生改变了才会通知handlers,没有改变则不会触发handlers;
	- 3.handlers是在所有前面的tasks都执行成功才会执行,如果前面任何一个task失败,会导致handlers跳过执行;

2.单个notify和handlers示例

	1.编写剧本
[root@worker232 yinzhengjie]# cat single-notify.yaml 
- hosts: 10.0.0.233
  gather_facts: no
  tasks:
  - name: set nginx index page
    copy:
      src: ./blog.txt
      dest: /usr/share/nginx/html/index.html

  - name: set nginx config
    copy: src=./nginx-sites.conf dest=/etc/nginx/conf.d
    # 当拷贝的文件发生变化时,就会触发handlers
    notify: reload nginx svc

  # handlers等到所有task执行完成之后才会被调用
  # 而且对于同一个handler,多个notify,也只会执行一次
  handlers:
  - name: reload nginx svc
    service: name=nginx state=restarted
[root@worker232 yinzhengjie]# 


	
	2.准备配置文件
[root@worker232 yinzhengjie]# cat nginx-sites.conf 
server {
	listen 81;

	server_name www.yinzhengjie.com;

	root /usr/share/nginx/html;

	index index.html;

	location / {
		try_files $uri $uri/ =404;
	}
}

[root@worker232 yinzhengjie]# 
	
	3.执行剧本
[root@worker232 yinzhengjie]# ansible-playbook -l 10.0.0.233 single-notify.yaml 


	4.访问测试
[root@worker232 yinzhengjie]# curl -H "host: www.yinzhengjie.com" 10.0.0.233:81
https://www.cnblogs.com/yinzhengjie
[root@worker232 yinzhengjie]# 

3.多个notify和handlers示例

	1.编写剧本 
[root@worker232 yinzhengjie]# cat multiple-notify.yaml 
- hosts: 10.0.0.233
  gather_facts: no
  tasks:
  - name: t1
    shell: echo "task 01"
    notify: [h1,h2]
  - name: t2
    shell: echo "task 02"
    notify: 
    - h1
    - h2
  handlers:
  - name: h1
    shell: echo h1
  - name: h2
    shell: echo h2
[root@worker232 yinzhengjie]# 


	2.执行剧本【2和task同时调用了多个handlers,但最终只会执行一次】
[root@worker232 yinzhengjie]# ansible-playbook multiple-notify.yaml

4.force_handlers示例

	1.编写剧本 
[root@worker232 yinzhengjie]# cat force_handlers.yaml 
- hosts: 10.0.0.231
  gather_facts: no
  # 表示成功执行的task,其调用的handlers肯定会执行成功
  force_handlers: yes
  tasks:
  - name: t1
    shell: echo "task01"
    notify: h1
  - name: t2
    # 故意让t2任务执行失败,因为我主机上并没有myecho命令哟~
    shell: myecho "task02"
    notify: h2
  - name: t3
    shell: echo "task01"
    notify: h3
  handlers:
  - name: h1
    debug: msg="in h1 handlers"
  - name: h2
    debug: msg="in h2 handlers"
  - name: h3
    debug: msg="in h3 handlers"
[root@worker232 yinzhengjie]# 

	
	2.执行剧本【由于第2个task失败,导致后续的handlers均无法调用】
[root@worker232 yinzhengjie]# ansible-playbook force_handlers.yaml 

六.ignore_errors忽略错误

1.ignore_errors概述

在同一个Playbook中,如果一个task出错,则默认不会再继续执行后续的其他task。

利用"ignore_errors: yes"可以忽略此错误,继续执行其他task,此项可以配置为全局选项。

2.ignore_errors示例

	1.编写剧本
[root@worker232 yinzhengjie]# cat ignore_errors.yaml
- hosts: 10.0.0.231
  gather_facts: no
  force_handlers: yes
  # 如果任务执行失败,则可以忽略错误继续向下执行任务。
  ignore_errors: yes
  tasks:
  - name: t1
    shell: echo "task01"
    notify: h1
  - name: t2
    shell: myecho "task02"
    notify: h2
  - name: t3
    shell: echo "task01"
    notify: h3
  handlers:
  - name: h1
    debug: msg="in h1 handlers"
  - name: h2
    debug: msg="in h2 handlers"
  - name: h3
    debug: msg="in h3 handlers"
[root@worker232 yinzhengjie]# 
 
 
	2.执行剧本【尽管t2任务执行失败,但t3依旧是可以正常执行的】
[root@worker232 yinzhengjie]# ansible-playbook ignore_errors.yaml 

七.Playbook的tags

1.tags概述

ansible在执行一个Playbook时,会执行Playbook中所有的任务,可以利用tag标记特定task而非整个Playbook文件。

一个task可以定义多个tags,也可以多个task对应同一个tag。

tags主要用于调试环境,内置有三个特殊的tags:
	- all:
		表示所有任务。
	- tagged:
		表示所有被tag标记的任务。
	- untagged:
		表示所有没有被标记的任务。

2.tags示例

	1.编写剧本
[root@worker232 yinzhengjie]# cat tags.yaml
- hosts: 10.0.0.231
  gather_facts: no
  tasks:
  - name: t1
    shell: echo "in t1 task"
    tags: [k8s,ceph]
  - name: t2
    shell: echo "in t2 task"
    tags: [k8s,docker]
  - name: t3
    shell: echo "in t3 task"
    tags: [elasticstack]
  - name: t4
    shell: echo "in t4 task"
[root@worker232 yinzhengjie]# 

	
	2.查看tags信息
[root@worker232 yinzhengjie]# ansible-playbook tags.yaml --list-tags

playbook: tags.yaml

  play #1 (10.0.0.231): 10.0.0.231	TAGS: []
      TASK TAGS: [ceph, docker, elasticstack, k8s]
[root@worker232 yinzhengjie]# 

	
	3.查看任务信息
[root@worker232 yinzhengjie]# ansible-playbook tags.yaml --list-tasks

playbook: tags.yaml

  play #1 (10.0.0.231): 10.0.0.231	TAGS: []
    tasks:
      t1	TAGS: [ceph, k8s]
      t2	TAGS: [docker, k8s]
      t3	TAGS: [elasticstack]
      t4	TAGS: []
[root@worker232 yinzhengjie]# 
	
	4.执行指定tags案例
[root@worker232 yinzhengjie]# ansible-playbook tags.yaml -t k8s
[root@worker232 yinzhengjie]# ansible-playbook tags.yaml -t docker
[root@worker232 yinzhengjie]# ansible-playbook tags.yaml -t elasticstack
[root@worker232 yinzhengjie]# ansible-playbook tags.yaml -t ceph,docker


	5.使用内置的tags案例
[root@worker232 yinzhengjie]# ansible-playbook tags.yaml -t untagged
[root@worker232 yinzhengjie]# ansible-playbook tags.yaml -t tagged
[root@worker232 yinzhengjie]# ansible-playbook tags.yaml -t all

八.Playbook的变量

1.playbook变量概述

Playbook支持变量的定义与引用,变量有数字,字母下划线组成,区分大小写且只能以字母开头。
    变量定义的两种方式:
        方式一:
            KEY=VALUE,例如: name=yinzhengjie
        方式二:
            KEY: VALUE,例如: age: 18

    引用变量的方式:
        通过"{{ 变量名称 }}"来调用,例如: "{{ name }}"
	
变量的来源:
	- 1.使用setup facts获取的远程主机信息都是放在变量中的,可以直接使用;
	- 2.在命令行执行ansible-playbook时,可以使用-e选项设置变量,这种变量的优先级最高;
	- 3.在Playbook文件中定义变量;
	- 4.在单独的变量文件中定义变量,在Playbook中引用该文件;
	- 5.在主机清单中定义,当单独主机的变量与分组的变量有冲突时,单独定义的主机变量,优先级更高;
	- 6.在主机变量目录(host_vars)和主机分组目录(group_vars)中创建以主机名或分组名为文件名的文件,在该文件中定义;
	- 7.使用register将其他task或模块执行的输出内容保存到变量中,供别的task来使用;
	- 8.在role中定义;
	
	
变量的优先级:
	- 1"-e"选项定义变量;
	- 2.Playbook中vars_files;
	- 3.Playbook中vars变量定义;
	- 4.host_vars/主机名文件;
	- 5.主机清单中主机变量;
	- 6.group_vars/主机组名文件;
	- 7.group_vars/all 文件;
	- 8.主机清单组变量;

2.使用setup模块中的变量

2.1 setup模块概述

在命令行中,可以通过指定setup模块的方式获取目标主机信息。在Playbook中,可以使用gather_facts选项来获得目标主机的信息。

gather_facts选项默认是yes,次执行都需要消耗一定的资源和时间,在不需要时可以禁用该项来加快Playbook的执行效率。

如果需要收集远程主机的信息,合理的配置“ansible.cfg”中facts相关的本地缓存策略,以便在频繁执行时减少资源消耗。
    gathering=implicit
        facts策略,有效值为: implicit(the default),explicit,smart。
        implicit:
        	不使用缓存,每次都抓取新的。
        explicit:
       		不收集主机信息,除非在playbook中用"gather_facts: yes"显式指定。
        smart:
        	远程主机信息如果有本地缓存,则使用缓存,如果没有,就去抓取,在存到缓存中,下次就直接使用缓存信息。

    fact_caching_timeout=86400
        本地缓存时长,默认86400s

    fact_caching=memory
        缓存类型,默认是memory,如果jsonfile,需要指定文件,如果redis,需要指定redis地址。

    fact_caching_connection=/path/to/cachedir
        本地缓存路径

2.2 开启gather_facts实战案例

	1.编写剧本
[root@worker232 yinzhengjie]# cat setup-facts.yaml 
- hosts: 10.0.0.231
  gather_facts: yes
  tasks:
  - name: show-facts
    debug: msg={{ ansible_facts }}
  - name: show-facts-hostname
    debug: msg={{ ansible_hostname }}
  - name: show-facts-ipv4-xixi
    debug: msg={{ ansible_facts["eth0"]["ipv4"]["address"] }}-----{{ ansible_facts.eth0.ipv4.address }}
  - name: show-facts-ipv4-haha
    debug: msg={{ ansible_eth0["ipv4"]["address"] }}@@@@@{{ ansible_eth0.ipv4.address }}
  - name: show-facts-ipv4-hehe
    debug: msg={{ ansible_default_ipv4["address"] }}#####{{ ansible_default_ipv4.address }}
[root@worker232 yinzhengjie]# 

	2.执行剧本
[root@worker232 yinzhengjie]# ansible-playbook setup-facts.yaml 

3 在命令行传递环境变量

3.1 编写剧本

[root@worker232 yinzhengjie]# cat facts-custom-variables.yaml 
- hosts: 10.0.0.231
  gather_facts: no
  tasks:
  - name: t1
    debug: msg={{ name }}:{{ hobby }}
  - name: t2
    shell: echo "https://www.cnblogs.com/yinzhengjie"
    notify: h1
  handlers:
  - name: h1
    debug: msg={{ gender }}
[root@worker232 yinzhengjie]# 

3.2 执行剧本

	1.在命令行中指定
[root@worker232 yinzhengjie]# ansible-playbook -e name=yinzhengjie -e hobby=K8S -e gender=boy facts-custom-variables.yaml -v


	2.多个变量一次定义
[root@worker232 yinzhengjie]# ansible-playbook -e "name=yinzhengjie hobby=K8S gender=boy" facts-custom-variables.yaml -v


	3.从文件中加载变量
[root@worker232 yinzhengjie]# cat ./variables.txt 
name: JasonYin2020
hobby: 象棋
gender: boy
[root@worker232 yinzhengjie]# 
[root@worker232 yinzhengjie]# ansible-playbook -e "@./variables.txt" facts-custom-variables.yaml -v

4.在Playbook文件中定义变量

4.1 Playbook文件变量概述

在Playbook文件中定义的变量,只能在当前Playbook中使用,属于私有变量。

4.2 Playbook文件变量案例

	1.编写剧本
[root@worker232 yinzhengjie]# cat variables-playbook.yaml
- hosts: 10.0.0.231
  gather_facts: yes
  vars:
    name: 尹正杰
    hobby: kubernetes
    gender: boy
    ip: "{{ ansible_facts.eth0.ipv4.address }}"
  tasks:
  - name: t1
    debug: msg={{ name }}:{{ hobby }}
  - name: t2
    shell: echo "https://www.cnblogs.com/yinzhengjie"
    notify: h1
  - name: t3
    debug: msg="变量支持互相调用 ---> {{ ip }}"
  handlers:
  - name: h1
    debug: msg={{ gender }}
[root@worker232 yinzhengjie]# 


	2.执行剧本
		2.1 使用Playbook定义的变量
[root@worker232 yinzhengjie]# ansible-playbook variables-playbook.yaml

		2.2 命令行传递的变量可以覆盖Playbook的变量
[root@worker232 yinzhengjie]# ansible-playbook -e "name=JasonYin" variables-playbook.yaml

5.在单独文件中定义变量

5.1 文件定义变量的优先级概述

在单独的变量文件中定义变量的优先级比在Playbook本身定义的变量优先级更高。

在Playbook引用变量使用"vars_files"来定义,而"vars"在Playbook内置的变量,命令行传参使用"-e"来指定。

5.2 文件定义变量案例

	1.定义变量文件
[root@worker232 yinzhengjie]# cat var01.txt 
name: JasonYin
age: 18
[root@worker232 yinzhengjie]# 
[root@worker232 yinzhengjie]# cat var02.txt 
address: BeiJing
[root@worker232 yinzhengjie]# 

	
	2.Playbook引用变量文件
[root@worker232 yinzhengjie]# cat ref-variables.yaml
- hosts: 10.0.0.231
  gather_facts: no
  vars_files:
  - var01.txt
  - /root/yinzhengjie/var02.txt
  vars:
    name: 尹正杰
    age: 30
    address: 北京
    hobby: "Kubernetes"
  tasks:
  - name: t1
    debug: msg="{{ name }}---{{ age }}---{{ address }}---{{ hobby }}"
[root@worker232 yinzhengjie]# 


	3.执行剧本
		3.1 验证vars_files优先级高于vars
[root@worker232 yinzhengjie]# ansible-playbook ref-variables.yaml

		3.2 验证命令行变量优先级更高,vars_files次之,vars最低
[root@worker232 yinzhengjie]# ansible-playbook -e "name=杰哥讲运维" ref-variables.yaml

6.在主机清单中定义变量

6.1 在主机清单定义变量

[root@worker232 yinzhengjie]# cat /etc/ansible/hosts 
[k8s]
# 给分组的特定主机添加变量
10.0.0.23[1:3] hobby="k8s"
10.0.0.14[1:3]

# 给整个分组定义变量
[k8s:vars]
ansible_ssh_password=1
name="yinzhengjie"
age=35
[root@worker232 yinzhengjie]# 

6.2 添加主机清单

	1.添加主机
[root@worker232 yinzhengjie]# cat ref-hosts-variables.yaml 
- hosts: 10.0.0.231
  gather_facts: no
  vars:
    address: 北京
  tasks:
  - name: t1
    debug: msg="{{ name }}---{{ age }}---{{ address }}---{{ hobby }}"
[root@worker232 yinzhengjie]# 


	2.执行脚本
[root@worker232 yinzhengjie]# ansible-playbook ref-hosts-variables.yaml

7.在项目目录中定义变量

7.1 项目中定义变量概述

在不同的项目中添加"host_vars","group_vars"目录。

在"host_vars"目录下添加主机名或IP命名的文件,将该主机的变量写在此文件中。

在group_vars目录中添加以分组命名的文件,将改组的变量写在此文件中。

7.2

	1.创建存放主机和组变量的目录
[root@worker232 yinzhengjie-apps]# mkdir group_vars host_vars
[root@worker232 yinzhengjie-apps]# 
[root@worker232 yinzhengjie-apps]# ll
total 16
drwxr-xr-x 4 root root 4096 Jan 14 00:17 ./
drwxr-xr-x 3 root root 4096 Jan 14 00:17 ../
drwxr-xr-x 2 root root 4096 Jan 14 00:17 group_vars/
drwxr-xr-x 2 root root 4096 Jan 14 00:17 host_vars/
[root@worker232 yinzhengjie-apps]# 


	2.查看主机清单
[root@worker232 yinzhengjie-apps]# cat /etc/ansible/hosts 
[k8s]
10.0.0.23[1:3]
[root@worker232 yinzhengjie-apps]# 


	3.定义组变量【远程主机清单存在的组】
[root@worker232 yinzhengjie-apps]# tree 
.
├── group_vars
│   └── k8s
├── host_vars
│   └── 10.0.0.231
├── my-variables.yaml
└── ref-project-vars.yaml

2 directories, 4 files
[root@worker232 yinzhengjie-apps]# 
[root@worker232 yinzhengjie-apps]# cat group_vars/k8s 
ansible_ssh_password: 1
name: "yinzhengjie"
age: 35
[root@worker232 yinzhengjie-apps]# 

	4.定义主机变量【远程主机清单存在的主机】
[root@worker232 yinzhengjie-apps]# cat host_vars/10.0.0.231 
hobby: "k8s"
[root@worker232 yinzhengjie-apps]# 

	5.自定义变量
[root@worker232 yinzhengjie-apps]# cat my-variables.yaml 
address: 北京
[root@worker232 yinzhengjie-apps]# 

	6.引用自定义变量
[root@worker232 yinzhengjie-apps]# cat ref-project-vars.yaml 
- hosts: 10.0.0.231
  gather_facts: no
  vars_files:
  - my-variables.yaml
  tasks:
  - name: t1
    debug: msg="{{ name }}---{{ age }}---{{ address }}---{{ hobby }}"
[root@worker232 yinzhengjie-apps]# 

	7.运行剧本
[root@worker232 yinzhengjie-apps]# ansible-playbook ref-project-vars.yaml

8.register注册变量

8.1 register注册变量概述

在Playbook中可以使用register将捕获命令的输出保存在临时变量中,方便后续调用此变量。

说白了,就是让前一个task的结果保存为一个变量,让后一个task去使用该变量。

8.2 register注册变量案例

	1.编写剧本
[root@worker232 yinzhengjie]# cat register-variables.yaml 
- hosts: 10.0.0.231
  gather_facts: no
  tasks:
  - name: t1
    shell: hostname
    # 使用关键字定义一个名称为"server_name"的变量,将执行结果放在该变了中
    register: server_name
  - name: t2
    # 调用变量
    debug: msg={{ server_name }}
  - name: t3
    # 调用变量的多个字段
    debug: msg={{ server_name.stdout }}---{{ server_name.start }}---{{ server_name.end }}


[root@worker232 yinzhengjie]# 


	2.运行变量
[root@worker232 yinzhengjie]# ansible-playbook register-variables.yaml -k
posted @ 2025-01-16 01:21  尹正杰  阅读(926)  评论(0)    收藏  举报