ansible自动化运维(5)

本文介绍了如何在Ansible中处理任务失败,包括忽略错误、强制执行处理程序以及使用`failed_when`和`changed_when`关键字控制任务状态。此外,还详细讲解了文件模块的使用,如`blockinfile`, `copy`, `fetch`, `file`, `lineinfile`等,并展示了如何使用Jinja2模板动态构建和部署文件。文章最后探讨了管理大型项目时的主机选择、动态清单、并行配置、滚动更新以及包含和导入文件的策略。" 125499998,11446017,今日头条小程序:新特性与未来发展趋势,"['小程序', '微信小程序', '内容电商', '支付', 'Android']

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

##处理任务失败

通常playbook遇到错误会中止执行,但是有时我们想要失败时也继续执行

##忽略任务失败
关键字:ignore_errors
#举例
[root@workstationcode]#cat ignore.yml

---
- name: Test
  hosts: webservers
  tasks:
    - name: Install package
      yum:
        name: k8s
        state: latest
      ignore_errors: yes


#执行

[root@workstationcode]#ansible-playbook ignore.yml
...
TASK[Installpackage]*********************************************************
fatal:[servera.lab.example.com]:FAILED!=>{"changed":false,"failures":["No
packagek8savailable."],"msg":"Failedtoinstallsomeofthespecifiedpackages",
"rc":1,"results":[]}
...ignoring

##任务失败后强制执行处理程序
通常任务失败,play会中止,那么收到play中之前任务通知的处理程序将不会运行,如果要运
行,需要使用关键字:force_handlers: yes
#举例
[root@workstationcode]#cat force.yml

---
- hosts: webservers
  force_handlers: yes
  tasks:
    - name: always notify
      command: /bin/true
      notify: restart apache
    - name: Fail task
      yum:
        name: k8s
        state: latest
  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted

'处理程序会在任务报告changed结果时获得通知,ok或者failed都不会'
##指定任务失败条件
关键字:failed_when

tasks:
  - name: Run Script
    shell: /usr/local/bin/user.sh
    register: command_result
    failed_when: "'failure'incommand_result.stdout"

#fail模块可以实现此效果

tasks:
  - name: Run Script
    shell: /usr/local/bin/user.sh
    register:command_result
    ignore_error: yes
  - name: Report failure
    fail:
      msg: "Authenticationfailure"            #fail模块可以提供明确消息
    when: "'failure'incommand_result.stdout"

##指定任务何时报告"Changed"结果
关键字:changed_when

#
- name: get time
  shell: date
  changed_when: false

##ansible块和错误处理
三种关键字:

block:定义要运行的主要任务
rescue:定义要在block子句中定义的任务失败时运行的任务
always:定义时中独立运行的任务


#练习:
故意制造错误

[root@workstationcode]#cat error.yml

---
- name: Task Failure
  hosts: webservers
  vars:
    web_pkg: http
    db_pkg: mariadb-server
    db_service: mariadb
  tasks:
    - name: Install {{ web_pkg }} packages
      yum:
        name: "{{ web_pkg }}"
        state: present
    - name: Install {{ db_pkg }} packages
      yum:
        name: "{{ db_pkg }}"
        state: present

运行报错
[root@workstationcode]#ansible-playbook error.yml

...
TASK[Installhttppackages]***************************************************
fatal:[servera.lab.example.com]:FAILED!=>{"changed":false,"failures":["No
packagehttpavailable."],"msg":"Failedtoinstallsomeofthespecifiedpackages",
"rc":1,"results":[]}

第一个任务失败,第二个任务不运行
#添加忽略关键字
[root@workstationcode]#vim error.yml
...
13ignore_errors:yes

---
- name: Task Failure
  hosts: webservers
  vars:
    web_pkg: http
    db_pkg: mariadb-server
    db_service: mariadb
  tasks:
    - name: Install {{ web_pkg }} packages
      yum:
        name: "{{ web_pkg }}"
        state: present
      ignore_errors: yes
    - name: Install {{ db_pkg }} packages
      yum:
        name: "{{ db_pkg }}"
        state: present

#使用block、rescue、always将任务分开
[root@workstationcode]#cat error.yml

---
- name: Task Failure
  hosts: webservers
  vars:
    web_pkg: http
    db_pkg: mariadb-server
    db_service: mariadb
  tasks:
    - name: Setup Web
      block:
        - name: Install {{ web_pkg }} packages
          yum:
            name: "{{ web_pkg }}"
            state: present
      rescue:
        - name: Install {{ db_pkg }} packages
          yum:
            name: "{{ db_pkg }}"
            state: present
      always:
        - name: Start {{ db_service }} service
          service:
            name: "{{ db_service }}"
            state: started

执行结果有报错,但是mariadb正常启动
#再修改,将http的包改为正确
[root@workstationcode]#vim error.yml
5 web_pkg: httpd

---
- name: Task Failure
  hosts: webservers
  vars:
    web_pkg: httpd
    db_pkg: mariadb-server
    db_service: mariadb
  tasks:
    - name: Setup Web
      block:
        - name: Install {{ web_pkg }} packages
          yum:
            name: "{{ web_pkg }}"
            state: present
      rescue:
        - name: Install {{ db_pkg }} packages
          yum:
            name: "{{ db_pkg }}"
            state: present
      always:
        - name: Start {{ db_service }} service
          service:
            name: "{{ db_service }}"
            state: started


发现rescue部分被忽略,但是always总会执行
#控制'changed'条件
[root@workstationcode]#cat error.yml

---
- name: Task Failure
  hosts: webservers
  vars:
    web_pkg: httpd
    db_pkg: mariadb-server
    db_service: mariadb
  tasks:
    - name: Check Time                  #添加查看时间任务
      command: date
      register: command_result
    - name: Print Time
      debug:
        var: command_result.stdout
    - name: Setup Web
      block:
        - name: Install {{ web_pkg }} packages
          yum:
            name: "{{ web_pkg }}"
            state: present
      rescue:
        - name: Install {{ db_pkg }} packages
          yum:
            name: "{{ db_pkg }}"
            state: present
      always:
        - name: Start {{ db_service }} service
          service:
            name: "{{ db_service }}"
            state: started

运行发现
check time任务始终是changed
TASK[CheckTime]**************************************************************
changed:[servera.lab.example.com]
因为任务没有更改受管主机,所以不应该每次都是changed

修改文件
[root@workstationcode]#vim error.yml
12 changed_when: false

---
- name: Task Failure
  hosts: webservers
  vars:
    web_pkg: httpd
    db_pkg: mariadb-server
    db_service: mariadb
  tasks:
    - name: Check Time                            #添加查看时间任务
      command: date      
      register: command_result
      changed_when: false
    - name: Print Time
      debug:
        var: command_result.stdout
    - name: Setup Web
      block:
        - name: Install {{ web_pkg }} packages
          yum:
            name: "{{ web_pkg }}"
            state: present
      rescue:
        - name: Install {{ db_pkg }} packages
          yum:
            name: "{{ db_pkg }}"
            state: present
      always:
        - name: Start {{ db_service }} service
          service:
            name: "{{ db_service }}"
            state: started

再次运行,变为ok
#使用failed_when关键字
[root@workstationcode]#vim error.yml
22 failed_when: web_pkg=="httpd"

---
- name: Task Failure
  hosts: webservers
  vars:
    web_pkg: httpd
    db_pkg: mariadb-server
    db_service: mariadb
  tasks:
    - name: Check Time                                #添加查看时间任务
      command: date      
      register: command_result
      changed_when: false
    - name: Print Time
      debug:
        var: command_result.stdout
    - name: Setup Web
      block:
        - name: Install {{ web_pkg }} packages
          yum:
            name: "{{ web_pkg }}"
            state: present
            failed_when: web_pkg == "httpd"
      rescue:
        - name: Install {{ db_pkg }} packages
          yum:
            name: "{{ db_pkg }}"
            state: present
      always:
        - name: Start {{ db_service }} service
          service:
            name: "{{ db_service }}"
            state: started

运行

[root@workstationcode]#ansible-playbook error.yml
TASK[Installhttpdpackages]**************************************************
fatal:[servera.lab.example.com]:FAILED!=>{"changed":false,
"failed_when_result":true,"msg":"Nothingtodo","rc":0,"results":["Installed:
httpd"]}

有报错,但是其实已经安装了httpd包,failed_when关键字只是改变了任务的执行状态,没有改变任务本身但是失败的状态可以让rescue语句块执行
#总结:

1.循环迭代的方法
2.条件用于仅再符合特定条件时执行任务或play
3.处理程序用法
4.只有任务报告受管主机做了更改,才会通知处理程序
5.处理任务失败,即使成功的任务也可以标记为失败
6.块用于将任务分组为单元,通过任务是否成功来确定执行其他任务与否

##########在受管节点上创建文件或目录##########
######修改文件并将其复制到主机######
##常用文件模块
blockinfile#将文本块添加到现有文件
copy#
将文件复制到受管主机
fetch#从受管主机拷贝文件到控制节点
file#设置文件属性
lineinfile#确保特定行位于某个文件
stat#检索文件状态信息
synchronize#rsync命令的一个打包程序

##file模块处理文件,如果不存在就新建
[root@workstationfile]#cat file.yml

---
- name: Test
  hosts: webservers
  tasks:
    - name: Touch a file
      file:
        path: /root/file
        owner: student
        group: student
        mode: 0640
        state: touch

#运行结果

[root@servera~]#ll file
-rw-r-----.1studentstudent0Apr610:06file

##修改文件属性
[root@workstationfile]#cat file.yml

---
- name: Test
  hosts: webservers
  tasks:
    - name: Touch a file
      file:
        path: /root/file
        owner: student
        group: student
        mode: 0640
        state: touch
    - name: Set SElinux
      file:
        path: /root/file
        setype: samba_share_t

#运行结果

[root@servera~]#ll -Z file
-rw-r-----.1studentstudentunconfined_u:object_r:samba_share_t:s00Apr6
10:12file

永久更改
[root@workstationfile]#cat file.yml

---
- name: Test
  hosts: webservers
  tasks:
    - name: Touch a file
      file:
        path: /root/file
        owner: student
        group: student
        mode: 0640
        state: touch
    - name: Set SElinux
      file:
        path: /root/file
        setype: samba_share_t
    - name: Set SElinux
      sefcontext:
        target: /root/file
        setype: samba_share_t
        state: present

##在受管主机上复制和编辑文件
block in file

copy

fetch

line in file
##从受管主机中删除文件

- name: Delete file
  file:
    dest: /root/file
    state: absent           #absent即删除

##检测受管主机上的文件状态
检测文件的MD5校验和

- name: Verify the status
  stat:
    path: /root/file
    checksum_algorithm: md5
  register: result
- debug:
    msg: "The check sum is {{ result.stat.checksum }}"

运行(上面代码添加到file.yml最后)

TASK[debug]*******************************************************************
ok:[servera.lab.example.com]=>{
"msg":"Thechecksumisd41d8cd98f00b204e9800998ecf8427e"
}

##同步控制节点和受管主机之间的文件

- name: sync file
  synchronize:
    src: file
    dest: /root/file


######使用jinja2模板部署自定义文件######

构建出模板可以更方便的管理文件

{% EXPR %}                                   #表达式或者逻辑

{{ EXPR }}                                       #最终向用户输出表达式或结果
{# COMMENT #}                           #注释

##构建jinja2模板

jinja2模板由多个元素组成:数据、变量、表达式
模板中使用的变量可以在playbook的vars中指定
模板中所有的值都使用变量方式,将来会被受管主机对应的值替代

如:/etc/ssh/sshd_config文件
Port 22 ==> Port  {{ ssh_port }}
PermitRootLoginyes  ==>  {{ root_allowed }}
##部署jinja2模板

tasks:
  - name: template
    template:
      src: /root/j2-template.j2
      dest: /root/dest-config-file.txt

##控制结构
#使用循环
jinja2使用for语句提供循环:
#1.

{% for user in users %}
        {{ user }}                  #user变量将遍历users
{% endfor %}

#2.

{% for myhost in groups['myhosts'] %}          #列出myhosts组中所有主机
        {{ myhosts }}
{% endfor %}

#使用条件句

{% if finished %}               #只有此条件为真,才会将result变量的值放入文件
       {{ result }}
{% endif %}

jinja2的循环和条件只能在模板中使用,不能在playbook中使用
##变量过滤器

{{ output | to_json }}                    #以json格式输出

{{ output | to_yaml }}
{{ output | from_json }}               #对json格式字符串进行解析
{{ output | from_yaml }}

##练习
[root@workstationfile-template]#cat ansible.cfg
[defaults]
inventory=./inventory
[root@workstationfile-template]#cat inventory
[webservers]
servera.lab.example.com
[workstations]
workstation.lab.example.com
[root@workstationfile-template]#cat motd.j2

This is the system {{ ansible_facts['fqdn'] }}
This is a {{ ansible_facts['distribution'] }} version 
{{ ansible_facts['distribution_version'] }} system.
Systemowner is {{ system_owner }}.

[root@workstationfile-template]#cat motd.yml

---
- name: configure SOE
  hosts: all
  remote_user: student
  become: true
  vars:
    - system_owner: wsp439@sina.com
  tasks:
    - name: configure /etc/motd
      template:
        src: motd.j2
        dest: /etc/motd
        owner: root
        group: root
        mode: 0644

总结:

1.file模块库包含创建、复制、编辑、修改等权限和其他属性
2.使用jinja2模板动态构建文件来部署
3.jinja2模板由两个元素构成:变量和表达式,在使用jinja2模板时,他们被替换为值
4.通过jinja2过滤器,模板表达式可以从一种数据格式转换为另一种

##########管理大项目##########
######利用主机模式选择主机######
#使用通配符匹配多个主机

- hosts: '*'
- hosts: '*.example.com'
- hosts: '172.25.254.*'

#通过列表匹配主机或主机组

- hosts: www1.example.com,www2.example.com,172.25.254.250
- hosts: webservers,westos
也可以将通配符和列表等一起使用
- hosts: webservers,&westos                          #即属于webserver组,也属于westos组
- hosts: westos,!servera.lab.example.com      #匹配westos组中所有主机,但是servera.lab.example.com除外
- hosts: all,!servera.lab.example.com              #所有主机除了servera.lab.example.com

######管理动态清单######
github有很多动态清单脚本
##编写动态清单程序
将INI格式的清单转换为JSON格式
[root@workstationhost]#cat inventory
workstation.lab.example.com
[webservers]
web1.lab.example.com
web2.lab.example.com
[dbservers]
db1.example.com
db2.example.com
转换
[root@workstationhost]#ansible-inventory -i inventory --list
######配置并行######
##使用forks在ansible中配置并行
ansible最大同时连接数由ansible配置文件中forks参数控制

[root@workstation~]#grep forks /etc/ansible/ansible.cfg
#forks         =5                #默认是5
[root@workstation~]#ansible-config dump | grep -i forks
DEFAULT_FORKS(default) = 5
可以在命令行使用-f或者--forks参数来指定并行数
##管理滚动更新
如果更新发生在负载均衡服务器,更新完成会重启,可能导致后端所有web服务器停止服务,
可以使用serial关键字来分批运行
例如:

---
- name: Rolling update
  hosts: webservers
  serial: 2
  tasks:
    - name: Install apache
      yum:
        name: httpd
        state: latest
      notify:restartapache
  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted

参数还有一个优点:在更新时如果出现问题,那么在前2台发生问题是playbook就会停止运行,后面的服务器不会执行,那么也就保证了服务的高可用性
######包含和导入文件######
大型playbook管理起来比较复杂,可以用模块化的方式管理
两种方法:包含、导入
##导入playbook
例1:

- name: configure webserver
  import_playbook: web.yml

例2:

- name: Play1
  hosts: localhost
  tasks:
    - debug:
        msg: Play1
    - name: Import Playbook
      import_playbook: play2.yml

##导入和包含任务的playbook
#一个只有任务的playbook
[root@workstationdemo]#cat tasks.yml

- name: Install apache
  yum:
    name: httpd
    state: latest
- name: Start Apache
  service:
    name: httpd
    state: started

#导入任务

---
- name: Installweb
  hosts: webservers
  tasks:
    - import_tasks: tasks.yml

'使用导入时,when等条件语句应用于导入的每个任务;循环不能作用于导入的任务'
#包含任务

---
- name: Install web
  hosts: webservers
  tasks:
    - include_tasks: tasks.yml

##为外部play和任务定义变量提高复用性一个安装软件包和配置开机启动的任务

---
- name: Install the {{ packages }}
  yum:
    name: "{{ packages }}"
    state: latest
- name: Start the {{ service }}
  service:
    name: "{{ service }}"
    enabled: true
    state: started

可以用于导入

tasks:
  - name: Import task
      import_tasks: task.yml
vars:
  package: httpd
  service: httpd

#管理大项目综合实验:
[root@workstationproject]#cat ansible.cfg
[defaults]
inventory=./inventory
[root@workstationproject]#cat inventory
servera.lab.example.com
serverb.lab.example.com
serverc.lab.example.com
[root@workstationproject]#ansible server*.lab.example.com --list-hosts
目录结构
[root@workstationproject]#tree.
.
├──ansible.cfg
├──files
│└──example.conf
├──inventory
├──playbook.yml
└──tasks
├──firewall_tasks.yml
├──install_and_enabled.yml
└──web_tasks.yml
#相同的模块:安装包
[root@workstationtasks]#cat install_and_enabled.yml

---
- name: Install {{ packages }}
  yum:
    name: "{{ packages }}"
    state: latest
- name: Enable and start {{ service }}
  service:
    name: "{{ service }}"
    enabled: true
    state: started

#apache配置
[root@workstationtasks]#cat web_tasks.yml

---
- name: Install and start httpd
  import_tasks: install_and_enabled.yml
  vars:
    packages: httpd
    service: httpd
- name: Configure apache
  copy:
    src: files/example.conf
    dest: /etc/httpd/conf.d/example.conf
    owner: root
    group: root
    mode: 0644
notify:
  - restart httpd

#firewall配置
[root@workstationtasks]#cat firewall_tasks.yml

---
- name: Install and start firewalld
  import_tasks: install_and_enabled.yml
  vars:
    packages: firewalld
    service: firewalld
- name: Firewall permit apache
  firewalld:
    service: http
    immediate: true
    permanent: true
    state: enabled

#主playbook
[root@workstationproject]#cat playbook.yml

---
- name: Install and Configure webservice
  hosts: server*.lab.example.com
  serial: 2
  tasks:
    - name: Import web_tasks.yml
      import_tasks: tasks/web_tasks.yml
    - name: Import the firewall_tasks.yml
      import_tasks: tasks/firewall_tasks.yml
  handlers:
    - name: restart httpd
      service:
        name: httpd
        state: restarted


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值