Ansible使用03

1、使用循环迭代

迭代:当有需要重复性执行的任务时,可以使用迭代机制

1.1、迭代 loop (with_items)

对迭代项的引用,固定内置变量名为”item”
要在task中使用with_items给定要迭代的元素列表
注意:ansible2.5版本后,可以用loop代替with_items

列表元素格式:

- 字符串
- 字典
# 范例
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: add several users
      user: name={{ item }} state=present groups=wheel
      with_items:
        - testuser1
        - testuser2
        - testuser3

#上面语句的功能等同于下面的语句
    - name: add several users
      user: name=testuser1 state=present groups=wheel
    - name: add several users
      user: name=testuser2 state=present groups=wheel
    - name: add several users
      user: name=testuser3 state=present groups=wheel
# 安装多个软件包
# 方法1
# cat install_packages.yml
- hosts: webservers
  tasks:
    - name: Installed Httpd Php-fpm Package
      yum: name={{ pack }} state=latest
      vars:
        pack:
          - httpd
          - php-fpm

#方法2
# cat install_packages2.yml
---
- hosts: webservers
  tasks:
    - name: Installed Httpd Php-fpm Package
      yum:
        name={{ item }}
        state=latest
      loop:
        - httpd
        - php-fpm

# cat install_packages3.yml
---
- hosts:websrvs
  remote_user: root

  tasks
    - name: install some packages
      yum: name={{ item }} state=present
      with_items:
        - nginx
        - memcached
        - php-fpm 
# 初始化安装软件包
- name: Installed Packages All
  yum:
    name: "{{ item }}"
    state: present
  loop:
    - nfs-utils
    - net-tools
    - wget
    - rsync
    - tree
    - lrzsz
    - vim
    - unzip
    - httpd-tools
    - bash-completion
    - iftop
    - iotop
    - gzip
    - bzip2
    - xz
    - psmisc
    - bind-utils
    - MySQL-python 

1.2、迭代嵌套子变量

在迭代中,还可以嵌套子变量,关联多个变量在一起使用

---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: add some groups
      group: name={{ item }} state=present
      with_items:
        - nginx
        - mysql
        - apache
    - name: add some users
      user: name={{ item.user }} group={{ item.group }} uid={{item.uid}}
 state=present
      with_items:
        - { user: 'nginx', group: 'nginx',uid: "80" }
        - { user: 'mysql', group: 'mysql' ,uid: "3306"}
        - { user: 'apache', group: 'apache',uid: "8080"}
# 复制多个关联的文件
---
- hosts: websrvs
  vars:
    rsyncd_conf: /etc/rsync.conf
    rsync_pass: /etc/rsync.pass
  tasks:
    - name: Configure Rsyncd Service
      template: src={{ item.src }} dest={{ item.dest }} mode={{ item.mode }}
      with items:
        - {src: './rsyncd.conf.j2', dest: {{ rsyncd_conf }}, mode: '0644' }
        - {src: './rsync.pass.j2', dest: {{ rsync_pass }}, mode: '0600' }
#  批量修改用户密码
---
- hosts: ssh-host
  gather_facts: false
  tasks:
    - name: change user passwd
      user: name={{ item.name }} password={{ item.chpass | password_hash('sha512') }}  update_password=always
      with_items:
        - { name: 'root', chpass: '123456' }
        - { name: 'app', chpass: '654321' }

1.3、until 循环

#until为false时才会执行循环,为true则退出循环
[root@ansible ansible]#cat until.yml
---
- hosts: localhost
  gather_facts: false
  tasks:
    - debug: msg="until"
      until: false
      retries: 3 #默认值即为3次
      delay: 1

1.4、with_lines 逐行处理

[root@ansible ansible]#cat with_lines.yml
- hosts: localhost
  tasks:
    - debug: msg={{ item }}
      with_lines: ps aux

2、条件判断 when

when语句可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用jinja2的语法格式条件测试

# 范例:条件判断
---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: "shutdown RedHat flavored systems"
      command: /sbin/shutdown -h now
      when: ansible_os_family == "RedHat"
# 范例: 对主机名进行条件判断
---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: install nginx
      yum: name=nginx
      when: ansible_fqdn is match ("web*")
# 范例: 判断服务状态决定是否重新启动
---
- hosts: websrvs
  tasks :
    - name: Check nginx Service #检查nginx服务是否是活动的
      command: systemctl is-active nginx
      ignore_ errors: yes
      register: check_nginx

    - name: debug var        #输出var变量内容
      debug:
        var=check_nginx

    - name: Httpd Restart #如果check nginx执行命令结果成功,即check_nginx.rc等于0,则执行重启nginx,否则跳过
      service: name=nginx state=restarted
      when: check_nginx.rc == 0
      #failed_when: check_nginx.rc != 0 #条件不成立才执行,和when相反
# 判断软件是否安装
- hosts: all
  tasks:
    - name: Get Nginx state
      shell:
        cmd: rpm -qa nginx | wc -l
      register: get_nginx
    - name: Install Nginx
      yum:
        name: nginx
      when: get_nginx.stdout == '0'  #0不是数字,必须加引号
# 分组判断
tasks:
  - name: "shut down CentOS 6 and Debian 7 systems"
    shell:
      cmd: /sbin/shutdown -t now
    when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or (ansible_facts['distribution'] == "Ubuntu" and ansible_facts['distribution_major_version'] == "18")
# when的列表形式表示 and 关系
---
#关闭CentOS 7 版本的主机
- hosts: all

  tasks:
    - name: "shut down CentOS 7 systems"
      reboot:
      when:
        - ansible_facts['distribution'] == "CentOS"
        - ansible_facts['distribution_major_version'] == "7"
# 判断是否定义
- hosts: localhost
  tasks:
    - debug: msg="undefined"
      #when: foo is defined
      when: bar is undefined
# 和循环一起使用
- hosts: localhost
  tasks:
    - debug: msg="item > 3"
      with_items: [1,2,3,4,5]
      when: item > 3
# 判断执行状态
---
- hosts: localhost
  tasks:
    - command: /bin/true
      register: result
      ignore_errors: True

    - debug: msg="failed"
      when: result is failed

    - debug: msg="succeeded"
      when: result is succeeded

    - debug: msg="skipped"
      when: result is skipped
# failed_when 满足条件时,则任务失败,和when功能相反
tasks:
  - command: echo failed
    register: result
    failed_when: "'failed' in result.stdout"
    #failed_when: false 不满足条件时,任务正常执行
    #failed_when: true 满足条件时,任务失败
  - debug: msg="echo failed_when"
# 操作系统版本判断
---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: Install httpd on CentOS
      yum: name=httpd state=present
      when: ansible_distribution == "CentOS"
    - name: Install apache2 on Ubuntu
      apt: name=apache2 state=present
      when: ansible_distribution == "Ubuntu"
# 操作系统主版本号判断
---
- hosts: websrvs
  remote_user: root
  tasks:
    - name: add group nginx
      tags: user
      user: name=nginx state=present
    - name: add user nginx
      user: name=nginx state=present group=nginx
    - name: Install Nginx
      yum: name=nginx state=present
    - name: restart Nginx
      service: name=nginx state=restarted
      when: ansible_distribution_major_version == "6"

3、分组 block

当想在满足同样条件下,执行多个任务时,就需要分组。而不再针对每个任务都是用 when

[root@ansible ansible]#cat block.yml
---
- hosts: localhost

  tasks:
    - block:
        - debug: msg="first"
        - debug: msg="second"
      when:
        - ansible_facts['distribution'] == "CentOS"
        - ansible_facts['distribution_major_version'] == "8"

# 相当于下面写法
---
- hosts: localhost
  tasks:
    - debug: msg="first"
      when:
        - ansible_facts['distribution'] == "CentOS"
        - ansible_facts['distribution_major_version'] == "8"

    - debug: msg="second"
      when:
        - ansible_facts['distribution'] == "CentOS"
        - ansible_facts['distribution_major_version'] == "8"

4、changed_when

4.1、关闭 changed 状态

当确定某个task不会对被控制端做修改时但执行结果却显示是黄色的changed状态,可以通过changed_when: false 关闭changed状态

[root@ansible ansible]#cat test_changed.yml
---
- hosts: websrvs

  tasks:
    - name: check sshd service
      shell: ps aux| grep sshd
      changed_when: false  #关闭changed状态

4.2、利用 changed_when 检查task返回结果

changed_when 检查task返回结果,决定是否继续向下执行

[root@ansible ansible]#cat test_changed_when.yml
---
- hosts: websrvs
  tasks:
    - name: install nginx
      yum: name=nginx
    - name: config file
      template: src="nginx.conf.j2" dest="/etc/nginx/nginx.conf"
      notify: restart nginx
    - name: check config
      shell: /usr/sbin/nginx -t
      register: check_nginx_config
      changed_when:
        - check_nginx_config.stdout.find('successful')
# 如果执行结果中有successful字符串,则继续执行,如果没有则停止向下执行
        - false
# nginx -t 每次成功执行是changed状态,关闭此changed状态
    - name: start service
      service: name=nginx state=started enabled=yes
  handlers:
    - name: restart nginx
      service: name=nginx state=restarted

5、滚动执行

管理节点过多导致的超时问题解决方法
默认情况下,Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例,可以使用serial关键字定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次并行执行的主机数占总数的比例

# vim test_serial.yml
---
- hosts: all
  serial: 2
# 每次只同时处理2个主机,将所有task执行完成后,再选下2个主机再执行所有task,直至所
有主机
  gather_facts: False
  tasks:
    - name: task one
      comand: hostname
    - name: task two
      command: hostname
- name: test serail
  hosts: all
  serial: "20%"   #每次只同时处理20%的主机
[root@ansible ansible]#cat test_serial.yml
---
- hosts: websrvs
  serial: 1

  tasks:
    - name: task1
      shell: wall "{{ansible_nodename}} is running task1"
    - name: task2
      shell: wall "{{ansible_nodename}} is running task2"
    - name: task3
      shell: wall "{{ansible_nodename}} is running task3"

6、委派至其它主机执行

利用委托技术,可以在非当前被控主机的其它主机上执行指定操作

[root@ansible ~]#cat delegate.yml
#在192.168.1.22上执行hostname -I,而非当前主机localhost
- hosts: localhost

  tasks:
    - name: show ip address
      command: hostname -I
      delegate_to: 192.168.1.22 #指定当前任务被委派给的目标主机
      delegate_facts: true      #收集被委派的目标主机的facts信息
#在本地执行ifconfig,而非192.168.1.22
[root@ansible ~]#cat delegate2.yml
- hosts: 192.168.1.22

  tasks:
    - name: show ip address
      local_action: command ifconfig  #被委派给控制端ansible主机执行
    - name: show hostname
      shell: hostname
      connection: local   #被委派给控制端ansible主机执行
    - name: kernel version
      shell: uname -r
      delegate_to: localhost   #被委派给控制端ansible主机执行
      run_one: true            #委派任务只执行一次
被委派给控制端ansible主机执行
# 创建普通用户基于ssh key验证
[root@ansible ~]#cat ssh_key_push.yml
# 创建普通用户管理ansible
- hosts: all
  vars:
    - user_name: ssh_demo
  tasks:

# manager
  - name: Create Manager {{ user_name }}
    user:
      name: "{{ user_name }}"
      generate_ssh_key: yes
      ssh_key_bits: 2048
      ssh_key_file: .ssh/id_rsa
    register: user_message
    delegate_to: localhost # 委派给管理端
    run_once: true # 委派任务仅执行一次
# node
  - name: 打印管理用户的key结果
    debug:
      msg: "{{ user_message.ssh_public_key }}"
  - name: 在被控端上创建用户
    user:
      name: "{{ user_name }}"

  - name: 在被控端上创建用户.ssh目录
    file:
      path: "/home/{{ user_name }}/.ssh"
      state: directory
      owner: "{{ user_name }}"
      group: "{{ user_name }}"
      mode: "0700"

  - name: 将管理端 {{ user_name }} 用户的key存储到被控端
    copy:
      content: "{{ user_message.ssh_public_key }}"
      dest: "/home/{{ user_name }}/.ssh/authorized_keys"
      owner: "{{ user_name }}"
      group: "{{ user_name }}"
      mode: "0600"

  - name: 配置被控制端sudo提权,最后追加一行
    lineinfile:
      path: /etc/sudoers
      line: "{{ user_name }} ALL=(ALL) NOPASSWD:ALL"

7、只执行一次

利用 run_once 指令可以只执行一次,而非在所有被控主机都执行

[root@ansible ~]#cat run_once.yml
- hosts: websrvs
  tasks:
    - command: hostname
      run_once: true

8、环境变量

临时修改环境变量

[root@ansible ~]#cat environment.yml
- hosts: localhost
  tasks:
    - shell: echo $PATH
      environment:
        PATH: /usr/local/app/bin:{{ ansible_env.PATH }}

9、yaml 文件的相互调用

9.1、include

利用include 或 include_tasks 可以在某个task中调用其它的只有task内容的yaml文件

[root@ansible ansible]#cat a.yml
---
- hosts: websrvs

  tasks:
    - name: run a job
      command: wall run a job
    - name: excute b.yml
      include: b.yml    #调用另一个yaml文件
      #include_tasks: b.yml #另一种写法
[root@ansible ansible]#cat b.yml
- name: run b job
  command: wall run b job

9.2、import_playbook

还可以将多个包含完整内容的yml文件由一个yml统一调用

[root@ansible ansible]#cat main.yml
- import_playbook: tasks1.yml
- import_playbook: tasks2.yml

[root@ansible ansible]#cat tasks1.yml
---
- hosts: websrvs
  tasks:
    - name: run task1 job
      command: wall run task1 job

[root@ansible ansible]#cat tasks2.yml
---
- hosts: dbsrvs
  tasks:
    - name: run task2 job
      command: wall run task2 job

[root@ansible ansible]#ansible-play main.yml 

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享