Ansible组件

Ansible Inventory

  • Inventory文件位置定义

      # ANSIBLE_HOSTS环境变量
      exporter ANSIBLE_HOSTS=/etc/ansible/hosts
      # ansibele.cfg内部指定
      inventory = /etc/ansible/hosts
      # 运行ansible或ansible-playbook用-i参数指定
      ansible -i hosts ...
      ansible-playbook -i hosts ...
    
  • 定义主机和主机组

      # 主机定义,使用inventory内置变量定义ssh登陆密码
      1 172.17.42.101 ansible_ssh_pass ='123456'
      2 172.17.42.102 ansible_ssh_pass ='123456'
    
      # 定义组docker,下面四台机器172.12.42.101~172.12.42.103
      3 [docker]
      4 172.17.42.10[1:3]
      # 针对docker组,使用inventory内置变量定义了ssh登陆密码
      5 [docker:vars]
      6 ansible_ssh_pass ='123456'
    
      # 定义了一个组ansible,包含docker组
      7 [ansible:children]
      8 docker
    
  • 多个inventory文件

    修改ANSIBLE_HOSTS环境变量或者修改ansible.cfg,此时使用目录即可,目录下可以存放不同主机 测试下来,必须放到inventory目录下;或者放在playbook目录下,-i指定

      # ANSIBLE_HOSTS环境变量
      exporter ANSIBLE_HOSTS=/root/inventory
      # ansibele.cfg内部指定
      inventory = /root/inventory
    

    比如:

      [root@Master ~ ]# cat inventory/hosts
      172.17.42.101 ansible_ssh_pass ='123456'
      172.17.42.102 ansible_ssh_pass ='123456'
      
      [root@Master ~ ]# cat inventory/docker
      [docker]
      172.17.42.10[1:3]
      [docker:vars]
      ansible_ssh__pass ='123456'
      [ansible:children)
      docker
    
  • 动态inventory

    将ansible.cfg配置文件中inventory定义成一个脚本即可. 该脚本必须支持2个参数:–list、–host
    或 运行ansible、ansible-playbook命令是-i + 脚本名字.

    #!/usr/bin/python  # 必须加上,否则会被解析为ini文本
    # coding:utf-8
    
    '''
    动态inventory:
    
    a) 需要支持两个参数,--list(返回组包含的主机列表hosts、主机组变量vars、子组列表children、_meta存放主机变量)
    '''
    
    import json
    import sys
    
    
    def groups():
    	'''groups信息:包含主机列表,组变量,子组等信息'''
    	host_list = ["172.22.12." + str(i) for i in range(11,14)]
    	r = dict()
    	r['docker'] = {'hosts':host_list[0:1]}
    	r['web'] = {'hosts':host_list[1:]}
    	print json.dumps(r, indent=4)
    
    
    def hosts(name):
    	'''hosts信息:包含主机变量'''
    	host_var = { 
        	"172.22.12.11":{"ansible_ssh_port":21},
        	"172.22.12.12":{"ansible_ssh_port":22},
        	"172.22.12.13":{"ansible_ssh_port":23}
        	}.get(name)
    	print json.dumps(host_var, indent=4)
    
    
    
    def main():
    	if len(sys.argv) == 2 and sys.argv[1] == "--list":
        	groups()
    	elif len(sys.argv) == 3 and sys.argv[1] == "--host":
        	hosts(sys.argv[2])
    	else:
        	print "Usage: {} --list or --host ".format(sys.argv[0])
    
    
    if __name__ == "__main__":
    	main()
    ```
    	
    
  • Inventory参数说明

    变量 说明
    ansible_ssh_host 将要连接的远程主机名.
    ansible_ssh_port ssh端口号
    ansible_ssh_user ssh用户名
    ansible_ssh_pass ssh密码,建议使用–ask-pass或ssh密钥
    ansible_sudo_pass sudo密码,建议使用–ask-sudo-pass
    ansible_sudo_exe sudo命令路径(适用V1.8及以上)
    ansible_connection 与主机连接的类型,比如 local、ssh、paramiko;ansible以前默认使用paramiko,以后默认使用 ‘smart’,‘smart’ 方式会根据是否支持 ControlPersist, 来判断’ssh’ 方式是否可行
    ansible_ssh_private_key_file ssh使用的私钥文件
    ansible_shell_type 目标系统的shell类型,命令的执行使用’sh’语法,可设置为’csh’或’fish’
    ansible_python_interpreter 目标主机的python路径

    定义主机和组变量的方式:
    a) /etc/ansible/group_vars/组名 /etc/ansible/host_vars/主机名
    b) /etc/ansible/group_vars/组名/{文件1,文件2} # 文件1、文件2中的变量都可以被加载;环境比较复杂时,这种管理方式更好

  • patterns(匹配执行任务的主机)
    下面列举一些常见的匹配条件:

      all:匹配所有主机   // ansible和ansible-playbook都支持
      
      webservers:dbservers:冒号表示或的关系,表示主机可以存在于多个group中   ansible和ansible-playbook都支持
      webservers:!phoenix:表示属于webservers组,不属于phoenix组的主机   ansible-playbook支持
    
      webservers:&staging:交集,表示同时属于webservers和staging组的主机  ansible-playbook支持
      webservers:dbservers:&staging:!phoenix:webserver和dbservers两个组中,隶属于staging组,不属于phoenix组的主机  ansible-playbook支持
    
      ~(web|db).*\.example\.com:正则  ansible-playbook支持
    

Ansible Ad-Hoc命令
ansible-doc -l查看所有自带模块,目前有259个命令
ansible-doc 模块名,查看模块使用方法

  • 执行命令

    ansible命令是并发执行的,并发数由ansible.cfg中的forks值控制、或者运行命令时通过-f参数指定.

    ansible允许异步执行任务,对于执行时间很长的任务,下发任务后每过一段时间轮询获取任务结果.

      # 异步任务超时时间为120s 每个-P参数后秒数轮询获取结果,-P + 0 表示不关心任务结果
      ansible docker -B 120 -P 0 -m shell -a 'sleep 10;hostname' -f 5 -o
    
  • 复制文件

    copy模块批量下发文件,文件变化通过MD5值判断.

      ansible docker -m copy -a 'src=hosts.py dest=/root/hosts.py owner=root group=root mode=644 backup=yes' -o
      # md5值验证  下发三个文件md5值都是一样的.
      ansible docker -m shell -a 'md5sum /root/hosts.py' -f 5 -o
    
  • 包和服务管理

      ansible docker -m yum -a 'name=httpd state=latest' -f 5 -o
      # 验证包是否安装
      ansible docker -m shell -a 'rpm -qa httpd' -f 5 -o
      # 验证服务是否启动
      ansible docker -m shell -a 'netstat -tpln | grep httpd' -f 5
    
  • 用户管理

    首先通过openssl 命令来生成一个密码,因为ansible user 的password 参数需要接受加密后的值:

      [root@Master ~]# echo ansible | openssl passwd -l -stdin
      $1$GPMku7yL$.qu3NC2geUvOJ.NvgfCiol
    

    使用user模块批量新建用户

      ansible docker -m user - a 'name=shencan password=" $1$GPMku7yL$ . qu3NC2geUvOJ.NvgfCiol"' -f 5 -o
      验证远程用户是否创建成功
      ssh 172.17.42.103 -l shencan		# -l 远端登陆用户
    

Ansible Playbook

实例:https://github.com/ansible/ansible-examples

  • 基本语法

      # -f 指定并行线程  --start-at-tasks 指定开始task
      ansible-playbook -i hosts nginx.yml -f 3 --start-at-task='Copy Nginx.conf'
    
  • playbook变量与引用

  1. 通过Inventory文件定义主机以及主机组变量

     # /etc/ansible/hosts
     #172.22.12.13 key=13
     #172.22.12.14 key=14
     [consul]
     172.22.12.1[3:4]
     [consul:vars]
     key: consul
    
     # ansible-playbook variable.yml
     ---
     - hosts: all
       gather_facts: false
       tasks:
         - name: display host variable from hostfile
           debug: msg="The {{ inventory_hostname }} value is {{ key }}"
    ==> 
    当主机处于主机组,并且同时定义相同的变量时,主机变量生效(比如 上述key=13、14生效);要是变量不同,不影响.
    
  2. 通过/etc/ansible/下文件定义主机和主机组变量

     # 主机变量 文件名字和host相同
     [root@shzj-o-proxy-12-7 ansible]# head host_vars/*
     ==> host_vars/172.22.12.13.yaml
     key: 172.22.12.13
    
     ==> host_vars/172.22.12.14.yaml <==
     key: 172.22.12.14
    
     # 主机组变量 主机组变量文件名字和主机组名字相同
     [root@shzj-o-proxy-12-7 ansible]# head group_vars/consul
     key: consul
    
  3. 通过ansbile-playbook命令行传入

     # 支持传入多个变量 空格隔开
     ansible-playbook variable.yml -e 'key=KEY'
     # 支持文件传入变量
     [root@shzj-o-proxy-12-7 ansible]# head var.*
     ==> var.json <==
     {"key": "JSON"}
    
     ==> var.yml <==
     ---
     key: YML
    
     ansible-playbook variable.yml -e '@/etc/ansible/var.yml'
    
  4. 在playbook文件内使用vars

     [root@shzj-o-proxy-12-7 playbook]# cat variable.yml 
     ---
     - hosts: all
       gather_facts: false
       vars:
         key: ansible
       tasks:
         - name: display host variable from hostfile
           debug: msg="The {{ inventory_hostname }} key is {{ key }}"
    
  5. 在playbook 文件内使用vars_files

       vars_files:
         - /etc/ansible/var/json
    
  6. 使用register注册的变量

       tasks:
       	- name: register variable
       	  shell: hostname
       	  register: info  # 接收变量
       	- name: display host variable from hostfile
       	  debug: msg="The {{ inventory_hostname }} key is {{ info['stdout'] }}"  # info是一个dict,此处标准dict取值
    
  7. 使用vars_ prompt 传入
    Ansible 还支持在运行playbook 的时候通过交互式的方式给定义好的参数传人变量值,只需在playbook 中定义vars_prompt 的变量名和交互式提示内容即可.

     - hosts: all
       gather_facts: false
       vars_prompt:
         - name: 'one'
           prompt: 'please input one value'
           private: no  # yes的话  输入不显示
           default: 'good'  # 默认值
       tasks:
         - name: display host variable from hostfile
     	  debug: msg="The {{ inventory_hostname }} key is {{ one }}"
    
  8. 变量引用顺序

  9. yml陷阱

    yml要求:要是值以{{foo}}开头的话,我们需要将整行用双引号引起来. 这是为了确认你不是想声明一个yaml字典.

    - hosts: app_servers
      vars:
         app_path: {{ base_path }}/22   错误
         app_path: "{{ base_path }}/22"
    
  • playbook循环
  1. 标准loops

     # with_items是python list数据结构
     ---
     - hosts: all
       gather_facts: false
       tasks:
         - name: debug loops
           debug: msg="name ---> {{ item }}"
           with_items:
             - one
             - two
     
     # 支持字典
     - hosts: all
       gather_facts: false
       tasks:
         - name: debug loops
           debug: msg="name ---> {{ item.key }} value ---> {{ item.value }}"
           with_items:
             - {key: 'one', value: 'VALUE1'}
             - {key: 'two', value: 'VALUE2'}
    
  2. 嵌套Loops

    嵌套Loops 也是我们编写playbook 中比较常见的一种循环,它主要实现一对多或者多对多的合并.

     # 此处多对多关系,A和B会一一和a,b,c对应,循环输出
     # 类似python中 [ i+y for i in ['A','B'] for y in ['a','b','c'] ]
     - hosts: all
       gather_facts: false
       tasks:
         - name: debug loops
     	  debug: msg="name ---> {{ item[0] }} value ---> {{ item[1] }}"
     	  with_nested:
     	    - ['A','B']
     		- ['a','b','c']
    
  3. 散列loops(循环哈希表)

    散列loops 相比标准loops 就是变量支持更丰富的数据结构,比如标准loops 的最外层数据必须是Python 的list 数据类型,而散列loops 直接支持YAML 格式的数据变量.

     ---
     - hosts: all
       gather_facts: false
       vars:
         user:
           shencan:
             name: shenchan
             shell: bash
       tasks:
         - name: debug loops
           debug: msg="name ---> {{ item.key }} value ---> {{ item.value.name }} shell ---> {{ item.value.shell }}"
           with_dict: "{{ user }}"  # 注意变量引用格式
    
  4. 文件列表loops(模糊匹配文件)

    文件匹配loops 是我们编写playbook 的时候需要针对文件进行操作中最常用的一种循环,比如我们需要针对一个目录下指定格式的文件进行处理,这个时候直接在引用w ith_fileglob 循环去匹配我们需要处理的文件即可.

     # 模糊匹配目录下*.yml文件
     ---
     - hosts: all
       gather_facts: false
       tasks:
         - name: debug loops
           debug: msg="name ---> {{ item }}"
           with_fileglob:
             - /opt/ansible/playbook/*.yml
    
  5. 随机选择loops

    # 传入的list中随机选择一个 和python的random原理一样
    with_random_choice:
      - 'one'
      - 'two'
    
  6. 条件判断Loops

    有时候执行一个task 之后,我们需要检测这个task 的结果是否达到了预想状态,如果没有达到我们预想的状态时,就需要退出整个playbook 执行,这个时候我们就需要对某个task 结果一直循环检测了.

     # 检测host变量是否以Master开头,满足执行task 重试5次
     tasks:
       - name: debug loops
         shell: cat /root/Ansible
         register: host
         until: host.stdout.startswith("Master")
         retries: 5
         delay: 5
    
  7. register loops

    有多个task结果需要注册时,可以使用

     tasks:
       - name: debug loops
         shell: "{{ item }}"
         with_items:
           - hostname
           - uname
         register: ret
       - name: display loops
         debug: msg="{{ item.stdout }}"  # 此处已经是字典了,获取字典key  方式2:var=item.stdout 两者互斥
         with_items: "{{ ret.results }}"  # 注意,此处ret和单个task结果不一样,results先获取list
    
  • playbook lookups

    Ansible 还支持从外部数据拉取信息,比如我们可以从数据库里面读取信息然后定义给一个变量的形式.

  1. lookups file

    读取文件内容,传递进变量 文件位于主控机器端

    # 它的原理就是使用Python 的codecs.open 打开文件然后把结果返回给变量
    vars:
      contents: "{{ lookup('file', '/etc/sysconfig/network') }}"
    tasks:
      - name: debug lookups
        debug: msg="The contents is {% for i in contents.split("\n") %} {{ i }} {% endfor %}"
    
  2. lookups password 对传入的内容进行加密

     vars:
       contents: "{{ lookup('password', 'passwd') }}"
     tasks:
       - name: debug lookups
         debug: msg="The contents is {{ contents }}"
     ⇒ 输出 ”msg ”:”The contents is Np6mOb9ZqrzVU3Sux5gH"
    
  3. lookups pipe

    控制机器上调用subprocess.Popen 执行命令,然后将命令的结果传递给变量

     vars:
       	contents: "{{ lookup('pipe', 'date +%Y-%m-%d') }}"
     tasks:
       - name: debug lookups
         debug: msg="The contents is {% for i in contents.split("\n") %} {{ i }} {% endfor %}"
     ⇒ 输出 ”msg ”:”The contents is Np6mOb9ZqrzVU3Sux5gH"
    
  4. lookups redis_kv

     vars:
       	contents: "{{ lookup('redis_kv', 'redis://localhost:6379,ansible') }}"
    
  5. lookups template

    template 跟file 方式有点类似,都是读取文件,但是template 在读取文件之前需要把jinja 模板渲染完后再读取

     # jinja 模板文件
     worker_processes {{ ansible_processor_cores }};
     IPaddress {{ ansible_eth0.ipv4.address }}
     # playbook文件
     vars:
       	contents: "{{ lookup('template', './lookups.j2') }}"
    
  • playbook conditionals

    实际应用过程中经常会碰到不同的主机可能要执行不同的命令,或者执行某个task 的时候需要进行一个简单的逻辑判断,此刻就需要在写task 的时候进行相应的判断.

    目前Ansible 的所有conditionals 方式都是使用when 进行判断, when 的值是一个条件表达式,如果条件判断成立,这个task 就执行某个操作,如果条件判断不成立,该task 不执行或者某个操作会跳过.

      # 多个when支持and、or操作
      # 和python语言类似,比如对于str:info ['stdout'] . startswith ('M')
      ---
      - hosts: all
        tasks:
          - name: host 172.22.12.13 run this task
    		  debug: msg="{{ ansible_default_ipv4.address }}"
    		  when: ansible_default_ipv4.address == "172.22.12.13"
    

    一系列Jinja过滤器条件也可以在when语句使用

    tasks:
      - command: /bin/false
        register: result
        ignore_errors: True
      - command: /bin/something
        when: result|failed    # | 判断
      - command: /bin/something_else
        when: result|success
      - command: /bin/still/something_else
        when: result|skipped
    

    有些时候你得到一个返回参数的值是一个字符串,并且你还想使用数学操作来比较它,那么你可以执行一下操作:

    tasks:
      - shell: echo "only on Red Hat 6, derivatives, and later"
        when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6   # | int  转换类型
    

    在playbooks 和 inventory中定义的变量都可以使用. 下面一个例子,就是基于布尔值来决定一个任务是否被执行:

    vars:
    	epic: true
    tasks:
    	- shell: echo "This certainly is epic!"
      	  when: epic
    

    如果一个变量不存在,你可以使用Jinja2的defined命令跳过或略过: 这个机制在选择引入变量文件时有时候特别有用

    tasks:
    	- shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
      	  when: foo is defined
    
    	- fail: msg="Bailing out. this play requires 'bar'"
      	  when: bar is not defined
    

    和with_item结合

    tasks:
      - command: echo {{ item }}
        with_items: [ 0, 2, 4, 6, 8, 10 ]
        when: item > 5
    

    在roles语句引入

    - hosts: webservers
      roles:
         - { role: debian_stock_config, when: ansible_os_family == 'Debian' }
    

    条件导入

    比如 Apache的包,在CentOS 和 Debian系统中也许不同, 但是这个问题可以一些简单的语法就可以被Ansible Playbook解决:

    ---
    - hosts: all
      remote_user: root
      vars_files:
    	- "vars/common.yml"
    	- [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ]   # ansible_os_family来自fact变量,可以设置fact缓存
      tasks:
    	- name: make sure apache is running
    	  service: name={{ apache }} state=running
    

    基于变量选择文件和模板

    - name: template a file
      template: src={{ item }} dest=/etc/myapp/foo.conf
      with_first_found:    // 查找第一个找到的文件
     	- files:   // 定义匹配文件
        	- {{ ansible_distribution }}.conf
        	- default.conf
       	  paths:  // 定义查找路径
        	- search_location_one/somedir/
       		- /opt/other_location/somedir/
    

    搭配注册变量,使用when + filter过滤

  • Jinja filters

    JinJa2官网也提供了很多filter

      vars:
      list: [1,2,3,4,5]
      	one: "1"
      	str: "string"
      tasks:
      	- name: run commands
      	  shell: cat /etc/passwd
      	  register: info
      	
      	#  对info.stdout仅从格式化
      	- name: debug pprint filter
      	  debug: msg="{{ info.stdout | pprint }}"
      	
      	#  对info执行状态进行判断 
      	- name: debug conditionals filter
    		  debug: msg="The run commands status is changed"
    		  when: info|changed
      	#  转换类型
      	- name: debug int capitalize filter
      	  debug: msg="The int value {{ one | int }} The lower value is {{ str | capitalize }}"
      	
      	#  对ansible变量引用,没定义引用default值
      	- name: debug defaulr filter
      	  debug: msg="The Variable value is {{ ansible | default('ansible is not define') }}"
      	
      	#  计算list的最大值、最小值、总数
      	- name: debug list max and min filter
      	  debug: msg="The list max value is {{ list | max }} The list min value is {{ list | min }} The list sum value is {{ list | sum }}"
      	
      	#  生成1000以内随机数,step等于10
      	- name: debug random filter
      	  debug: msg="The list random value is {{ list | random }} and generate a random value is {{ 1000 | random(1,10) }}"
    
      	#  list拼接
      	- name: debug join filter
      	  debug: msg="The join filter value is {{ list | join("+") }}"
    
      	# 字符串替换 
      	- name: rebug replace and regex_replace filter
      	  debug: msg="The replace value is {{ str | replace('t','T')}} The regex_replace value is {{ str | regex_replace('.*tr(.*)$','\\1')}}"
    
  • playbook内置变量

    play book 默认已经内置变量,掌握了这些变量之后,我们就可以很容易实现关于主机相关的逻辑判断了.

    变量 备注
    groups和group_names 1.groups 返回所有的组和host 2. groups[‘consul’] 引用consul组的host 3. group_names 返回主机所在的组
    hostvars 主机变量
    inventory_hostname和inventory _hostname_short 返回主机名、主机名第一部分
    play_hosts 和inventory_dir 运行playbook主机列表、清单目录

    范例说明:
    情况1:一般情况下,获取inventory_hostname和hostname,直接使用{{ invenroty_hostname }} {{ hostname }}
    情况2:针对主机组执行不同操作可以使用下面方式:

    # /etc/ansible/hosts
    [zabbix-server]
    172.22.5.25 hostname=xxx
    [zabbix-proxy]
    172.22.5.25 hostname=yyy
    
    # 获取主机和主机组  
    # 格式:{ungrouped: [], all: [u172.22.5.25], uzabbix-proxy: [u172.22.5.25], uzabbix-server: [u172.22.5.25]}
    {% for host in groups['all'] %}  
    # 获取主机变量
    # 格式:{'host == 主机ip':{变量字典}}
    {{ hostvars[host]['inventory_hostname'] }}  {{ hostvars[host]['hostname'] }}
    {% endfor %}
    
  • playbook tags使用

    对于一个很大的playbook,如果只想运行某个task,必须引入tag.

    tasks:
    
    - yum: name={{ item }} state=installed
      with_items:
         - httpd
         - memcached
      tags:
         - packages
    
    - template: src=templates/src.j2 dest=/etc/foo.conf
      tags:
         - configuration
    

    运行tag:

      ansible-playbook example.yml --tags "configuration,packages"    # run多个tags
      ansible-playbook example.yml --tags packages                   # 只run一个tag
    

    跳过某个task:

      ansible-playbook example.yml --skip-tags configuration
    

    使用场景:
    tags 这个属性也可以被应用到role上,例如:

      roles:
      	- { role: webserver, port: 5000, tags: [ 'web', 'foo' ] }
    

    tags这个属性可以被应用到play上,例如:

      ---
      - name: test1
        hosts: all
        gather_facts: false
        tags:
        	- all
    

    特殊tag

    always: 指定这个tag 后,task任务将永远被执行,而不用去考虑是否使用了–skip-tags标记
    tagged: 当 --tags 指定为它时,则只要有tags标记的task都将被执行,–skip-tags效果相反
    untagged: 当 --tags 指定为它时,则所有没有tag标记的task 将被执行,–skip-tags效果相反
    all: 这个标记无需指定,ansible-playbook 默认执行的时候就是这个标记.所有task都被执行

  • playbook错误处理

    1.忽略错误的命令

    # 只对当前task有用
    - name: this will not be counted as a failure
      command: /bin/false
      ignore_errors: yes
    

    2.控制对失败的定义
    在 Ansible 1.4及之后的版本中提供了如下的方式来指定这样的特殊行为:

    - name: this command prints FAILED when it fails
      command: /usr/bin/example-command -x -y -z
      register: command_result
      failed_when: "'FAILED' in command_result.stderr"
    

    在 Ansible 1.4 之前的版本能通过如下方式完成:

    - name: this command prints FAILED when it fails
      command: /usr/bin/example-command -x -y -z
      register: command_result
      ignore_errors: True
    
    - name: fail the play if the previous command did not succeed
      fail: msg="the command failed"
      when: "'FAILED' in command_result.stderr"
    

    3.覆盖changed结果

    tasks:
    
    	- shell: /usr/bin/billybass --mode="take me to the river"
    	  register: bass_result
    	  changed_when: "bass_result.rc != 2"
    
    	# this will never report 'changed' status
    	- shell: wall 'beep'
    	  changed_when: False
    
  • playbook委任和滚动更新

  1. 委任

    一般情况下,plays是按照顺序执行的; 如果需要在一个plays里,针对某台主机执行某个操作,那么用到委任;

    ---
    - hosts: all
      gather_facts: false
      vars:
    	tmplog: /tmp/connection.log
      tasks:
    	- name: create tmplog
      	  shell: test ! -f {{ tmplog }} && touch {{ tmplog }}
      	  failed_when: false
    	- name: delegate_to
      	  shell: echo "delegate_to . {{ inventory_hostname }} $(hostname) ." >> {{ tmplog }}
      	  run_once: true  # 只执行依次,一般和delegate_to一起使用; 如果单独使用,只会针对inventory清单第一个主机执行:webservers[0]
      	  delegate_to: 172.22.12.13  # 结果会被保存到13这台机器
    
  2. 滚动更新

    - hosts: webservers
      max_fail_percentage: 30   # 最大失败百分比  这个百分比必须被超过,不仅仅是相等.例如如果serial值呗设置为4,并且你希望任务主动在2个系统失败时候放弃.那么这个百分比应该设置为49而不是50.
      serial: 10  # 每次运行主机数量  还可以使用百分比
    

Ansible Facts

facts是ansible采集被管理机器设备信息的一个功能,我们使用setup模块查机器的所有facts信息,用filter查看指定的信息. 整个facts是json格式.

	# 查看主机facts信息
	ansible 172.17.42.101 - m setup
	# 查看ipv4地址
	ansible 172.17.42. 101 -m setup t 'f ilter=ansible all_ipv4_addresses'

扩展factor:可以使用facter或ohai模块扩展facts信息

Ansible role

管理playbook方式,对我们日常使用的playbook目录结构进行一些规范.

roles模块的路径可以在配置文件/etc/ansible/ansible.cfg里roles_path定义.

vim  /etc/ansible/ansible.cfg
roles_path  = /etc/ansible/roles:/usr/share/ansible/roles

playbook调用role.
方法1:

- hosts: websrvs
  remote_user: root
  roles:
  	- mysql
  	- memcached
  	- nginx

方法2:传递变量 k = v 条件测试

- hosts: all
  roles:
  	- { role: nginx, username: nginx, when: "ansible_distribution_major_version == '7' " }
  	- { role: nginx, username: nginx, when: "ansible_distribution_major_version == '7' " }

如果定义了一些tasks,需要在roles之前以及之后执行:

# 需要注意:如果tasks打了tag,那么pre_tasks和post_tasks也需要打上相同的标签.
- hosts: webservers

  pre_tasks:
    - shell: echo 'hello'

  roles:
    - { role: some_role }

  tasks:
    - shell: echo 'still busy'

  post_tasks:
    - shell: echo 'goodbye'

角色依赖:

"角色依赖"可以允许你将其他roles拉取到现有role中.

保存目录: roles 目录下的 meta/main.yml 文件.

示例:

---
dependencies:
  - { role: common, some_parameter: 3 }
  - { role: apache, port: 80 }
  - { role: postgres, dbname: blarg, other_parameter: 12 }
  - { role: '/path/to/common/roles/foo', x: 1 }  // 可以通过绝对路径指定

默认情况下,当作角色依赖的role只能执行依次,并且是递归执行. 但是可以添加allow_duplicates: yes到meta/main.yml中,重复执行.

比如:一个role名为’car’, 将’wheel’的role添加到自己的"角色依赖", “wheel"又有自己的角色依赖"tire”、“brake”.

# role为car的角色依赖
---
dependencies:
- { role: wheel, n: 1 }
- { role: wheel, n: 2 }
- { role: wheel, n: 3 }
- { role: wheel, n: 4 }

# role为wheel的角色依赖
---
allow_duplicates: yes
dependencies:
- { role: tire }
- { role: brake }

最终的执行顺序:
tire(n=1)
brake(n=1)
wheel(n=1)
tire(n=2)
brake(n=2)
wheel(n=2)
...
car

Ansible Galaxy

Ansible官网分享role平台
网址:https://galaxy.ansible.com/
在线安装:ansible-galaxy install 作者.role名字,默认安装在/etc/ansible/roles

你可能感兴趣的:(#,Ansible)