Ansible变量

一、变量介绍

1.1、概述

变量提供了便捷的方式来管理Ansible playbook的每一个项目中的动态之,比如nginx-1.6.3这个软件包的版本,在其他地方或许会反复使用,那么如果将此值设置为变量,然后在其他的playbook中调用,会方便维护,减少维护成本。

1.2、定义变量的方式

1.通过命令行进行变量定义
2.在play文件中进行变量定义
3.通过inventory主机清单中进行变量定义
4.通过vars_file定义变量
5.通过hosts_vars和group_vars定义定量

1.3、变量的优先级

如果在定义变量时,变量冲突了,生效会有优先级
如: 1.命令行中设置: age=11
	2.paly文件中: age=12
	3.Inventory中:age=13
最终结果是:11
优先级
# 命令行--> playbook --> Indentory文件

#变量设置:命令时,应该由字母数字,下划线组成,必须由字母开头

二、变量的定义

2.1、在playbook文件中进行变量定义

1)方式一:在模块下定义变量

- hosts: web_group
  tasks:
    - name: Install Http Nginx
      yum:
        name: "{{ packages }}"
        state: installed
      vars:
        packages:
          - httpd
          - nginx
# 如果将变量设置到模块下,其他的 - name 是不识别的

2)方式二:在hosts下定义变量

- hosts: web
  vars:
    packages:
      - httpd
      - nginx
  tasks:
    - name: Install Http Nginx
      yum:
        name: "{{ packages }}"
        state: installed

# 在 - hosts 下定义多个变量
- hosts: web
  vars:
    packages:
      - httpd
      - nginx
    web_vars:
      - mysql
      - redis
  tasks:
   - name: Install http
     yum:
       name: "{{ web_vars }}"
       
# 设置到 - hosts 下,其他 hosts 不能识别

2.2、在vars_file 文件中定义变量

在palybook中使用vars定义变量,只能在一个palybook中生效,其他playbook无法使用,第二种方式,在 'var_file文件'中定义变量.

1)准备变量文件

1.  mkdir vars		#创建单独目录,和playbook同级
2.  cd vars/		#进入目录
3. vim vars.yaml	#创建变量文件

packages:httpd		#设置变量
web:
  - nginx
  - httpd

2)调用变量文件

# 	vim playbook.yaml
- hosts: web_group
  vars_files: /tmp/vars/vars.yaml
  tasks:
    - name: Install Http
      yum:
        name: "{{ packages }}"
        
调用多个变量文件
#	vim playbook22.yaml
- hosts: lb_group
  vars_files:
    - /tmp/vars/vars.yaml
    - /tmp/vars/vars1.yaml
  tasks:
    - name: Install Mariadb
      yum:
        name: "{{ dbs }}"
        state: installed

2.3、通过Inventory主机清单进行变量定义

1)配置主机清单

[root@m01 ~]# vim /etc/ansible/hosts 
... ...
[db_server]
db01 ansible_ssh_pass='1'
 
[db_server:vars]
web=nginx

2)调用变量

[root@m01 project]# vim yum.yml 
- hosts: db_server
  tasks:
    - name: Touch File
      file:
        path: /tmp/{{ web }}
        state: touch
 
#注意:
	1.主机清单中定义变量,只要hosts配置的主机清单中设置变量的组,可以直接使用变量。
	2.如果hosts配置的不是主机清单中设置变量的组,变量不可识别

3)主机清单定义变量优先级

1.主机组定义的变量优先级高于整合组定义的变量
2.主机定义的变量优先级高于主机组定义的变量
#    主机 > 主机组 > 整合组


# vim /etc/ansible/hosts
[lb_server]			#主机组
lb01 ansible_ssh_pass='1'
lb02 ansible_ssh_pass='1'
 ......

[nginx:children]	#整合组
web_group
lb_server
 
 
[nginx:vars]
web=nginx_group
 
[web_group:vars]
web=nginx_host

2.4、通过hosts_vars和group_vars定义变量

比较好用的实在Ansible项目目录下创建两个变量目录:
# 切记,目录名字一定要一致,不能做任何修改。

	'host_vars'
	'group_vars'

1)主机组定义变量

1.创建主机组变量目录,在ansible项目目录下,不能改名字!和需要执行的ansible-playbook同级
[root@m01 project]#  mkdir group_vars

2.目录下创建变量文件,文件的名字要跟'主机清单中主机组名字一致'
[root@m01 project]# cd group_vars/
[root@m01 group_vars]# vim web_group
file: 
  - nginx
  - mariadb

# 只要剧本中的hosts与设置变量的主机组名字相同,就可以直接使用变量

3.调用变量

- hosts: web_group
  tasks:
    - name: Touch File
      path: /tmp/{{ file }}
      state: touch

2)主机定义变量

1.创建主机变量的目录,不能改名字!
[root@m01 project]#  mkdir host_vars

2.目录下创建变量文件,文件的名字要跟'主机清单中主机名字一致'
vim /tmp/host_vars/web01

file_name:
  - httpd
  - mysql

3.调用变量
- hosts: web_group
  tasks:
    - name: Touch File
      file:
        path: /tmp/{{ file_name }}
        state: touch

2.5、命令行定义变量(命令行 -e 设置变量)

1)查看剧本文件

[root@m01 project]# cat test.yml 
- hosts: web_group
  tasks:
    - name: Touch File
      file:
        path: /tmp/{{ file }}
        state: touch

2)命令行指定变量执行

# 命令行指定变量
ansible-playbook test.yaml -e "file=papa"
# 命令行指定多个变量
ansible-playbook test.yaml -e "file=papa" -e "file2=papa2"

2.6、内置变量---可直接使用

部分内置变量

# 简短主机名
ansible_fqdn
# 获取当前play所操作的所有主机的主机名列表
play_hosts
# 获取主机IP
ansible_eth1.ipv4.address
# 获取时间
ansible_data_time.data
# 获取系统
ansible_distribution
# 获取系统版本号
ansible_distribution_major_version
....

#使用内置变量创建目录,目录格式为 主机名_IP_时间
[root@m01 project]# vim test.yml 
- hosts: web_group
  tasks:
    - name: Touch File
      file:
        path: /backup/{{ ansible_fqdn }}_{{ ansible_eth1.ipv4.address }}_{{ ansible_date_time.date }}
        state: directory

2.7、层级定义变量

#编辑变量文件
[root@m01 ~]# vim vars_file.yml
lamp:
  framework:
    web_package: httpd
    db_package: mariadb-server
    php_package: php
 
lnmp:
  framework:
    web_package: nginx
    db_package: mysql
    php_package: php
 
lnmt:
  framework:
    web_package: nginx
    db_package: mysql
    java_package: tomcat
 
#编辑playbook文件
[root@m01 ~]# vim test.yml
- hosts: web_group
  vars_files: ./vars_file.yml
  tasks:
    - name: Install LAMP httpd
      yum:
        name: "{{ lamp.framework.web_package }}"
 
    - name: Install LAMP mariadb-server
      yum:
        name: "{{ lamp.framework.db_package }}"
 
    - name: Install LAMP php
      yum:
        name: "{{ lamp.framework.php_package }}"
 
#官方推荐写法
[root@m01 ~]# vim test.yml
- hosts: web_group
  vars_files: ./vars_file.yml
  tasks:
    - name: Install LAMP httpd
      yum:
        name: "{{ lamp['framework']['web_package'] }}"
 
    - name: Install LAMP mariadb-server
      yum:
        name: "{{ lamp['framework']['db_package'] }}"
 
    - name: Install LAMP php
      yum:
        name: "{{ lamp['framework']['php_package'] }}"
 
#执行playbook
[root@m01 ~]# ansible-playbook test.yml

三、变量注册

当ansible的模块在运行之后,其实都会返回一些result结果,就像是执行脚本,我们有的时候需要脚本给我们一些return返回值,我们才知道,上一步是否执行成功,但是默认情况下,ansible的result是不会显示出来的,所以,我们可以把这些返回值存储到变量中,这样我们就能通过调用对应的变量名,从而获得这些result,这样将模块的返回值,写入到变量中的方法称为变量注册。


register    定义变量,可以使用debug输出

debug模块
msg:可以输出变量或者任何内容

when  判断 rc
when: get_php_install.rc !=

ignore_errors: yes  忽略错误

3.1、使用ad-hoc回得到返回的结果

[root@m01 project]# ansible web01 -m shell -a 'ls -l /tmp'
web01 | CHANGED | rc=0 >>
total 0
drwx------. 2 root root 41 Dec 23 15:07 ansible_command_payload_Q9bnkr
-rw-r--r--. 1 root root  0 Dec 23 14:54 command
-rw-r--r--. 1 root root  0 Dec 23 14:57 host_vars
-rw-r--r--. 1 root root  0 Dec 23 14:56 playbook_vars
-rw-r--r--. 1 root root  0 Dec 23 14:55 vars_file

3.2、使用playbook执行同样的命令得不到结果

[root@m01 project]# cat test.yml 
- hosts: web_group
  tasks:
    - name: Touch File
      shell: "ls -l /tmp"
 
[root@m01 project]# ansible-playbook test.yml 
PLAY [web_group] *****************************************************************************************************
 
TASK [Gathering Facts] ***********************************************************************************************
ok: [web01]
ok: [web02]
 
TASK [Touch File] ****************************************************************************************************
changed: [web01]
changed: [web02]
 
PLAY RECAP ***********************************************************************************************************
web01                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
web02                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

3.3、使用注册变量的方式

1)注册一个变量并调用

#	注册变量
- hosts:
  tasks:
    - name: Touch File
      shell: ls -l /tmp
      register: get_dir_list
      
#	调用变量
- hosts:
  tasks:
    - name: Touch File
      shell: ls -l /tmp
      register: get_dir_list
      
    - name: Get get_dir_list	#调用
      debug:
        msg: "{{ get_dir_list }}"
 

#	只输出想要的部分
- hosts:
  tasks:
    - name: Touch File
      shell: ls -l /tmp
      register: get_dir_list
      
    - name: Get get_dir_list
      debug:
        msg: "{{ get_dir_list.stdout_lines }}"  # . 后面跟想要得到的信息

2)变量注册一般使用场景

- hosts:
...

- name: Check Install Status
  shell: "rpm -qa | grep php | wc -l"
 #shell: rpm -qa nginx
  register: get_php_is_install
  
- name: Install Php Server
  shell: "yum localinstall -y /tmp/*.rpm"
  when: get_php_is_install.stdout_lines == 0
  
...

四、facts缓存

Ansible facts 是在被管理主机上通过Ansible 自动采集发现的变量,facts包含每台特定的主机信息,比如:被控端的主机名、IP地址、系统版本、cpu数量、内存状态、磁盘状态等等

4.1、使用场景

1.通过facts缓存检查cpu,来生成对应的nginx配置文件
2.通过facts缓存检查主机名,生成不同的redis配置文件
3.通过facts缓存检索物理机的内存大小来生成不同的mysql配置文件

# ansible facts类似于saltstack中的grains对于做自动化的小伙伴是非常有用滴。

4.2、关闭facts缓存

- hosts:
  gather_facts: no # 关闭缓存信息采集
  tasks:
  ...
  
#	如果不适用内置变量,可以关闭会提高剧本的执行速度,如果使用内置变量,那么不能关闭facts缓存

4.3、一般使用

# template 用法和copy类似,支持ansible——facts的内置变量
用于推送配置文件时,使用内置变量,主机名和IP地址会根据主机的信息做出更改,适合不同的主机使用配置文件

1.配置redis配置文件
vim /etc/redis.conf
#   bind {{ ansible_eth1.ipv4.address }}

2.编写剧本
- hosts: web_group
  tasks:
    - name: Install Redis
      yum:
        name: redis
     - name: Send Config File
       tmplate:
         src: /tmp/redis.conf
         dest: /etc/
3.查看受控端配置
[root@web01 ~] #    bind 172.16.1.7       
[root@web02 ~] #    bind 172.16.1.8

五、Ansible流程控制

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

#例如:
1.我们使用不同的系统的时候,可以通过判断系统来对软件包进行安装
2.在nfs和rsync安装过程中,客户端服务器不需要推送配置文件,之前我们都是写多个play,会影响效率。
3.我们在源码安装nginx的时候,执行第二遍就无法执行了,此时我们就可以进行判断是否安装过。

5.1、playbook条件语句

#	when  判断语句,符合条件后执行,变量不需要加{{}}和""

1)判断系统

- hosts: web_group
  tasks:
    - name: Install CentOS httpd
      shell: yum install -y https
      when: ansible_distribution == "CentOS"
    
    - name: Install Ubuntu Httpd
      shell: "apt-get apache2"
      when: ansible_distribution == "Ubuntu"

2)判断主机

- name: Creater 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)判断服务是否安装

- hosts:
  tasks:
    # 使用shell模块检查nginx是否安装,复制给变量注册
    - name: Check Nginx Status
      shell: rpm -qa nginx
      register: is_install_nginx
    # 调用注册变量,当stdout_lines为0的时候,才会安装
    - name: Install Nginx
      yum:
        name: nginx
      when: is_install_nginx.stdout.lines == 0

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

两种方式:1.列表的形式 2.多条件and连接
#  使用列表的形式
- name: Start CentOS 6 Server
  shell:  "/etc/init.d/htttpd 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

#  使用多条件and连接
- name: Start CentOS 7 Server 
  shell: "systemctl start httpd"
  when: (ansible_distribution == 'CentOS') and (ansible_distribution_major_version == '7')

### 5)判断是否启动

- hosts: web01
  tasks:
    - name: Check Nginx
      shell: ps -ef | grep [n]ginx  # 判断是否启动
      ignore_errors: yes		#忽略错误,如果没有启动就报错,ansible就会停止,所以要忽略错误
      register: check_nginx		#变量注册
    
    - name: Stop Nginx
      service:
        name: nginx
        state: stopped
      when: check_nginx.rc == 0  # 返回值为0是启动,非0就是没有启动

5.2、playbook循环语句

ansible操作多台主机,需要传送文件,创建目录之类的,创建两个目录需要两个file模块来创建,100个需要100个file模块,为了提高工作效率,可以使用循环,减少重复性代码。

1)定义循环安装服务

- hosts: web_group
  tasks:
    - name: Install Nginx and Nfs
      yum:
        name: "{{ nginx_nfs }}"
      vars:
        nginx_nfs:
          - nginx
          - nfs-server

2)定义循环启动服务

#	错误写法
- hosts: web01
  tasks:
    - name: Start Server
      service:
        name: "{{ packages }}"
        state: started
      vars:
        packages:
          - nginx
          - httpd

#	正确写法
- hosts: web01
  tasks:
    - name: Start Server
      service:
        name: "{{ item }}"
        state: started
    with_items:
      - nginx
      - httpd

3)字典定义变量

- hosts: web_group
  tasks:
    - name: Create Some Group
      group:
        name: "{{ item.name }}"
        uid: "{{ item.uid }}"
        state: present
      with_items:
        - { name: "haopapa", gid: "666" }
        - { name: "papahao", gid: "777" }
        - { name: "pahaopa", gid: "888" }
 
- hosts: web_group
  tasks:
    - name: Create Some User
      user:
        name: "{{ item.user }}"
        uid: "{{ item.uid }}"
        group: "{{ item.group }}"
        shell: "{{ item.shell }}"
        create_home: "{{ item.create_home }}"
      with_items:
        - { name: "a", uid: "111", group: "www", shell: "/sbin/nologin", create_home: "false" }
        - { name: "b", uid: "222", group: "www", shell: "/sbin/nologin", create_home: "false" }
        - { name: "c", uid: "333", group: "www", shell: "/sbin/nologin", create_home: "false" }
        - { name: "d", uid: "444", group: "www", shell: "/sbin/nologin", create_home: "false" }

六、playbook handlers触发器

6.1、什么是handlers?

handlers用来执行某些条件下的任务,比如当配置文件发生变化的时候,通过notify触发handler去重启服务
在saltstack中也有类似的触发器,写法相对ansible简单,只需要watch,配置文件即可。

6.2、配置触发器

- hosts: web01
  tasks:
    - name: Config Nginx Server
      copy:
        src: /etc/nginx/nginx.conf
        dest: /etc/nginx/
      notify: restart_nginx	#配置notify
      
    - name: Start Nginx Server
      service:
        name: nginx
        state: started
      
  handlers:				#handlers放在最后,所以tasks执行完之后,执行handlers
    - name: restart_nginx
      service:
        name: nginx
        state: restarted

6.3、触发器使用注意事项

1.无论'多少个task'通知了相同的handlers, handlers仅会在tasks结束后'运行一次'。
2.handlers只有在'其所在'的任务'被执行时',才会被'运行';如果一个任务中定义了notify调用handlers,但是由于条件判断等原因,该任务未被执行,那么handlers同样不会执行。
3.handlers只会在每一个play的'末尾运行'一次;如果想在一个playbook'中间运行'handelers,则需要'meta模块'来实现,例如:flush_handlers。
4.如果一个play在运行到调用handlers的语句之前失败了,那么这个handlers将不会被执行,我们可以使用meta模块的-'-force-handlers'选项来'强制执行handlers',即使handlers所在的play中途运行失败也能执行。

6.4、示例:

[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任务标签

7.1、标签的作用

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

7.2、打标签的方式

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

7.3、对一个task打一个标签

- hosts: web01
  task:
    - name: Config Nginx Server
      copy: 
        src: /etc/nginx/nginx.conf
        dest: /etc/nginx/
      notify: restart_nginx
      tags: reconf_nginx		# 在某一个任务上打上标签

7.3、对多个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	#同一个标签

7.4、对一个task打多个标签

- hosts: nginx
    - name: Config Nginx Server
      copy:
        src: /etc/nginx/nginx.conf
        dest: /etc/nginx/
      notify: restart_nginx
      tags: 
        - reconf_nginx
        - reconfig_nginx	#在同一个任务上打多个标签

7.5、标签使用方式

1)查看标签

#	ansible-playbook ceshi.yaml --list-tags

playbook: ceshi.yaml

  play #1 (web01): web01	TAGS: []
      TASK TAGS: [httpd_start, nginx_start]

2)执行指定标签的内容

# 执行指定标签代表的内容
ansible-playbook ceshi.yaml -t nginx_start

# 执行指定多个标签代表的内容
ansible-playbook ceshi.yaml -t nginx_start,httpd_start

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

ansible-playbook ceshi.yaml --skip-tags nginx_start

# 八、palybook的复用

playbok提供了include功能,可以调用多个yaml文件内的task任务列表统一执行,可以实现将功能拆分模块化,'可以理解为松耦合',然后根据需求调用各个模块去执行任务

java yaml工具类 java yaml $ 值替换_java yaml工具类

8.1、playbook复用的配置

1)编辑两个剧本

# cat play1.yaml
- name: Install Nginx
  yum:
    name: nginx
 
# cat play2.yaml
- name: Config Nginx
  copy:
    src: /etc/nginx/nginx.conf
    dest: /etc/nginx/

2)编写复用剧本的文件

- hosts: web_group
  tasks:
    - include_tasks: /tmp/play1.yaml
    - include_tasks: /tmp/play2.yaml

3)直接复用playbook文件

[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

九、playbook其他功能

9.1、playbook忽略错误

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

#	ignore_errors:yes  忽略错误

- hosts: web_group
  tasks:
    - name: Ignore False
      shell: /bin/false    # 出现错误,playbook停止
    ignore_errors: yes     # 忽略错误,ansible继续执行

当task执行失败是,playbook将不再执行,如果在task设置了handlers也不会被执行,所以可以使用强制调用handler

9.2、强制调用handler

#	force_handlers: yes  强制调用handlers

- hosts: web_group
  force_handlers: yes	# 在hosts层写上强制调用
  tasks:
    - name: Send Nginx Config
      template:
        src: /etc/nginx/nginx.conf
        dest: /etc/nginx/
      notify:
        - restart_nginx
        - restart_php-fpm
    - name: Make False
      shell: /bin/false  # 人为制造错误
      
  handlers:
    - name: restart_nginx
      systemd:
        name: nginx
        state: restarted
    - name: restart_php-fpm
      systemd:
        name: php-fpm
        state: restarted	
# 正常情况下,playbook会在发生错误时停止运行playbook,handlers不会被执行,因为在最前面开启了强制调用handlers,所以handlers还是会执行。

9.3、抑制changed

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

#	changed_when	被管理主机没有变化,将change状态改为ok

- hosts: web_group
  tasks:
    - name: shell
      shell: netstat -tupln | grep nginx
      register: grep_port
      changed_when: false  # 没有改变时,状态改为ok

9.4、max_fail_percentage

一般来讲,当task失败时,ansible会停止执行失败的那台主机上的任务,但是继续对其他 主机执行。在负载均衡的场景中,我们会更希望ansible在所有主机执行失败之前就让play停止,否则很可能会面临所有主机都从负载均衡器上摘除并且都执行失败导致服务不可用的场景。这个时候,我们可以使用'serial'语句'配合'---'max_fail_percentage语句使用'。'max_fail_percentage'表示当最大失败主机的比例达到多少时,ansible就让整个play'失败'

假如负载均衡后面有4台主机,并且有一台主机执行失败,这时ansible还会继续运行,要让Play停止运行,则必须超过25%,所以如果想一台失败就停止执行,我们可以将max_fail_percentage的值设为24。如果我们希望只要有执行失败,就放弃执行,我们可以将max_fail_percentage的值设为0。

9.5、serial每次在指定数量的主机上运行playbook

serial的值为1,即表示在某一个时间段内,play只在一台主机上执行。如果为2,则同时有2台主机运行play

9.6、ignore_errors

在执行playbook时,不可避免会遇到一些错误。ansible默认处理错误的机制是遇到错误就停止执行。但有些时候,有些错误是计划之中的。我们希望忽略这些错误,以让playbook继续往下执行。这个时候就需要用到ignore_erros了

ignore_errors: yes

9.7、when用法

1. when: ansible_fqdn == "lb01" 	匹配一台主机
2. when: ansible_fqdn != "lb01"		取反
3. when: ansible_fqdn is match "web*"	匹配多台主机

when 的 in 和 and 及 or 用法

when:
  ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux'] and
  (ansible_distribution_version|version_compare('7', '<') or
  ansible_distribution_version|version_compare('8', '>='))
  or
  ansible_distribution == 'Fedora'
  or
  ansible_distribution == 'Ubuntu' and
  ansible_distribution_version|version_compare('15.04', '>=')


# 更加简洁的用法

when:
  - ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux']
  - ansible_distribution_version|version_compare('15.04', '>=')

十、Ansible Jinja2模板概述

10.1、Jinja2模板概述

# 什么是Jinja2模板
Jinja2是python的全功能模板引擎,是Flask作者开发的一个模板系统,起初是模仿django模板的一个模板引擎,为flask提供模板支持。Jinja2能识别所有的pythone数据类型字典、对象等等。
# 优点:
1.相对于 template , Jinja2更加灵活,提供了控制结构,表达式和继承等。
2.相对于Mako,Jinja2仅有控制结构,不允许在模板中编写太多的业务逻辑
3.相对于Django模板,Jinja2性能更好
4.Jinjs2模板的可读性很好。

# Jinja2与Ansible关系
Ansible通常会使用Jinja2模板来修改被管理主机的配置文件等,在saltstack中同样会使用到Jinja2

# Ansible如何使用Jinja2
使用Ansible的Jinja2模板也就是使用template模块,该模块和copy模块一样,都是将'文件复制'到远端主机上去,但是区别在于, template模块可以获取到文件中的变量,而copy则是原封不动的把文件内容复制过去。'template能识别变量','copy不能'.

# Ansible使用Jinja2注意事项
Ansible允许Jinja2模板中使用条件判断和循环,但是不允许在playbook中使用。
# 不是每个管理员都需要这个特性,但是有些时候Jinja2模板能大大提高效率

10.2、Ansible Jinja2模板使用

1)变量使用语法

{{ EXPR }} 输出变量值,会输出自定义的变量值或facts
Jinja2模板中使用 {{ }} 语法表发一个变量,它是一种特殊的占位符,当利用jinja2进行渲染的时候,他会把这些特殊的占位符进行填充/替换。
搭配 template 模块进行使用

2)逻辑判断语法

#	条件判断	
{% if EXPR %}
{% elif EXPR %}
{% else EXPR %}
{% endif EXPR %}

3)循环语法

#	循环表达式  支持python中的变量语句
range就是python中经常使用的取值范围,和shell中`seq 20`一样

{% for i in range(7,20) %}
{% endfor %}

4)注释

Jinja2注释语法
{# COMMENT #}

shell中只是在内容最前面加上#

10.3、Jinja2模板测试

1)配置登陆文件的Jinja2模板

#	vim motd.j2
Welcome to {{ ansible_fqdn }}
This system total mem is : {{ ansible_memtotal_mb }} MB
This system free mem is : {{ ansible_memfree_mb }} MB

# 编写剧本
- hosts: all		# all代表主机清单中所有主机
  tasks:
    - name: Send Motd
      template:
        src: /root/motd.j2
        dest: /etc/motd

# 执行查看结果

[root@m01 project]# ansible-playbook motd.yml
 
#查看结果  以下结果只是推过来时候查看一次,不是动态表示,做测试用查看
Last login: Thu Dec 24 15:29:37 2020 from 10.0.0.61
Welcome to db01
This system total mem is : 972 MB
This system free mem is: 267 MB

2)配置负载均衡nginx

vim upstream.j2
upstream {{ server_name }} {
 {{ for i in range(7,20) }}
 	server {{ net_ip }}.{{ i }};
 {{ endfor }}
}

server {
	server_name {{ server_name }};
	listen {{ nginx_port }};
	
	location / {
		proxy_pass http://{{server_name}};
		include proxy_params;
	}	
}

# 准备变量文件
vim upstream_vars.yml
server_name: www.papacnb.com
nginx_port: 80
net_ip: 172.16.1

# 编写剧本
- hosts: lb
  tasks:
    - name: Send Nginx Conf File
      template:
        src: /root/upstream.j2
        dest: /etc/nginx/conf.d/upstream.conf
      notify: restart_upstream
      
    - name: start nginx
      service:
        name: nginx
        state: started
        
  handlers:
    - name: restart_upstream
      service:
        name: nginx
        state: restarted
# 执行并测试

### 3)keepalived配置文件

# 编辑配置文件--使用变量+判断语句

[root@m01 project]# vim keepalived.conf
global_defs {
    router_id {{ ansible_fqdn }}  # 变量
}
vrrp_instance VI_1 {
   {% if ansible_fqdn == lb01 %} # 判断
    state MASTER
   {% else %} 				# 判断
    state BACKUP
   {% endif %}					# 结束判断
    interface eth0
    virtual_router_id 50
    {% if ansible_fqdn == lb01 %} # 判断
    priority 100
    {% else %}				 # 判断
    priority 90
    {% endif %}					# 结束判断
    advert_int 1
    authentication {    
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.3
    }
}

# 编辑剧本
- hosts: lb_group
  tasks:
    - name: Send Keepalived.conf
      template:
        src: keepalived.conf
        dest: /etc/keepalived/
      notify: restart_keepalived
      
  handlers:
    - name: restart_keepalived
      service:
        name: keepalived
        state: restarted