文章引导
前言
示例
错误处理
tags
标记
触发器handlers
条件判断
调试debug
前言
上一章节说到,用ansible-playbook执行yaml文件来到达某一种目的。这章来讲过滤器。
示例
一:使用过滤器给密码加密
- 使用
user
模块,创建一个用户,并赋予一个密码
[root@ansible ~]# vim users.yaml
---
- hosts: db
remote_user: root
vars:
username: mysql
tasks:
- name: 添加用户
user:
name: "{{username}}"
group: users
password: "1234"
##执行yaml文件
[root@ansible ~]# ansible-playbook users.yaml
PLAY [db] ********************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************
ok: [db1]
TASK [添加用户] ******************************************************************************************************************
[WARNING]: The input password appears not to have been hashed. The 'password' argument must be encrypted for this module to
work properly.
changed: [db1]
PLAY RECAP *******************************************************************************************************************
db1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
##验证
[root@ansible ~]# ssh mysql@db1
mysql@db1's password:
Permission denied, please try again.
##发现登录不上,去目标主机看看,是否由此用户
[root@db1 ~]# cat /etc/shadow | grep mysql
mysql:1234:19536:0:99999:7:::
##找到问题所在,发现影子文件应该把密码存为加密的方式保存,在这里却显示了明文密码,那么就发现了问题所在,所有登录不上。
- 使用过滤器,把密码变为加密后的参数,然后再写入影子文件中,密码加密方式为
SHA512
##修改users.yaml
---
- hosts: db
remote_user: root
vars:
username: mysql
tasks:
- name: 添加用户
user:
name: "{{username}}"
group: users
password: "{{'1234'|password_hash('sha512')}}"
##password_hash是password的过滤器函数算法,把密码加密成需要的sha512的格式。
##解读:把字符串1234转化为sha512的加密格式然后直接存入到影子文件中。
##执行users.yaml
[root@ansible ~]# ansible-playbook users.yaml
PLAY [db] ********************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************
ok: [db1]
TASK [添加用户] ******************************************************************************************************************
changed: [db1]
PLAY RECAP *******************************************************************************************************************
db1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
##验证
[root@ansible ~]# ssh mysql@db1
mysql@db1's password:
Last failed login: Wed Jun 28 17:43:53 CST 2023 from 192.168.32.7 on ssh:notty
There was 1 failed login attempt since the last successful login.
二:通过外部变量传参到yaml文件里要求为(yaml和json格式)
- 通过
json
传参
##修改user.yaml文件,注释变量。
---
- hosts: web
remote_user: root
# vars:
# username: mysql
tasks:
- name: 添加用户
user:
name: "{{username}}"
group: users
password: "{{'1234'|password_hash('sha512')}}"
##执行命令, -e 就是变量参数,编写一个json格式的键值对,username是yaml文件的变量,web是对username变量的赋值。
[root@ansible ~]# ansible-playbook users.yaml -e '{"username": "web"}'
PLAY [web] *******************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************
ok: [web2]
ok: [web1]
TASK [添加用户] ************************************************************************************************************** ****
changed: [web1]
changed: [web2]
PLAY RECAP *******************************************************************************************************************
web1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
##验证
[root@ansible ~]# ssh web@web1
web@web1's password:
[web@web1 ~]$ exit
登出
Connection to web1 closed.
[root@ansible ~]# ssh web@web2
web@web2's password:
[web@web2 ~]$ exit
登出
Connection to web2 closed.
- 通过
yaml
传参
##编写yaml文件,定义一个不变量名为username,值为test。
[root@ansible ~]# vim args.yaml
--- #文件开始
username: #变量名
test #变量值
##执行命令,-e 指定变量 @是指定的文件
[root@ansible ~]# ansible-playbook users.yaml -e @args.yaml
PLAY [db1] *********************************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************************
ok: [db1]
TASK [添加用户] ********************************************************************************************************************************************************
changed: [db1]
PLAY RECAP *********************************************************************************************************************************************************
db1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
##验证
[root@ansible ~]# ssh test@db1
test@db1's password:
[test@db1 ~]$ exit
登出
Connection to db1 closed.
错误处理
尽量不要用ansible的shell命令去执行,多使用ansible的模块去执行。shell在playbook里面执行的是按照顺序执行的,一条一条执行,然后前一条命令执行失败了后,后面的命令是不会执行的。
如果真的要是使用shell执行的话,会预感到错误,就需要加上判断和逻辑关系。
一:创建文件夹然后重启httpd服务,使用shell命令与模块对比
- 编写yaml
[root@ansible ~]# vim service1.yaml
---
- hosts: web1,web2
remote_user: root
# vars: #定义变量关键字
# service: httpd #变量的键值对key:value
tasks:
- name: mkdir /tmp/test
shell: mkdir /tmp/test
- name: restart httpd
service:
name: "{{service}}"
state: restarted
##在变量yaml文件写入所需变量
[root@ansible ~]# vim args.yaml
---
username:
test
service:
httpd
##执行yaml
[root@ansible ~]# ansible-playbook service1.yaml -e @args.yaml
[root@ansible ~]# ansible-playbook service1.yaml -e @args.yaml
PLAY [web1,web2] ***************************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************************
ok: [web1]
ok: [web2]
TASK [mkdir /tmp/test] *********************************************************************************************************************************************
[WARNING]: Consider using the file module with state=directory rather than running 'mkdir'. If you need to use command because file is insufficient you can add
'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message.
fatal: [web2]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/test", "delta": "0:00:00.003528", "end": "2023-06-28 19:01:05.793504", "msg": "non-zero return code", "rc": 1, "start": "2023-06-28 19:01:05.789976", "stderr": "mkdir: 无法创建目录\"/tmp/test\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/test\": 文件已存在"], "stdout": "", "stdout_lines": []}
fatal: [web1]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/test", "delta": "0:00:00.003595", "end": "2023-06-28 19:01:21.161762", "msg": "non-zero return code", "rc": 1, "start": "2023-06-28 19:01:21.158167", "stderr": "mkdir: 无法创建目录\"/tmp/test\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/test\": 文件已存在"], "stdout": "", "stdout_lines": []}
PLAY RECAP *********************************************************************************************************************************************************
web1 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
web2 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
##发现通过shell去创建目录,如果目录存在就会报错导致后面所有都执行不下去,下面采用file模块来创建,
##通过doc查看模块案例,file模块创建文件夹,如果存在就不存在,如果不存在就创建。这样就避免了脚本的错误率
[root@ansible ~]# ansible-doc file
- name: Create a directory if it does not exist
file:
path: /etc/some_directory
state: directory
mode: '0755'
##修改service1.yaml
[root@ansible ~]# vim service1.yaml
---
- hosts: web1,web2
remote_user: root
tasks:
- name: mkdir /tmp/test
file:
path: /tmp/test
state: directory
mode: '0755'
- name: restart httpd
service:
name: "{{service}}"
state: restarted
##执行yaml
[root@ansible ~]# ansible-playbook service1.yaml -e @args.yaml
PLAY [web1,web2] ***************************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************************
ok: [web1]
ok: [web2]
TASK [mkdir /tmp/test] *********************************************************************************************************************************************
ok: [web2]
ok: [web1]
TASK [restart httpd] **********************************************************************************************************************************************
changed: [web1]
changed: [web2]
PLAY RECAP *********************************************************************************************************************************************************
web1 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
二:如果shell模块发生错误,增加ignore_erros
参数来解决
ignore_errors: True
表示忽略错误继续执行,默认为False
##编写service1.yaml
[root@ansible ~]# vim service1.yaml
---
- hosts: web1,web2
remote_user: root
tasks:
- name: mkdir /tmp/test
shell: mkdir /tmp/test
ignore_errors: True #默认为False,
- name: restart httpd
service:
name: "{{service}}"
##执行yaml,不管发生任何错误都是略过执行下一个命令模块。
[root@ansible ~]# ansible-playbook service1.yaml -e @args.yaml
[root@ansible ~]# ansible-playbook service1.yaml -e @args.yaml
PLAY [web1,web2] ***************************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************************
ok: [web2]
ok: [web1]
TASK [mkdir /tmp/test] *********************************************************************************************************************************************
[WARNING]: Consider using the file module with state=directory rather than running 'mkdir'. If you need to use command because file is insufficient you can add
'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message.
fatal: [web1]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/test", "delta": "0:00:00.004034", "end": "2023-06-28 19:15:20.528831", "msg": "non-zero return code", "rc": 1, "start": "2023-06-28 19:15:20.524797", "stderr": "mkdir: 无法创建目录\"/tmp/test\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/test\": 文件已存在"], "stdout": "", "stdout_lines": []}
...ignoring
fatal: [web2]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/test", "delta": "0:00:00.003959", "end": "2023-06-28 19:15:05.165913", "msg": "non-zero return code", "rc": 1, "start": "2023-06-28 19:15:05.161954", "stderr": "mkdir: 无法创建目录\"/tmp/test\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/test\": 文件已存在"], "stdout": "", "stdout_lines": []}
...ignoring
TASK [restart httpd] **********************************************************************************************************************************************
changed: [web2]
changed: [web1]
PLAY RECAP *********************************************************************************************************************************************************
web1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
web2 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
##无论执行多次都会往下执行。
tags
标记
在写playbook中,当有一些特定的功能需要临时调用的时候,去临时调用的标记。
YAML语法:
- name: NAME
- module: arguments
- tags: TAG_ID
playbook调用方式
- -t TAGS, --tags=TAGS
- 编写一个更新apache的配置文件和网页的playbook
[root@ansible ~]# cat httpd1.yaml
---
- hosts: web #主机组
remote_user: root #使用账户
tasks:
- name: Ensure the default Apache port is 8080
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: '^Listen '
insertafter: '^#Listen '
line: Listen 80
- name: copy文件到主机
copy:
src: /root/index.html #源端文件
dest: /var/www/html/index.html #目标地址文件
owner: root #文件权限属性
group: root #属于组
mode: 644
tags: index
- name: 设置自启动和启动服务
service:
name: httpd
state: restarted
##编写index.html
[root@ansible ~]# cat index.html
hello word !!!!
ansible test !!!!!
测试 TAGS!!!!!!!!!!!!!!!!!!!!!!
##验证使用-t参数加上tags的名字,多个名字用英文逗号分割
[root@ansible ~]# ansible-playbook httpd1.yaml -t index
PLAY [web] *********************************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************************
ok: [web1]
ok: [web2]
TASK [copy文件到主机] ***************************************************************************************************************************************************
changed: [web2]
changed: [web1]
PLAY RECAP *********************************************************************************************************************************************************
web1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
##发现日志只输出了copy的TASK
##验证
[root@ansible ~]# curl web1
hello word !!!!
ansible test !!!!!
测试 TAGS!!!!!!!!!!!!!!!!!!!!!!
[root@ansible ~]# curl web2
hello word !!!!
ansible test !!!!!
测试 TAGS!!!!!!!!!!!!!!!!!!!!!!
触发器handlers
触发条件:当关注的资源发生变化时采取的操作
对于tags标记执行的时候可能会调用多次,就很不方便,这个时候就需要触发器了。
比如:执行了更新配置文件操作,那么肯定需要重启,这时候又要执行重启的tags标记,就很麻烦,也容易忘记。这时候触发器就可以帮助了:在执行了一个配置了触发器的tags标记后,后面的tags标记会一起执行。
语法:触发器与tasks同级, 触发与tags同级
---
- hosts:
remote_user:root
tasks:
......
- file模块1
tags: 标记名
notify:#触发器
- reload #触发器要触发的名字
handlers: #触发
- name: reload #触发名字
service模块2
- 修改配置文件,然后触发重启
[root@ansible ~]# vim httpd1.yaml
---
- hosts: web1 #主机组
remote_user: root #使用账户
tasks:
- name: Ensure the default Apache port is 8080
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: '^Listen '
insertafter: '^#Listen '
line: Listen 80
tags: duankou
notify: #触发器
- reload_test #触发的名字
- name: copy文件到主机
copy:
src: /root/index.html #源端文件
dest: /var/www/html/index.html #目标地址文件
owner: root #文件权限属性
group: root #属于组
mode: 644
tags: index
handlers: #触发
- name: reload_test #触发名字
service:
name: httpd
state: restarted
tags: restart
- 执行
##执行yaml文件,然后指定tags名字。因为tags配置了触发器,那么只要执行了这个tags,就会触发下一步操作。
[root@ansible ~]# ansible-playbook httpd1.yaml -t duankou
PLAY [web1] ********************************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************************
ok: [web1]
TASK [Ensure the default Apache port is 8080] **********************************************************************************************************************
changed: [web1]
RUNNING HANDLER [reload_test] **************************************************************************************************************************************
changed: [web1]
PLAY RECAP *********************************************************************************************************************************************************
web1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 验证
[root@ansible ~]# curl web1:80
hello word !!!!
ansible test !!!!!
测试 TAGS!!!!!!!!!!!!!!!!!!!!!!
- 注意事项
notify调用的必须是handler段的name定义的字符串,名称必须一致
多个task触发同一个notify的时候,同一个服务只会触发一次 notify可以触发多个条件(比如你重启了httpd,后面还有一个service模块对httpd执行重启,就不会触发了,只会执行一次。)
handler有一个标记,记录着是否被触发,触发一次和触发十次也都是被触发了
触发原理:1. 首先执行tasks里面所有任务,2.handler里面只标记一个被触发,3.从handler拿到被触发的任务列表后,4.再执行被触发的任务,5.发现被触发后,就不触发
结合vars可以写出一般的服务管理脚本了
条件判断
一:when
在有些时候需要再满足特定的条件后再触发某一项操作,或者再特定的条件下终止某个行为,这个时候就需要条件判断语句,when
就是解决问题的最佳选项
语法:与模块位置一样
tasks:
- name:
yum:
......
when:
##示例,先载入模块,然后做判断。如果为true就安装,如果为false就不执行
---
- name: Install VIM
hosts: all
tasks:
- name: Install VIM via yum
yum: name=vim-enhanced state=installed
when: ansible_os_family == 'RedHat'
- name: Install VIM via apt
apt: name=vim state=installed
when: ansible_os_family == 'Debian'
二:register
有时候我们还需要更复杂的例子,如判断前一个命令的执行结果才去处理后面的操作,这时候就需要register
模块来保存前一个命令的返回状态和结果和输出等,在后面进行调用
语法:
- command: test command
register: result
- command: run command
when: result
例子:
对于服务器的CPU使用率做一个判断,如果符合要求,然后在执行操作。
1. 编写playbook
---
- hosts: web
remote_user: root #远程用户
tasks:
- name: 获取系统负载
shell: uptime | awk '{printf ("%.2f",$(NF-2))}'
register: result #保存shell命令执行结果。保存到本机上
- name: 使用service操作服务
service:
name: httpd
state: stopped
when: result.stdout|float > 0.7 #使用result的一个对象集合,调用stdout(输出)来和0.7做判断,stdout是字符串,
##使用float过滤器把字符变成浮点数,这样才能和0.7做判断是否大于小于
2. 执行playbook
[root@ansible ~]# ansible-playbook apache-cpu.yaml
PLAY [web] **********************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************
ok: [web1]
ok: [web2]
TASK [获取系统负载] *******************************************************************************************************************************************
changed: [web2]
changed: [web1]
TASK [使用service操作服务] ************************************************************************************************************************************
skipping: [web1]
skipping: [web2]
PLAY RECAP **********************************************************************************************************************************************
web1 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
web2 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
从输出结果得知停止服务被跳过了skipping,是因为判断不成立,cpu负载不大于0.7所有不执行。
3. 通过执行命令把其中一台系统负载升高
[root@web1 ~]# awk 'BEGIN{while(1){}}' &
[root@web1 ~]# uptime
00:33:26 up 8:40, 2 users, load average: 0.74, 0.25, 0.12
4. 再次执行playbook
[root@ansible ~]# ansible-playbook apache-cpu.yaml
PLAY [web] **********************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************
ok: [web1]
ok: [web2]
TASK [获取系统负载] *******************************************************************************************************************************************
changed: [web1]
changed: [web2]
TASK [使用service操作服务] ************************************************************************************************************************************
skipping: [web2]
changed: [web1]
PLAY RECAP **********************************************************************************************************************************************
web1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
发现web2机器还是被略过了,web1执行成功了。
三:with_items
with_items
是playbook标准循环,可以用于迭代一个列表或字典,通过{{ item }}获取每次都迭代的值
语法:例如创建多个用户
---
- hosts: web1
remote_user: root
tasks:
- name: add user
user: group=wheel password={{'123456'| password_hash('sha512')}} name = {{item}}
with_items: ["aa","bb","cc","dd"]
示例:创建多个用户,同一个密码
1. 编写playbook
---
- hosts: web
remote_user: root
# vars:
# username: mysql
tasks:
- name: 添加多个用户"{{item}}"
user:
name: "{{item}}"
group: users
password: "{{'1234'|password_hash('sha512')}}"
with_items: #多个用户的语法,
- aa
- bb
- cc
- dd
- ee
#with_items里面有一个item变量会去遍历with_items里面的所有值
#首先item变量会去with_items里面拿值
#拿到值后就去执行user模块
#然后user模块执行完成后
#item又回去拿值,如此循环
#有多少值就拿多少次,
2. 执行playbook文件
[root@ansible ~]# ansible-playbook users-items.yaml
PLAY [web] **********************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************
ok: [web2]
ok: [web1]
TASK [添加多个用户"{{item}}"] *********************************************************************************************************************************
changed: [web2] => (item=aa)
changed: [web1] => (item=aa)
changed: [web1] => (item=bb)
changed: [web2] => (item=bb)
changed: [web2] => (item=cc)
changed: [web1] => (item=cc)
changed: [web1] => (item=dd)
changed: [web2] => (item=dd)
changed: [web2] => (item=ee)
changed: [web1] => (item=ee)
PLAY RECAP **********************************************************************************************************************************************
web1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3. 验证
[root@ansible ~]# ansible web -m shell -a 'cat /etc/shadow'
web2 | CHANGED | rc=0 >>
aa:$6$Cmfw907O0GyoOcxx$UtruicduEHWUSYPc3Usw4JzZiaI4B73r6n/Atz4uBCds/noDWQ1L6AqojgsT2UB5VFrrIugWXaNNDJEvAUAwb1:19536:0:99999:7:::
bb:$6$2LLWk6/NaYguVGm7$Xq8h9q39XMSZq65pBbDNJMaZU0NF2tpHqpcWOnTKuBNqPZG2d0ecgxDEctC22OGr5SkfF1u9XXBuNPm1cmTDK0:19536:0:99999:7:::
cc:$6$xRx6TdCI4hhBOFeh$dYs5ydtzonsUkzjbgOw8NZNQqr.VBw2nezp.Zf/O6jzsIgn9ZXKWbPEzK.yvkFoF002gZYPhmQHg8HzQ4cftn0:19536:0:99999:7:::
dd:$6$vWPO0moe680/FE9D$EW4ZLsvHZJWUA6O3ITctBVBe0L5w0nJJmNkC/1MTZ88bdAnOfGEqqqn2PJ8fFj0kKDRBjT63rhbVCNemCBLB21:19536:0:99999:7:::
ee:$6$FrpMUoOq1pjUYbud$FiUNTf/u5fQnSwsGdW3/.56MpxTAny8KUJFAHA9krdip61RsfTPWwqfoxhNd06Tbo04qRVH4p75AggpjKQRnD.:19536:0:99999:7:::
web1 | CHANGED | rc=0 >>
aa:$6$/vNVhvGbhhcNSxkI$i609mMOoGBJKI6tynjliXBwlUVHUCxckK6cuelmvFyUqDWNw4Ms1RMjv4zMrDmqaXuXmdFSt5Okl3MYKo1N9G0:19536:0:99999:7:::
bb:$6$Ne5l4.OwlaPyKVJt$hLWYqA5l3uGo6l3tUeRjz9CbJOcPGTZSsGy1HVEeVkDGphbbhsTx3UZbCgtv/IRo4DRs4mk7x8sL0tpy8B1US/:19536:0:99999:7:::
cc:$6$FMNVJhKiKOprSNF9$NqRAPhnSQvr1L1SUg/TcwnnzLfxNJx3TFljsSyY0RBVypspOfPv6UyiJ2flacPb4vxuzVgo/mcRMpHf1HETpM0:19536:0:99999:7:::
dd:$6$1iFZHb4WHryWWy.T$1iIBGPHlgoqdj9axbTHOGVmoHo73Rq9MUCxkdLHXun5rn./G6myauGfkbS9d0mqYowSwYT0V1O8kobXCtHQ3w/:19536:0:99999:7:::
ee:$6$.KEdKm53pOdHzRa/$g2aTkyWCPuxh2nhbdeqCxYRFQYQYV49DUR9gbw0Tsi/wYgwrAo5ZjFqubNsxNj/HnWWiFd1uSMh.Gmik9rUPP.:19536:0:99999:7:::
示例:创建多个用户,不相同的密码,不同组。
1. 编写playbook
---
- hosts: db1
remote_user: root
tasks:
- name: 添加多个用户 "{{item.username}}"
user:
name: "{{item.username}}" #调用item里面username变量。如果只有一个边框 就 - 变量值。如果多个变量写成键值对。
group: "{{item.group}}" #如果没有组,请先创建组,不然会报错
password: "{{item.password|password_hash('sha512')}}"
with_items: #多个用户的语法,
-
username: aaa
group: users
password: "12345"
-
username: bbb
group: bin
password: "54321"
-
username: ccc
group: root
passoword: w1s2d
- {username: 'ddd' , group: 'root' , password: 'sd2d2cc' }
#with_items里面有一个item变量会去遍历with_items里面的所有值
#首先item变量会去with_items里面拿值
#拿到值后就去执行user模块
#然后user模块执行完成后
#item又回去拿值,如此循环
#有多少值就拿多少次,
#有两种格式:一是每行一个变量。二是用花括号里面使用逗号分割变量
2. 执行
[root@ansible ~]# ansible-playbook users-items-db1.yaml
PLAY [db1] **********************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************
ok: [db1]
TASK [添加多个用户 "{{item.username}}"] ***********************************************************************************************************************
changed: [db1] => (item={u'username': u'aaa', u'password': u'12345', u'group': u'users'})
changed: [db1] => (item={u'username': u'bbb', u'password': u'54321', u'group': u'bin'})
changed: [db1] => (item={u'username': u'ccc', u'password': u'w1s2d', u'group': u'root'})
changed: [db1] => (item={u'username': u'ddd', u'password': u'sd2d2cc', u'group': u'root'})
PLAY RECAP **********************************************************************************************************************************************
db1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
##看到两种格式都被解析了。
3. 验证
[root@ansible ~]# ansible db1 -m shell -a 'cat /etc/shadow'
db1 | CHANGED | rc=0 >>
root:$6$7HgcoH8OcgF6uBFC$EyaWHs8.kpQFp8M3gIoyk37sHCvdx8aG4gkspORjHh2WEIqa38kgWa3E/KkNdAJU.RW1SLzYwYedZYgDUBQ0V1::0:99999:7:::
aaa:$6$ENUmS7k7I/de3Y7E$7KHFIMKo83Gkd8SH0bL7CB7I0OEVEdCPLqX4mK1omOAt99yIQTG5EwJKif68feYFdWkdLonTQqnHdZNkJhlva1:19536:0:99999:7:::
bbb:$6$EF050.pSw5nkmziR$Gb4xA76lj0SuoW0ThVQX7/2oPxtTkUYlz2qzbGrfnfKVg2vbu8gz9tBrmfvw1S7xPLCq8zXwbfOy4CLowwk22.:19536:0:99999:7:::
ccc:$6$b32tdeIeNHlW4AEE$Kn0P7TwdONN0zzhODdtKDcgds.MIJvvRs.P6I6PMP6IraJ1EYuuOB0JMbcEPNGq6ilw3MEh06N7qPzE8vtPty/:19536:0:99999:7:::
ddd:$6$zl0rU3qhT9ejIVYq$xSwavPXLOhRGPvP5RzQnjoT.6Zj4dhiFqVKMA0mLZkFiJ04BVhFBq365IsQCwrzAdB2sK/mbuDGgoN5NRW60v0:19536:0:99999:7:::
四:include
在编写playbook的时候随着项目越来越大,playbook越来越复杂,修改也麻烦。这时候可以把一些play、task或者handler放到其他文件中,通过include指令包含进来是一个不错的选择
语法:
tasks:
- include: tasks/setup.yaml
- include: tasks/users.yaml user=aaa #users.yaml中可以通过{{user}}来使用这些变量
handlers:
- include: handlers/handlers.yaml
五:roles
roles像是加强版的include,它可以映入一个项目的文件和目录
一般所需的目录层级有
- vars: 变量层
- tasks: 任务层
- hendlers: 触发条件
- files: 文件
- template: 模板
- default: 默认,优先级最低
调试debug
一:使用debug模式返回出被调用的参数及变量所存在的信息
示例
- 编写playbook
---
- hosts: web
remote_user: root #远程用户
tasks:
- name: 获取系统负载
shell: uptime | awk '{printf ("%.2f",$(NF-2))}'
register: result #保存shell命令执行结果。保存到本机上
- name: 使用service操作服务
service:
name: httpd
state: stopped
when: result.stdout|float > 0.7
- name: show debug info #需要执行的任务名字
debug: var=result #result是变量名字
- 运行检测命令
TASK [show debug info] **********************************************************************************************************************************
ok: [web1] => {
"result": {
"changed": true,
"cmd": "uptime | awk '{printf (\"%.2f\",$(NF-2))}'",
"delta": "0:00:00.004480",
"end": "2023-06-29 01:37:56.087218",
"failed": false,
"rc": 0, #这就是默认输出的值,相当于 echo $?
"start": "2023-06-29 01:37:56.082738",
"stderr": "",
"stderr_lines": [],
"stdout": "0.00",
"stdout_lines": [
"0.00"
]
}
}
ok: [web2] => {
"result": {
"changed": true,
"cmd": "uptime | awk '{printf (\"%.2f\",$(NF-2))}'",
"delta": "0:00:00.004912",
"end": "2023-06-29 01:37:40.195860",
"failed": false,
"rc": 0,
"start": "2023-06-29 01:37:40.190948",
"stderr": "",
"stderr_lines": [],
"stdout": "0.00",
"stdout_lines": [
"0.00"
]
}
}
看到result返回的是一个集合,stdout
就会返回的cpu的负载,然后使用调用result.stdout
的语法,把结果返回,再用过滤器float
进行过滤出我们需要的结果
二:检测语法(可能有检测不准的问题)
##语法格式
ansible-playbook --syntax-check playbook.yaml
##需要在playbook.yaml中加入以下语句
- name: show debug info
debug: var=result #result变量名
示例:
##语法正确输出空白
[root@ansible ~]# ansible-playbook --syntax-check apache-cpu.yaml
playbook: apache-cpu.yaml
##语法错误输出错误的位置
[root@ansible ~]# ansible-playbook --syntax-check apache-cpu.yaml
ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
JSON: No JSON object could be decoded
Syntax Error while loading YAML.
did not find expected key
The error appears to be in '/root/apache-cpu.yaml': line 12, column 9, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
state: stopped
when: result.stdout|float > 0.7
^ here
三:测试运行(只会模拟运行,也不怎么准,和业务逻辑相关)
ansible-playbook -C playbook.yaml
四:检测脚本(执行脚本看查看影响的主机和任务,线上环境执行之前必须检查)
- 显示受到影响的主机 --list-hosts
- 显示工作的task --list-tasks
- 显示将要运行的tag --list-tags
示例
[root@ansible ~]# ansible-playbook apache-cpu.yaml --list-hosts
playbook: apache-cpu.yaml
play #1 (web): web TAGS: []
pattern: [u'web']
hosts (2):
web2
web1
[root@ansible ~]# ansible-playbook apache-cpu.yaml --list-tasks
playbook: apache-cpu.yaml
play #1 (web): web TAGS: []
tasks:
获取系统负载 TAGS: []
使用service操作服务 TAGS: []
show debug info TAGS: []