Ansible入门教程----playbook基础(四)

文章介绍了如何在Ansible中使用过滤器加密密码,通过变量和JSON传递参数,以及如何处理shell命令错误。强调了避免使用shell模块,而应使用内置模块以减少错误。此外,文章讨论了tags标记的使用,如何通过它们来分组任务以及如何使用触发器(handlers)确保服务在配置更改后自动重启。还讲解了条件判断(when)和注册(register)的用法,以及如何利用with_items进行循环操作。最后提到了include和roles的组织结构,以及debug调试技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章引导

前言
示例
错误处理
tags标记
触发器handlers
条件判断
调试debug

前言

上一章节说到,用ansible-playbook执行yaml文件来到达某一种目的。这章来讲过滤器。

示例

一:使用过滤器给密码加密

  1. 使用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:::
##找到问题所在,发现影子文件应该把密码存为加密的方式保存,在这里却显示了明文密码,那么就发现了问题所在,所有登录不上。
  1. 使用过滤器,把密码变为加密后的参数,然后再写入影子文件中,密码加密方式为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格式)

  1. 通过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.
  1. 通过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命令与模块对比

  1. 编写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参数来解决

  1. 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
  1. 编写一个更新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
  1. 修改配置文件,然后触发重启
[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
  1. 执行
##执行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
  1. 验证
[root@ansible ~]# curl web1:80

hello word !!!!
ansible test !!!!!
测试 TAGS!!!!!!!!!!!!!!!!!!!!!!
  1. 注意事项

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模式返回出被调用的参数及变量所存在的信息

示例

  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
     - name: show debug info  #需要执行的任务名字
       debug: var=result     #result是变量名字
  1. 运行检测命令
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: []
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值