Ansible流程控制

Ansible流程控制

playbook条件语句

不管是shell还是各大编程语言中,流程控制,条件判断这些都是必不可少的,在我们使用Ansible的过程中,条件判断的使用频率极其高。

例如:

1.我们使用不同的系统的时候,可以通过判断系统来对软件包进行安装。

2.在nfs和rsync安装过程中,客户端服务器不需要推送配置文件,之前我们都是写多个play,会影响效率。

3.我们在源码安装nginx的时候,执行第二遍就无法执行了,此时我们就可以进行判断是否安装过。

官方语法

 when: ansible_facts['hostname'] == 'web01'

判断多条件列表

[root@m01 ~/rsync]$ vim rsync.yml 
# 因为有了判断,所以这里可以直接选择所有主机
- hosts: all
  tasks:
    - name: Install rsync server
      yum:
        name: rsync
        state: present
      # when语句可以判断安装在哪写机器上,这里代表backup和nfs(用列表就是和的意思)
      when: 
        - ansible_hostname == "backup"
        - ansible_hostname == "nfs"

判断分组

# 判断系统是sentos6或是debian7的(and:和  or:或)
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or 
      (ansible_distribution == "Debian" and ansible_distribution_major_version == "7")

判断条件运算

# 取到major的值后,通过管道交给int转化为整形进行判断,这里是大于等于1
ansible_python['version']['major']|int >=1

# 查看主机所有内置变量
[root@m01 ~]$ ansible web01 -m setup
"ansible_python": {
            "executable": "/usr/bin/python", 
            "has_sslcontext": true, 
            "type": "CPython", 
            "version": {
                "major": 2, 
                "micro": 5, 
                "minor": 7, 
                "releaselevel": "final", 
                "serial": 0
            }

#######################################################################################################################
# 官方示例
tasks:  
  - shell: echo "only on Red Hat 6, derivatives, and later"    
  when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb'] ['major_release']|int >= 6

模糊匹配

- hosts: all  
  tasks:    
    - name: Install Nginx      
      yum:        
        name: nginx        
        state: present
      # 给以web开头的主机名安装nginx
      when: ansible_hostname is match 'web*'

条件语句判断实战:rsync

- hosts: all  
  tasks:    
    - name: Install Rsync Server      
      yum:        
        name: rsync
      # 客户端服务端都需要安装
      when: ansible_hostname == 'nfs' or  ansible_hostname == 'backup'
 
    - name: rsyncd conf
      copy:
        src: /root/rsync/rsyncd.conf
        dest: /etc/rsyncd.conf
      # 推送配置文件只有backup需要
      when: ansible_hostname == "backup"
      
     - name: Create Rsync Passwd File      
       copy:        
         content: rsync_backup:123        
         dest: /etc/rsync.passwd        
         mode: 0600
       # 服务端密码文件只有backup需要
       when: ansible_hostname == 'backup'
   
     - name: Create nfs Passwd File      
       copy:        
         content: '123'        
         dest: /etc/rsync.passwd        
         mode: 0600
      # 客户端密码文件配给nfs   
       when: ansible_hostname == 'nfs'
   
    - name: Start rsync server
      service:
        name: rsyncd
        state: started
      # 启动rsync服务也只有backup需要
      when: ansible_hostname == "backup" 

playbook循环语句

循环语法

[root@m01 ~/rsync]$ vim test.yml
- hosts: web_group
  tasks:
    - name: Install all
      yum:
        # 调用循环
        name: "{{ item }}"
        state: present
      # 定义循环,先安装rsync,再安装nginx
      with_items:
        - rsync
        - nginx

    - name: start all
      service:
        name: "{{ item }}"
        state: started
      # 定义循环,先启动rsync,再启动nginx
      with_items:
        - rsyncd
        - nginx

字典循环

创建用户

- hosts: all  
  tasks:    
    - name: Create Group      
      group:
        # 创建组
        name: "{{ item }}"  
      # 利用字典循环定义多个组名
      with_items:        
        - linux        
        - av
        
    - name: Create User      
      user:
        # 创建多个用户
        name: "{{ item.name }}"
        # 给多个用户指定不同的组
        group: "{{ item.group }}" 
      # 利用字典循环定义多个用户名及组名
      with_items:        
        - {name: "zls",group: "linux"}        
        - {name: "cls",group: "av"}

推送文件

    - name: copy conf and code
      copy:
        # 调用字典循环,这里相当于推送nginx.conf配置文件,再推送blog.conf站点文件
        src: "{{ item.src }}"
        # 循环接收文件
        dest: "{{ item.dest }}"
        # 循环设置文件权限
        mode: "{{ item.mode }}"
      # 字典循环,类似于层级变量,在with_items下面定义,这样一循环可以推送多个文件,可以加多个循环变量
      with_items:
        - { src: "/root/ansible/nginx.conf", dest: "/etc/nginx/nginx.conf", mode: "0644" }
        - { src: "/root/ansible/blog.wj.com.conf", dest: "/etc/nginx/conf.d/blog.wj.com.conf", mode: "0644"}
        
#####################################################################################################################################
TASK [copy conf and code] *************************************************************************************************
changed: [web02] => (item={u'dest': u'/etc/nginx/nginx.conf', u'src': u'/root/ansible/nginx.conf', u'mode': u'0644'})
changed: [web01] => (item={u'dest': u'/etc/nginx/nginx.conf', u'src': u'/root/ansible/nginx.conf', u'mode': u'0644'})
ok: [web02] => (item={u'dest': u'/etc/nginx/conf.d/blog.wj.com.conf', u'src': u'/root/ansible/blog.wj.com.conf', u'mode': u'0644'})
ok: [web01] => (item={u'dest': u'/etc/nginx/conf.d/blog.wj.com.conf', u'src': u'/root/ansible/blog.wj.com.conf', u'mode': u'0644'})

playbook handlers

触发器

handler用来执行某些条件下的任务,比如当配置文件发生变化的时候,通过notify触发handler去重启服务。

在saltstack中也有类似的触发器,写法相对Ansible简单,只需要watch,配置文件即可

实践案例

- hosts: web_group   
  tasks:  
    - name: copy conf and code
      copy:
        src: "{{ item.src }}"
        dest: "{{ item.dest }}"
        mode: "{{ item.mode }}"
      with_items:
        - { src: "/root/ansible/nginx.conf", dest: "/etc/nginx/nginx.conf", mode: "0644" }
        - { src: "/root/ansible/blog.wj.com.conf", dest: "/etc/nginx/conf.d/blog.wj.com.conf", mode: "0644"}
      # 还是用上面的playbook,在推送配置文件时,添加触发器,并定义一个名称“Restart nginx”,一旦传输的内容发生变化,就会触发下面的动作
      notify:
        - Restart nginx
  
  # handlers接收触发器反馈的信息并作出动作,注意:必须和tasks在同一层级
  handlers:
    # 指定接收的触发器
    - name: Restart nginx
      # 做出的动作:重启服务
      service:
        name: nginx
        state: restarted

注意:

1.无论多少个task通知了相同的handlers,handlers仅会在所有tasks结束后运行一次。

2.Handlers只有在其所在的任务被执行时,才会被运行;如果一个任务中定义了notify调用Handlers,但是由于条件判断等原因,该任务未被执行,那么Handlers同样不会被执行。

3.Handlers只会在每一个play的末尾运行一次;如果想在一个playbook中间运行Handlers,则需要使用meta模块来实现。例如: -meta: flush_handlers。

4.如果一个play在运行到调用Handlers的语句之前失败了,那么这个Handlers将不会被执行。我们可以使用meta模块的--force-handlers选项来强制执行Handlers,即使Handlers所在的play中途运行失败也能执行。

5.不能使用handlers替代tasks

playbook tags

默认情况下,Ansible在执行一个playbook时,会执行playbook中定义的所有任务,Ansible的标签(tag)功能可以给单独任务甚至整个playbook打上标签,然后利用这些标签来指定要运行playbook中的个别任务,或不执行指定的任务。

打标签的方式

1.对一个task打一个标签

2.对一个task打多个标签

3.对多个task打一个标签

打标签语法

- hosts: web_group
  tasks:
    - name: Install all
      yum:
        name: "{{ item }}"
        state: present
      with_items:
        - rsync
        - nginx

    - name: start all
      service:
        name: "{{ item }}"
        state: restarted
      with_items:
        - rsyncd
        - nginx
      # 给服务启动模块打一个标签,并指定名称
      tags:
        - manager_nginx_server

执行方式

  • -t:执行指定的标签
  • --skip-tags:跳过指定标签
# 只执行指定的标签模块
ansible-playbook rsync.yml -t manager_nginx_server

# 跳过指定标签,执行其他模块
ansible-playbook rsync.yml --skip-tags manager_nginx_server

playbook include - 剧本复用

在之前写playbook的过程中,我们发现,写多个playbook没有办法,一键执行,这样我们还要单个playbook挨个去执行,很鸡肋。所以在playbook中有一个功能,叫做include用来动态调用task任务列表。

微信图片_20210816173332

只调用task:include_tasks

调用整个task文件:include (新版本:import_playbook)

在saltstack中,叫做top file入口文件。

剧本复用实践

# 1.创建一个项目专属目录
[root@m01 ~]$ mkdir /ansible_project
# 2.将不同服务或主机单独分为一个目录
[root@m01 /ansible_project]$ mkdir group_vars			# 主机组变量文件
[root@m01 /ansible_project]$ mkdir host_vars			# 单个主机变量文件
[root@m01 /ansible_project]$ mkdir mariadb				# 数据库相关配置文件和数据库playbook存放目录
[root@m01 /ansible_project]$ mkdir nfs 					# nfs配置文件和nfs的playbook存放目录
[root@m01 /ansible_project]$ mkdir nginx				# nginx相关配置文件和nginx的playbook存放目录
[root@m01 /ansible_project]$ mkdir php					# php相关配置文件和php的playbook存放目录
[root@m01 /ansible_project]$ mkdir rsync				# rsync相关配置文件和backup的playbook存放目录
[root@m01 /ansible_project]$ mkdir sersync				# sersync相关配置文件存放目录
[root@m01 /ansible_project]$ touch lnmp.yml				# 主剧本playbook文件,必须和其他项目目录同级
[root@m01 /ansible_project]$ tree .
├── group_vars
├── host_vars
├── lnmp.yml
├── mariadb
├── nfs
├── nginx
├── php
├── rsync
└── sersync

8 directories, 1 file

####################################################################################################################################
# 在rsync目录下配置各个playbook,直接从- name开始编写即可
## 安装服务的playbook
[root@m01 ansible_project]$ vim rsync/install_rsync.yml 
- name: Install rsync  
  yum:    
    name: 
      - rsync
      - nfs
    state: absent  
  when: ansible_hostname == 'nfs' or ansible_hostname == 'backup'

## 推送rsync配置文件的playbook
[root@m01 ansible_project]$ vim rsync/config_rsync.yml 
- name: Configure Rsync Server  
  copy:    
    src: ./rsyncd.conf    
    dest: /etc/rsyncd.conf
  notify: Restart Rsync			-------------------notify触发器必须在子playbook中,handlers在主playbook中
  when: ansible_hostname == 'backup'

# 启动服务的playbook
[root@m01 ansible_project]$ vim rsync/start_rsync.yml 
- name: Start Rsync  
  service:    
    name: rsyncd    
    state: started    
    enabled: yes  
  when: ansible_hostname == 'backup'

######################################################################################################################################
# 编辑主playbook
## 主playbook中需要- hosts
[root@m01 ansible_project]# cat task.yml 
- hosts: all
  # 在tasks下面直接include各个文件
  tasks:    
    - include_tasks: rsync/install_rsync.yml		------服务安装playbook
    - include_tasks: rsync/config_rsync.yml          ------服务配置文件playbook
    - include_tasks: rsync/start_rsync.yml           ------启动服务的playbook
    
  handlers:
    - name: Restart Rsync
      service:
      name: rsyncd

playbook忽略错误

默认playbook会检测task执行的返回状态,如果遇到错误则会立即终止playbook的后续task执行,然鹅有些时候playbook即使执行错误了也要让其继续执行

加入参数:ignore_errors:yes 忽略错误

- hosts: web_group
  # 不调用系统内置变量,节省时间
  gather_facts: no  
  tasks:    
    - name: panduan php
      # 判断php是否安装
      shell: 'rpm -qa|grep php'
      # 定义变量名panduan_php
      register: panduan_php
      # 忽略错误提示,不会有错误返回结果,但是如果第一次安装就没成功也不会有错误结果,所以需要下面的判断,是否安装成功
      ignore_errors: yes
      
    - name: Install php
      shell: 'rpm -Uvh /tmp/*.rpm'
      # 判断变量panduan_php.rc返回值为0时(没有安装时),就执行php安装程序
      when: panduan_php.rc != 0

抑制changed

被管理主机没有发生变化,可以使用参数将change状态改为ok

就是将返回值为黄色的结果转为绿色的结果......

vim nginx.yml 
- hosts: web_group  
  gather_facts: no  
  tasks:
    # 检测nginx配置文件
    - name: check nginx
      shell: '/sbin/nginx -t'
      # 定义变量check_nginx
      register: check_nginx
      changed_when:
        # 取变量check_nginx下面的stderr_lines.0.find值,返回值为ok时,表示nginx配置文件没啥问题,就显示绿色
        - check_nginx.stderr_lines.0.find('ok')        
        - false
posted @ 2021-08-16 22:15  AnOldSong  阅读(63)  评论(0编辑  收藏  举报