Ansible 流程控制

Ansible 流程控制

一、playbook 条件语句

# 不管是shell还是各大编程语言中,流程控制,条件判断这些都是必不可少的,在我们使用Ansible的过程中,条件判断的使用频率极其高。
例如:
1.我们使用不同的系统的时候,可以通过判断系统来对软件包进行安装。
2.在nfs和rsync安装过程中,客户端服务器不需要推送配置文件,之前我们都是写多个play,会影响效率。
3.我们在源码安装nginx的时候,执行第二遍就无法执行了,此时我们就可以进行判断是否安装过。

1.判断系统

[root@m01 project]# vim xitong.yml
- hosts: web_group
  tasks:
    - name: Install Centos httpd
      shell: "yum install -y httpd"
      when: ansible_distribution == "CentOS"
 
    - name: Install Ubuntu httpd
      shell: "apt-get apache2"
      when: ansible_distribution == "Ubuntu"

2.判断主机

[root@m01 project]# cat base.yml
    - name: Create www Group
      group:
        name: www
        gid: 666
        state: present
      when: ansible_fqdn != "db01"
 
    - name: Create www User
      user:
        name: www
        uid: 666
        group: www
        shell: /sbin/nologin
        create_home: false
        state: present
      when: ansible_fqdn != "db01"

3.判断服务是否安装

[root@m01 project]# cat php.yml
- hosts: web_group
  tasks:
    - name: Tar php Package
      unarchive:
        src: /project/package/php.tar.gz
        dest: /tmp/
 
    #使用shell模块,检查php是否安装,将结果赋值给注册的变量
    - name: Check php Install Status
      shell: "rpm -qa | grep php | wc -l"
      register: get_php_instll_status
 
    #调用注册的变量,当变量中stdout_lines为0的时候,才会安装php
    - name: Install php Server
      shell: "yum localinstall -y /tmp/*.rpm"
      when: get_php_instll_status.stdout_lines == 0

4.判断系统版本启动服务

1)写法一:使用列表的形式

[root@m01 project]# vim startserver.yml
- hosts: web_group
  tasks:
    - name: Start CentOS 6 Server
      shell: "/etc/init.d/httpd start"
      when:
        - ansible_distribution == "CentOS"
        - ansible_distribution_major_version == "6"
 
    - name: Start CentOS 7 Server
      shell: "systemctl start httpd"
      when:
        - ansible_distribution == "CentOS"
        - ansible_distribution_major_version == "7"

2)写法二:多条件and连接

[root@m01 project]# vim startserver.yml
- hosts: web_group
  tasks:
    - name: Start CentOS 6 Server
      shell: "/etc/init.d/httpd start"
      when: (ansible_distribution == "CentOS") and (ansible_distribution_major_version == "6")
 
    - name: Start CentOS 7 Server
      shell: "systemctl start httpd"
      when: (ansible_distribution == "CentOS") and (ansible_distribution_major_version == "7")

5.判断服务是否启动

- hosts: web_group
  tasks:
    - name: Check Httpd Server
      command: systemctl is-active httpd
      ignore_errors: yes
      register: check_httpd
 
    - name: debug outprint
      debug: var=check_httpd
 
    - name: Httpd Restart
      service:
        name: httpd
        state: restarted
      when: check_httpd.rc == 0

二、playbook 循环语句

在之前的学习过程中,我们经常会有传送文件,创建目录之类的操作,创建2个目录就要写两个file模块来创建,如果要创建100个目录,我们需要写100个file模块???妈耶~~~~ 当然不是,只要有循环即可,减少重复性代码。

1.定义循环安装服务

[root@m01 project]# vim yum.yml 
- hosts: web_group
  gather_facts: no
  tasks:
    - name: Install Redis Server
      yum:
        name: "{{ package }}"
        state: present
      vars:
        package:
          - redis
          - httpd

2.定义循环启动服务

#错误写法
[root@m01 project]# vim start.yml
- hosts: web_group
  tasks:
    - name: Start Server
      systemd:
        name: "{{ package }}"
        state: started
      vars:
        package:
          - redis
          - httpd
 
#正确写法
[root@m01 project]# vim start.yml
- hosts: web_group
  tasks:
    - name: Start Server
      systemd:
        name: "{{ item }}"
        state: started
      with_items:
        - redis
        - httpd

3.字典定义变量

[root@m01 project]# cat user.yml 
- hosts: lb01
  tasks:
    - name: Create Some Group
      group:
        name: "{{ item.name }}"
        gid: "{{ item.gid }}"
        state: present
      with_items:
        - { name: "lhd", gid: "777" }
        - { name: "test", gid: "888" }
        - { name: "egon", gid: "999" }
 
    - name: Create Some User
      user:
        name: "{{ item.name }}"
        uid: "{{ item.uid }}"
        group: "{{ item.group }}"
        shell: "{{ item.shell }}"
        create_home: "{{ item.create_home }}"
      with_items:
        - { name: "lhd", uid: "777", group: "lhd", shell: "/sbin/nologin", create_home: "false" }
        - { name: "test", uid: "888", group: "test", shell: "/bin/bash", create_home: "false" }
        - { name: "egon", uid: "999", group: "egon", shell: "/bin/bash", create_home: "true" }

三、playbook handlers 触发器

1.什么是handlers?

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

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

2.配置触发器

[root@m01 project]# cat nginx.yml 
- hosts: nginx
  tasks:
    - name: Config Nginx Server
      copy:
        src: /etc/nginx/nginx.conf
        dest: /etc/nginx/
      notify: restart_nginx
 
    - name: Start Nginx Server
      systemd:
        name: nginx
        state: started
 
  handlers:
    - name: restart_nginx
      systemd:
        name: nginx
        state: restarted

3.触发器使用注意事项

# 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

4.简单优化后的php文件

[root@m01 project]# cat php.yml 
- hosts: web_group
  tasks:
    - name: Tar php Package
      unarchive:
        src: /project/package/php.tar.gz
        dest: /tmp/
 
    - name: Check php Install Status
      shell: "rpm -qa | grep php | wc -l"
      register: get_php_instll_status
 
    - name: Install php Server
      shell: "yum localinstall -y /tmp/*.rpm"
      when: get_php_instll_status.stdout_lines == 0
 
    - name: Config php Server
      copy:
        src: "{{ item.src }}"
        dest: "{{ item.dest }}"
      with_items:
        - { src: "/project/conf/php.ini", dest: "/etc" }
        - { src: "/project/conf/www.conf", dest: "/etc/php-fpm.d/" }
      notify: restart_php
 
    - name: Start php Server
      systemd:
        name: php-fpm
        state: started
 
  handlers:
    - name: restart_php
      systemd:
        name: php-fpm
        state: restarted

四、playbook 任务标签

1.标签的作用

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

2.打标签的方式

# 1.对一个task打一个标签
# 2.对一个task打多个标签
# 3.对多个task打一个标签

3.对一个task打一个标签

- hosts: nginx
    - name: Config Nginx Server
      copy:
        src: /etc/nginx/nginx.conf
        dest: /etc/nginx/
      notify: restart_nginx
      tags: reconf_nginx

4.对多个task打一个标签

- hosts: nginx
    - name: Config Nginx Server
      copy:
        src: /etc/nginx/nginx.conf
        dest: /etc/nginx/
      notify: restart_nginx
      tags: reconf_nginx
 
    - name: Config Nginx wordpress
      copy:
        src: /project/conf/linux.wp.com.conf
        dest: /etc/nginx/conf.d/
      notify: reload_nginx
      when: (ansible_fqdn == "web01") or (ansible_fqdn == "web02")
      tags: reconf_nginx

5.对一个task打多个标签

- hosts: nginx
    - name: Config Nginx Server
      copy:
        src: /etc/nginx/nginx.conf
        dest: /etc/nginx/
      notify: restart_nginx
      tags: 
        - reconf_nginx
        - reconfig_nginx

6.标签使用方式

1)查看标签

[root@m01 project]# ansible-playbook wp.yml --list-tags
 
playbook: wp.yml
 
  play #1 (nginx): nginx    TAGS: []
      TASK TAGS: [reconf_nginx, reconfig_nginx]

2)执行指定标签的内容

[root@m01 project]# ansible-playbook wp.yml -t reconfig_nginx

3)执行多个标签代表的内容

[root@m01 project]# ansible-playbook wp.yml -t reconf_nginx,reconfig_nginx

4)不执行指定标签的内容

[root@m01 project]# ansible-playbook wp.yml --skip-tags reconfig_nginx

五、playbook 复用

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

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

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

1.playbook复用的配置

1)编辑两个剧本

[root@m01 project]# cat play1.yml 
- name: Install Nginx Server
  yum:
    name: nginx
    state: present
 
[root@m01 project]# cat play2.yml 
- name: Config Nginx Server
  copy:
    src: /etc/nginx/nginx.conf
    dest: /etc/nginx/

2)编写复用剧本的文件

[root@m01 project]# vim main.yml
- hosts: web_group
  tasks:
    - include_tasks: /project/play1.yml
    - include_tasks: /project/play2.yml

2.直接复用palybook文件

[root@m01 project]# cat main.yml 
- import_playbook: ./base.yml
- import_playbook: ./nginx.yml
- import_playbook: ./php.yml
- import_playbook: ./wordpress.yml
- import_playbook: ./mariadb.yml

2、playbook忽略错误

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

- hosts: web_group
  tasks:
    - name: Check Httpd Server
      #使用命令检查服务启动状态时,如果服务没有启动则会得到错误结果,剧本会停止运行
      command: systemctl is-active httpd
      #配置忽略错误可以继续执行剧本
      ignore_errors: yes
      register: check_httpd
 
    - name: debug outprint
      debug: 
        msg: "{{ check_httpd }}"
 
    - name: Httpd Restart
      service:
        name: httpd
        state: restarted
      when: check_httpd.rc == 0

3、错误处理

# 如上所述,当task执行失败时,playbook将不再继续执行,包括如果在task中设置了handler也不会被执行。
 
#但是我们可以采取强制措施...

1)强制调用handlers

[root@m01 ~]# cat handler.yml 
- hosts: web_group
  vars:
    - http_port: 8080
  force_handlers: yes
  tasks:
    - name: config httpd server
      template:
        src: ./httpd.j2
        dest: /etc/httpd/conf
      notify: 
        - Restart Httpd Server
        - Restart PHP Server
 
    - name: Install Http Server
      yum:
        name: htttpd
        state: present
 
    - name: start httpd server
      service:
        name:httpd
        state: started
        enabled: yes
 
  handlers:
    - name: Restart Httpd Server
      systemd:
        name: httpd
        state: restarted
 
    - name: Restart PHP Server
      systemd:
        name: php-fpm
        state: restarted

2)抑制changed

# 被管理主机没有发生变化,可以使用参数将change状态改为ok
 
    - name: Check php Install Status
      shell: "rpm -qa | grep php | wc -l"
      register: get_php_instll_status
      changed_when: false
posted @ 2021-09-02 15:25  小丶凡  阅读(38)  评论(0编辑  收藏  举报
1