Ansible常用知识点 – lannyMa.github.io

vagrant destroy
rm -rf .vagrant

安装包

yum install -y libselinux-python

在通过执行 play脚本的过程中 有步骤结束后 必须重启一下 目标电脑

- name: Waiting for server to come back
  local_action: wait_for host={{ ansible_host }} port=22 state=started delay=30 timeout=600
  become: no

关于用户

1,批量创建用用户

ansible all -m shell -a 'useradd apps -m -d /home/apps -s /bin/bash -u 2222'
ansible all -m shell -a 'useradd apps -u 2222'

检查

ansible all -m shell -a "id apps"

2.批量修改密码

$ ansible all -m shell -a 'echo apps:ABCedf123 | chpasswd' #centos 7
$ ansible all -m shell -a 'echo ABCedf123 | passwd --stdin apps' #centos 6

3.批量做互信

$ su - apps && ssh-keygen
$ ansible web -m authorized_key -a "user=apps state=present key="{{ lookup('file', '/home/apps/.ssh/id_rsa.pub') }}"" -k

过滤setup内容

ansible 192.168.14.132 -m setup -a 'filter=ansible_all_ipv4_addresses' -o

ansible 192.168.14.132 -m setup
ansible 192.168.14.132 -m setup -a 'filter=ansible_all_ipv4_addresses'

playbook的过滤: 返回的ansible_eth0是字典.可以过滤

[[email protected] ~]# cat t.yml
- hosts: 192.168.14.133
  tasks:
    - debug: msg="{{ ansible_eth0['device'] }}"

这样就有问题了

ansible all -m setup -a "filter=ansible_eth0['device']"
ansible all -m setup -a "filter=ansible_eth0|ipv4"
- hosts: 192.168.14.132
  tasks:
    - debug: msg="{{ ansible_user_shell }}"

这样ok

ansible all -m setup -a 'filter=ansible_eth[0-2]'

修改内核参数

# 开启路由转发的功能
- sysctl: name="net.ipv4.ip_forward" value=1 sysctl_set=yes

ansible多线程

ansible在多任务下,推荐使用多进程模式的。其实就是用multiprocess做的多进程池 ! -f 10 就是limit 10个任务并发。

书写格式

- hosts: 192.168.14.133
  tasks:
  - debug: msg="hi1"
  - debug: msg="hi2"

也就是很多笔记这样写的原因了.

- lineinfile: dest=/etc/selinux/config regexp=^SELINUX= line=SELINUX=enforcing      # 将以“SELINUX”开头的行换成 “SELINUX=enforcing”
- lineinfile: dest=/etc/sudoers state=absent regexp="^%wheel"                       # 将以 %wheel 开头的行删除
- lineinfile: dest=/etc/hosts regexp='^127.0.0.1' line='127.0.0.1 localhost' owner=root group=root mode=0644
- lineinfile: dest=/etc/httpd/conf/httpd.conf regexp="^Listen " insertafter="^#Listen " line="Listen 8080" # 将以 #Listen 开头行的下面的 以Listen开头的行换成  Listen 8080
- lineinfile: dest=/etc/httpd/conf/httpd.conf insertafter="^#Listen " line="Listen 8080"            # 在 #Listen 开头行的下面的 添加 Listen 8080 新行
- lineinfile: dest=/etc/httpd/conf/httpd.conf regexp="^Listen " insertbefore="^#Listen " line="Listen 8080" # 将以 #Listen 开头行的上面的 以Listen开头的行换成  Listen 8080
- lineinfile: dest=/tmp/testfile line="192.168.1.99 foo.lab.net foo"  # 添加一个新行

可以写一行

  - name: Copy Nginx Software To Redhat Client
    copy: src=nginx-{{ nginx_version }}.tar.gz dest=/tmp/nginx-{{ nginx_version }}.tar.gz owner=root group=root
    when: ansible_os_family == "RedHat" and ansible_distribution_version|int >=6
  - name: Uncompression Nginx Software To Redhat Client
    shell: tar zxf /tmp/nginx-{{ nginx_version }}.tar.gz -C /usr/local/
    when: ansible_os_family == "RedHat" and ansible_distribution_version|int >=6
  - name: Copy Nginx Start Script To Redhat Client
    template: src=nginx dest=/etc/init.d/nginx owner=root group=root mode=0755
    when: ansible_os_family == "RedHat" and ansible_distribution_version|int >=6
  - name: Copy Nginx Config To Redhat Client
    template: src=nginx.conf dest=/usr/local/nginx-{{ nginx_version }}/conf/ owner=root group=root mode=0644
    when: ansible_os_family == "RedHat" and ansible_distribution_version|int >=6
  - name: Copy Nginx Vhost Config to RedHat Client
    template: src=vhost.conf dest=/usr/local/nginx-{{ nginx_version }}/conf/vhost/ owner=root group=root mode=0644
    when: ansible_os_family == "RedHat" and ansible_distribution_version|int >=6

ansible安装zabiix

---
  - hosts: "{{ host }}"
    remote_user: "{{ user }}"
    gather_facts: false
    tasks:
        - name: Install the 'Development tools' package group
          yum:
              name: "@Development tools"
              state: present
          tags:
              - Dev_tools

        - name: Install packages
          yum: state=present name={{ item }}
          with_items:
              - gcc
              - gcc-c++
              - autoconf
              - automake
              - libxml2-devel
              - sysstat
              - vim
              - iotop
              - unzip
              - htop
              - iotop
              - strace
              - wget
              - tar
              - libselinux-python
              - rsync
              - rdate
          tags:
              - packages
        - name: Selinux modify disabled
          lineinfile:
              dest: /etc/selinux/config
              regexp: '^SELINUX='
              line: 'SELINUX=disabled'
          tags:
              - testselinux

        - name: Modify lineinfile
          lineinfile:
              dest: "{{ item.dest }}"
              state: present
              regexp: "{{ item.regexp }}"
              line: "{{ item.line }}"
              validate: 'visudo -cf %s'
          with_items:
                # - {
                #   dest: "/etc/zabbix/zabbix_agentd.conf",
                #   regexp: "^Include",
                #   line: "nn###Add includenInclude=/etc/zabbix/zabbix_agentd.conf.d/*.conf" }
              - {
                dest: "/etc/sudoers",
                regexp: "^Defaults    requiretty",
                line: "# Defaults    requiretty" }
          tags:
              - testline

        - name: Copy configuration file
          copy:
              src='#'" /etc/init.d/zabbix_agentd",
                dest: "/etc/init.d/zabbix_agentd",
                mode: "0755"}
          tags:
              - testcopy
        - name: Create a directory
          file: path={{ item }} state=directory mode=0750
          with_items:
              - /etc/sudoers.d
          tags:
              - testdir

        - name: Looping over Fileglobs
          copy: src={{ item }} dest=/etc/sudoers.d/ owner=root mode=0440
          with_fileglob:
              - /etc/sudoers.d/*
          tags:
              - test_fileglobs

        - name: synchronization of src on the control machine to dest on the remote hosts
          synchronize:
            src='#'" /etc/zabbix",
                dest: "/etc/"}
              - {
                src='#'" /usr/local/zabbix",
                dest: "/usr/local/"}
          tags:
              - sys_dir

        - name: Ensure two job that runs of crontab
          cron:
            name: "{{ item.name }}"
            minute: "{{ item.minute}}"
            job: "{{ item.job}}"
          with_items:
                - {
                  name: "Time synchronization",
                  minute: "10",
                  job: "/usr/bin/rdate -s 192.168.1.163 > /dev/null 2>&1"}
                - {
                  name: "a job vmstat_output",
                  minute: "1",
                  job: "vmstat 1 10 > /tmp/vmstat_output"}
                - {
                  name: "a job iostat_output",
                  minute: "1",
                  job: "bin/bash /usr/local/zabbix/script/iostat.sh"}
          tags:
              - testcron

        - name: Starting zabbix_agentd
          shell: /usr/local/zabbix/script/zabbix_agent.sh
          tags:
              - starting_zabbix_aqentd

        - name: Install omsa
          shell: sh /usr/local/zabbix/script/dell.sh
          tags:
              - install_omsa

02ansible常用

ansible配置文件

yum install -y libselinux-python
/etc/ansible/ansible.cfg(主要参数解析,这里主要有两个需要解释的选项)
  library        = /usr/share/ansible  #ansible模块存放位置
  remote_tmp     = $HOME/.ansible/tmp  #客户端临时文件的路径(ansible通过ssh通道在远程主机上根据playbook生成对应的临时python代码,
                                       #然后远程执行这一段临时代码,
                                       #并在执行完成后删除,
                                       #我们在执行的时候可以去客户端执行ps命令看到这个过程的)
/etc/ansible/hosts  (主机配置文件)
  文件的配置格式为
  [definename]
  host or hostname
  #在定义主机的时候,主要需要注意的有
  1) 要以主机名定义客户机的时候要保证server端能够正确的解析这个主机名;
  2) 主机定义的时候可以有很多匹配规则,如web-[a-z].host.com,db-[01:30].host.com;

ansible命令格式

#命令格式:
ansible all -m copy -a 'src=/etc/my.cnf dest=/etc/'

几个重要参数的含义: -i #指定inventory文件(主机定义文件) 栗子: ansible -i test all -m ping all #表示在host文件中定义的所有的主机,可以替换成响应的组名或IP地址

针对于主机可以使用匹配规则(所有的匹配都基于配置文件中的主机) IP地址: ansible 192.168.239.132 栗子: ansible -i test 192.168.14.13* -m ping IP匹配: ansible 192.168.239.* IP匹配: ansible * 组匹配: ansible 组名:&hostname <表示这个组跟其他组的一个主机> 组匹配: ansible 组名:!hostname <表示这个组但是出除去这个组的这个主机> 类似的匹配还很多,几乎能想到的匹配都能支持,具体参照http://docs.ansible.com/intro_patterns.html -m #指定使用哪个模块,默认采用command模块 -a #指定模块的参数,每个模块都有相应的模块参数 -u #指定远端机器的用户

查看帮助

列出模块

ansible-doc -l

查看某一模块详情

ansible-doc ping

查看参数

ansible-doc -s ping

参数

ansible all -m ping -o -f 3

初始化目录结构

ansible-galaxy init test1

常用模块

command   <执行linux命令的>
  #ansible all  -m command -a 'ifconfig'

copy     <实现文件复制>
  #ansible all  -m copy -a 'src=/etc/my.cnf dest=/etc/my.cnf owner=mysql group=mysql' #owner group 可以根据选择自定义的决定要不要指定

file    <实现目录文件权限的修改/创建与删除>
  #ansible all -m file -a 'dest=/etc/rsync.d/secrets  mode=600 owner=root group=root'
  #ansible all -m file -a 'dest=/data/install mode=755 owner=root grou=root state=directory' #创建这个不存在的目录
  #ansible all -m file -a 'dest=/data/tmp state=absent'  #删除这个目录

yum     <使用yum进行软件包的管理>
  #ansible all -m yum -a 'name=httpd state=installed'

  更新包:
  ansible all -m yum -a 'name=htop state=latest'

service   <管理linux系统服务>
  #ansible all -m service -a 'name=httpd state=started'
  #state选项主要有:started,stopped,restarted,reloaded

cront      <管理linux计划任务>
  #ansible all -m cron -a 'name="you autoupdate" weekday="2" minute=0 hour=12 user="root" job="/usr/sbin/yum-autoupdate" cron_file=ansible_yum-autoupdate'
  栗子:
  ansible all -m cron -a "name=ntpdate job=ntpdate ntp.pool.ntp.org" hour=*/2 user="root"

帮助

ansible-doc modulename

常见模块主要参数

yum模块中:
关于yum模块有几个状态参数<即state=>
  latest    #安装最新的一个版本
  installed #安装一个包
  removed   #卸载已经安装的软件包
  present   #安装指定的软件包<需要提供软件包的位置>,如
#yum: name=http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present
#yum: name=/usr/local/src/nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present
关于name参数的选项<即name=>


  *       #匹配所有的已经安装的包
#ansible all -m yum -a 'name=* state=latest'  #表示更新所有的已经安装的rpm包


  @       #表示安装软件包组
#ansible all -m yum -a '[email protected] Tools state=present'

service模块中: #state选项有start,restart,stop ansible 192.168.14.132 -m service -a "name=nginx state=restarted enabled=yes"

cron,模块中: name #相当于计划任务的注释说明,会在crontab里面以注释行的形式出现 关于时间的定义 #minute #指定分的格式:*(每分)(默认值) */5(每五分) 01(01分) 15(15分) #hour #指定小时的格式: *(每小时)(默认值) */5(没五小时) 01(1点) 15(15点) #day #指定天的格式: *(每天)(默认值) */5(每五天) 01(每个的1日) (0-31) #month #指定月的格式: *(每月)(默认值) */5(每五个月) 01(一月) (1-12) #weekday #指定周的日期: *(每周)(默认值) */2(每两周) 1(周一)(1-7) reboot #这个计划任务是否等下次重启后再生效 user #指定哪个用户的计划任务

playbook语法格式

ansible-playbook

资产

  • 存在父子关系
  • 调用资产时,可以给资产传变量
192.168.14.132 ansible_ssh_pass="123456"
192.168.14.132 ansible_ssh_pass="123456"

[docker]
192.168.14.13[2:3]

[docker:vars]
ansible_ssh_pass="123456"

[ansible:children]
docker

playbook基本骨架

host: web
tasks:
  - name: install nginx
    yum: xxx
  - name: xxx
    shell: xxx

官网playbook几个书写栗子

- hosts: node14
  remote_user: root
  tasks:
    - name: xxx
      yum: name=openldap
    - name: xxx
      yum: name=nginx

- hosts: node67
  remote_user: root
  tasks: #clean
    - name: Keeps scm-data.tar.gz of 7 days in local
      shell: find /data/backup/scm-data/ -name "*.tar.gz"  -type f -mtime +7|xargs rm -f

带 handler

---
- hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum: name=httpd state=latest
  - name: write the apache config file
    template: src=/srv/httpd.j2 dest=/etc/httpd.conf
    notify:
    - restart apache
  - name: ensure apache is running (and enable it at boot)
    service: name=httpd state=started enabled=yes
  handlers:
    - name: restart apache
      service: name=httpd state=restarted

---
- hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum:
      name: httpd
      state: latest
  - name: write the apache config file
    template:
      src: /srv/httpd.j2
      dest: /etc/httpd.conf
    notify:
    - restart apache
  - name: ensure apache is running
    service:
      name: httpd
      state: started
  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted

---
- hosts: webservers
  remote_user: root
tasks:
  - name: ensure apache is at the latest version
    yum: name=httpd state=latest
  - name: write the apache config file
    template: src=/srv/httpd.j2 dest=/etc/httpd.conf
- hosts: databases
  remote_user: root
tasks:
  - name: ensure postgresql is at the latest version
    yum: name=postgresql state=latest
  - name: ensure that postgresql is started
    service: name=postgresql state=started

adhoc转换为playbook

host: web
tasks:
  - name: "nginx install"
    yum: name=nginx state=present
  - name: enable nginx&start nginx
    service: name=nginx state=restarted enabled=yes
ansible 192.168.14.132 -m service -a "name=nginx state=restarted enabled=yes"

playbook实用选项

列出主机和task

ansible-playbook web.yaml --list-hosts
ansible-playbook web.yaml --list-tasks

缩小执行范围

ansible-playbook web.yaml --limit=192.168.14.132
ansible-playbook web.yaml -l 192.168.14.132

以这个用户身份运行

ansible-playbook web.yaml --become-user=maotai
-u REMOTE_USER, --user=REMOTE_USER
    connect as this user (default=None)
--become-user=BECOME_USER
    run operations as this user (default=root)

playbook试验

step1错误 则step2不会被执行

- hosts: web
  tasks:
    - name: step1
      shell: cat /tmp/1.txt
    - name: step2
      shell: cat /etc/hosts

返回内容看不到具体值 只看到结果 但是adhoc可以看到执行输出内容

- hosts: web
  tasks:
    - name: step1
      shell: ls /tmp
    - name: step2
      shell: cat /etc/hosts

定义变量

- hosts: test
  strategy: debug
  gather_facts: no
  vars:
    var1: value1
  tasks:
    - name: wrong variable
      ping: data={{ wrong_var }}

debug模块

平时我们在使用ansible编写playbook时,经常会遇到错误,很多时候有不知道问题在哪里 。这个时候可以使用-vvv参数打印出来详细信息,不过很多时候-vvv参数里很多东西并不是我们想要的,这时候就可以使用官方提供的debug模块来查找问题出现在哪里。

- hosts: 192.168.14.132
  tasks:
    - name: debug test one host
      debug:
        msg: "System {{ inventory_hostname }} has uuid {{ ansible_product_uuid }}"

msg: 默认是”hello world”,赋值形式 + msg: + msg=

template模块

把/mytemplates/foo.j2文件经过填写参数后,复制到远程节点的/etc/file.conf,文件权限相关略过

- template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode=0644

跟上面一样的效果,不一样的文件权限设置方式

- template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode="u=rw,g=r,o=r"

rgistry变量–输出字典

- hosts: 192.168.14.132
  tasks:
    - name: registry vars
      shell: hostname
      register: info
    - name: display var
      debug: msg="The regis var is {{ info }}"

rgistry变量–过滤结果

- hosts: 192.168.14.132
  tasks:
    - name: registry vars
      shell: hostname
      register: info
    - name: display var
      debug: msg="The regis var is {{ info['stdout'] }}"

1,变量-通过hosts

给某台定义变量

192.168.14.132 key=132
192.168.14.133 key=133 #优先级比组高

为一个组所机器定义变量

[nginx]
192.168.14.13[2:3]
[nginx:vars]
key=nginx
- hosts: web
  tasks:
    - name: var via hosts
      debug: msg="the {{ inventory_hostname }} value is {{ key }}"

同时给某一主机和组指定变量,key的结果 132 133

#cat /etc/ansible/hosts
192.168.14.132 key=132
192.168.14.133 key=133
[web]
192.168.14.132
192.168.14.133

[web:vars]
key=webserver
#cat y1.yaml
- hosts: web
  tasks:
    - name: var via var-files
      debug: msg="the {{ inventory_hostname }} value is {{ key }}"

给组指定变量,key的结果webserver

#192.168.14.132 key=132
#192.168.14.133 key=133
[web]
192.168.14.132
192.168.14.133

[web:vars]
key=webserver
#cat y1.yaml
- hosts: web
  tasks:
    - name: var via var-files
      debug: msg="the {{ inventory_hostname }} value is {{ key }}"

2,变量–通过文件vars_file

#cat var.yaml
key: hello world  # 变量名为key
#cat y1.yaml
- hosts: web
  vars_files:
    - var.yaml
  tasks:
    - name: var via var-files
      debug: msg="the {{ inventory_hostname }} value is {{ key }}"

3,变量定义–通过命令行传入

[[email protected] an]# cat y3.yaml
- hosts: web
  tasks:
    - name: var via var-files
      debug: msg="the {{ inventory_hostname }} value is {{ key }}"
ansible-playbook y3.yaml -e "key=KEY"
ansible-playbook y3.yaml -e "@var.yaml" #通过指定的文件传入

4,变量定义–playbook中使用vars

- hosts: web
  vars:
    key: Ansible
  tasks:
    - name: var via vars
      debug: msg="the {{ inventory_hostname }} value is {{ key }}"

5,变量定义–通过vars_prompt

- hosts: web
  vars_prompt:
    - name: "one"
      prompt: "pls input one value"
      private: no
    - name: "two"
      prompt: "pls input two value"
      default: good
      private: yes
  tasks:
    - name: display one value
      debug: msg="one value is {{ one }}"
    - name: display two value
      debug: msg="one value is {{ two }}"

执行过程

[[email protected] an]# ansible-playbook y4.yaml
pls input one value: one
pls input two value [good]:   #这就是private的好处,输入的时候不显示

PLAY [web]

注: 如果输入为空,则 key=“”,可以执行成功

playbook循环

简单循环item

key是item

[[email protected] an]# cat y5.yaml
- hosts: web
  tasks:
    - name: debug
      debug: msg="name----->{{ item }}"
      with_items:
        - one
        - tow
        - three

item是字典类型

item数据理性是python类型.

[[email protected] an]# cat y6.yaml
- hosts: web
  gather_facts: False
  tasks:
    - name: debug loops
      debug: msg="key----->{{ item.key }} value----->{{ item.value }}"
      with_items:
        - {key: "one",value: "VALUE1"}
        - {key: "two",value: "VALUE2"}

随机选一个

从上到下,first优先

template调用自定义变量

ansible分支when ansible循环

# cat httpd.j2
{{ key }}

# cat y3.yaml
- hosts: 192.168.14.132
  vars:
    key: ansible
  tasks:
    - name: template调用var
      template: src=./httpd.j2 dest=/root/an/httpd2.conf
验证
# cat httpd2.conf
ansible

03ansible模块

role

按照anisble标准创建目录,目录间联系不需要管.如下面,include即可以执行了

ansible-galaxy init somedir
$ tree
.
├── roles
│   └── common
│       ├── handlers
│       ├── meta
│       └── tasks
│           └── main.yml
└── test.yml

5 directories, 2 files
$ cat roles/common/tasks/main.yml
- name:
  debug: msg="helllllllo"
$ cat test.yml
- hosts: 192.168.14.132
  roles:
    - common

cron模块

ansible all -m cron -a 'name="jutest" hour="5" job="/bin/bash /tmp/test.sh"'
效果如下:
* 5 * * *  /bin/bash /tmp/test.sh

template模块

把/mytemplates/foo.j2文件经过填写参数后,复制到远程节点的/etc/file.conf,文件权限相关略过

- template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode=0644

跟上面一样的效果,不一样的文件权限设置方式

- template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode="u=rw,g=r,o=r"

setup模块

通过命令获取所有的系统信息 搜集主机的所有系统信息

ansible all -m setup

搜集系统信息并以主机名为文件名分别保存在/tmp/facts 目录

ansible all -m setup --tree /tmp/facts

#搜集和内存相关的信息

nsible all -m setup -a 'filter=ansible_*_mb'

搜集网卡信息

ansible all -m setup -a 'filter=ansible_eth[0-2]'

archive模块

支持的格式:gz,bz2,zip,tar 0,压缩单个目录得到最根的目录

- hosts: 192.168.x.x
  tasks:
    - name: 测试压缩模块
      archive:
        path: /opt/test
        dest: /root/an/test.tar
        format: tar
解压后得到: test

1.压缩多个目录

- hosts: 192.168.x.x
  tasks:
    - name: 测试压缩模块
      archive:
        path:
            - /opt/test
            - /tmp/test2/test3/1.txt
        dest: /root/an/test.tar
        format: tar
解压后得到: /opt/test
            /tmp/test2/test3/

注:空文件或目录压缩不计入压缩范围.

发邮件

- hosts: node67
  remote_user: root
  tasks:
    - name: cat hosts
      shell: cat /etc/hosts
      register: info

    - name: sendMail to op
      mail:
        host: smtp.sina.com
        port: 25
        username: [email protected]
        password: 123456
        from: [email protected] (lanny)
        to: maotai <[email protected]>
        # cc: John Doe <[email protected]>, Suzie Something <[email protected]>
        # cc: Mao Tai2 <[email protected]>, Mao Tai3 <[email protected]>
        # attach: /etc/fstab /etc/hosts
        subject: Backup-scm successfully
        body: 'System {{ ansible_hostname }}-192.168.x.x {{ info['stdout_lines'] }}'

synchronize模块

rsync同步

#ansible test -m synchronize -a "src=/data/adminshell/ dest=/data/adminshell/ "

rsync无差异同步

#ansible test -m synchronize -a "src=/data/adminshell/ dest=/data/adminshell/ delete=yes"
"msg": "*deleting   test.txtn"

排除同步

#同步目录,排除某个文件
ansible test -m synchronize -a "src=/data/adminshell/ dest=/data/adminshell/ rsync_opts="--exclude=exclude.txt" "
#同步目录,排除多个文件
ansible test -m synchronize -a "src=/data/adminshell/ dest=/data/adminshell/ rsync_opts="--exclude=*.conf,--exclude=*.html,--exclude=test1" "

相对copy模块 * 1.copy没mode,只能发出去 * 2.copy是全量的

replace模块

ansible 192.168.14.133 -m replace -a "dest=/etc/hosts regexp='^Old' replace='New' backup=yes"
#备份效果
[[email protected] tmp]# ll /etc/hosts*
-rw-r--r--  1 root root 350 Jul 20 16:56 /etc/hosts
-rw-r--r--  1 root root 312 Jul 20 16:43 /etc/[email protected]:44:03~
-rw-r--r--  1 root root 350 Jul 20 16:55 /etc/[email protected]:56:53~

注: copy fetch模块也有backup的功能.

copy模块

#拷贝本地的/etc/hosts 文件到myserver主机组所有主机的/tmp/hosts(空目录除外),如果使用playbooks 则可以充分利用template 模块
ansible myserver -m copy -a "src=/etc/hosts dest=/tmp/hosts mode=600 owner=ju group=ju"
#file 模块允许更改文件的用户及权限
ansible webservers -m file -a "dest=/srv/foo/a.txt mode=600"
ansible webservers -m file -a "dest=/srv/foo/b.txt mode=600 owner=ju group=ju"
#使用file 模块创建目录,类似mkdir -p
ansible webservers -m file -a "dest=/path/to/c mode=755 owner=ju group=ju state=directory"
#使用file 模块删除文件或者目录
ansible webservers -m file -a "dest=/path/to/c state=absent"

raw模块

- hosts: node14-scm
  remote_user: root
  vars:
  - sfpath: "/backup/scm-data/*_$(date +%F -d '-1 day')_scmdata.tar.gz"
  - dfpath: "/data/backup/scm-data/"
  tasks:
    #清理远端的压缩包,远端进保留一天scm-data.tar.gz  2,远端打包并将压缩包取回
    - name: Clean | keeping [scm-server-node14]'s /backup/scm-data dir only have one tar pkg
      shell: find /backup/scm-data/ -name "*.tar.gz"  -type f -mtime -7 |xargs rm -f

    - name: Package | make /root/.scm to tar.gz package on node14
      raw:
           cd /backup/scm-data && 
           rm -rf .scm && 
           cp -r /root/.scm /backup/scm-data/ && 
           tar zcf /backup/scm-data/`ifconfig|sed -n '2p'|awk -F':' '{print $2}'|awk '{print $1}'`_$(date +%F -d '-1 day')_scmdata.tar.gz .scm

- hosts: node1
  task:
    - name: 清理/tmp
      raw:
           cd /tmp && 
           rm -rf *

tags

如果你有一个很大的playbook,而你只想run其中的某个task,这个时候tags是你的最佳选择。 此时若你希望只run其中的某个task,这run 的时候指定tags即可

tasks:

    - yum: name={{ item }} state=installed
      with_items:
         - httpd
         - memcached
      tags:
         - packages

    - template: src=templates/src.j2 dest=/etc/foo.conf
      tags:
         - configuration
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 结合使用 tags 这个属性也可以被应用到role上,例如:

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

tags和include结合使用

- include: foo.yml tags=web,foo

这样,fool.yml 中定义所有task都将被执行

blockinfile模块

- hosts: 192.168.14.133
  tasks:
  - name: Edit profile JDK conf
    blockinfile:
      dest: /etc/profile
      backup: yes
      marker: "# {mark} jdk config"
      content: |
        JAVA_HOME=/usr/java/jdk1.8.0_66
        CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar
        PATH=$JAVA_HOME/bin:$ANT_HOME/bin:$PATH
        export JAVA_HOME CLASSPATH PATH
#cat profile
...
# BEGIN jdk config
JAVA_HOME=/usr/java/jdk1.8.0_66
CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar
PATH=$JAVA_HOME/bin:$ANT_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
# END jdk config

lineinfile模块

ansible实现sed功能

替换目标文件中的某行

- hosts: 192.168.14.132
  tasks:
    - name: seline modify enforcing
      lineinfile:
        dest: /etc/selinux/config
        regexp: '^SELINUX='
        line: 'SELINUX=enforcing'

删除一行

- hosts: 192.168.14.132
  tasks:
    - name: 删除一行
      lineinfile:
        path: /root/an/httpd2.conf
        state: absent
        regexp: '^an'

在目标文件某行前添加一行

- name: httpd.conf modify 8080
  lineinfile:
     dest: /opt/playbook/test/http.conf
     regexp: '^Listen'
     insertbefore: '^#Port'
     line: 'Listen 8080'
  tags:
   - http8080
验证:
[[email protected] test]# cat http.conf
#Listen 12.34.56.78:80
#Listen 80
Listen 8080
#Port

在目标文件某行后添加一行

- name: httpd.conf modify 8080
      lineinfile:
        dest: /opt/playbook/test/http.conf
        regexp: '^Listen'
        insertafter: '^#Port'
        line: 'Listen 8080'
      tags:
        - http8080
验证:
[[email protected] test]# cat http.conf
#Listen 12.34.56.78:80
#Listen 80
#Port
Listen 8080

lookup templates

#lookups.j2
worker_process {{ ansible_processor_cores }}
IPaddress {{ ansible_eth0.ipv4.address }}
- hosts: 192.168.14.132
  vars:
    # contents相当于f.read,将文件读取成了1个大的字符串
    contents: "{{ lookup('template','./lookups.j2') }}"
  tasks:
  - name: debug lookups
    # 使用jinja2对文件进行遍历.
    debug: msg="The contents is {% for i in contents.split("n") %} {{ i }} {% endfor %}"

# 结果 由此可见是模板渲染后的结果做了行遍历
#"msg": "The contents is  worker_process 1  IPaddress 192.168.14.132     "

authorized_key建互信

ansible web -m authorized_key -a "user=root state=present key="{{ lookup('file', '/root/.ssh/id_rsa.pub') }}"" -k

ansible all -m authorized_key -a "user=root state=present key="{{ lookup('file', '/root/.ssh/id_rsa.pub') }}"" -k    # 将本地root的公钥导入到远程用户root的authorized_keys里
ansible all -m authorized_key -a "user=root state=present key="{{ lookup('file', '/home/test/.ssh/id_rsa.pub') }}"" -k # 将本地test的公钥导入到远程用户root的authorized_keys里
vi /etc/ansible/ansible.cfg
host_key_checking = False

script模块

相对shell,好处是script可以集中管理脚本,过程是:将shell下发到目标机执行. 而shell必须将shell下发下去执行

$ cat s.sh
#!/bin/sh

/bin/tar -xf /tmp/opt.tar.gz -C /tmp

执行过程

$ansible 192.168.14.133 -m script -a '/tmp/s.sh' -o
192.168.14.133 | SUCCESS => {"changed": true, "rc": 0, "stderr": "Shared connection to 192.168.14.133 closed.rn", "stdout": "", "stdout_lines": []}

结果

$ ll
total 128
drwxr-xr-x 6 root root    157 Jul 20 17:07 opt
-rw-r--r-- 1 root root 128187 Jul 21 16:29 opt.tar.gz

unarchive 解压缩

可以将本地的压缩包直接解压到远程 可以将远程压缩包直接解压

  src
  copy  yes|no  # yes:默认,压缩包在本地,src=本地压缩包路径,dest=解压到远程路径;no远程主机已存在压缩包,src=远程压缩包路径,dest=解压到远程路径
  creates  # 创建文件目录,当文件存在就不执行
  dest
  group
  mode
  owner
  unarchive: src=foo.tgz dest=/var/lib/foo
  unarchive: src=/tmp/foo.zip dest=/usr/local/bin copy=no
  unarchive: src=/tmp/test.tar.gz dest=/opt/tmp/ creates=/opt/tmp/ copy=no

04ansible when

ansible条件-简单的条件

tasks:
  - name: "shut down Debian flavored systems"
    command: /sbin/shutdown -t now
    when: ansible_os_family == "Debian"
    # note that Ansible facts and vars like ansible_os_family can be used
    # directly in conditionals without double curly braces

ansible条件-or

tasks:
  - name: "shut down CentOS 6 and Debian 7 systems"
    command: /sbin/shutdown -t now
    when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or
          (ansible_distribution == "Debian" and ansible_distribution_major_version == "7")

ansible条件-and

tasks:
  - name: "shut down CentOS 6 systems"
    command: /sbin/shutdown -t now
    when:
      - ansible_distribution == "CentOS"
      - ansible_distribution_major_version == "6"

ansible条件-jinja2

tasks:
  - command: /bin/false
    register: result
    ignore_errors: True

  - command: /bin/something
    when: result|failed

  # In older versions of ansible use |success, now both are valid but succeeded uses the correct tense.
  - command: /bin/something_else
    when: result|succeeded

  - command: /bin/still/something_else
    when: result|skipped

ansible-playbook高级

参考

任务委派

1.在14.132执行, 14.133上没任何变动

- hosts: 192.168.14.133
  tasks:
    - shell: "echo '1.1.1.1 www.abc.com' >> /etc/hosts"
      delegate_to: 192.168.14.132

2.先在14.133上输出字符串,然后再触发让14.132去干活(即修改hosts)

$ cat t.yml
- hosts: 192.168.14.133
  tasks:
    - debug: msg="hello node2"
    - shell: "echo '1.1.1.1 www.abc.com' >> /etc/hosts"
      delegate_to: 192.168.14.132

验证:

[[email protected] ~]# cat /etc/hosts
...
1.1.1.1 www.abc.com

任务委派功能还可以用于以下场景: > + 在部署之前将一个主机从一个负载均衡集群中删除。 > + 当你要对一个主机做改变之前去掉相应 dns 的记录 > + 当在一个存储设备上创建 iscsi 卷的时候 > + 当使用外的主机来检测网络出口是否正常的时候

本地操作功能 –local_action

Ansible 默认只会对控制机器执行操作,但如果在这个过程中需要在 Ansible 本机执行操作呢?细心的读者可能已经想到了,可以使用 delegate_to( 任务委派 ) 功能呀。没错,是可以使用任务委派功能实现。不过除了任务委派之外,还可以使用另外一外功能实现,这就是 local_action 关键字。

- name: add host record to center server
  local_action: shell 'echo "192.168.1.100 test.xyz.com " >> /etc/hosts'

当然您也可以使用 connection:local 方法,如下:

- name: add host record to center server
  shell: 'echo "192.168.1.100 test.xyz.com " >> /etc/hosts'
  connection: local

委托者的facts

默认情况下, 委托任务的facts是inventory_hostname中主机的facts, 而不是被委托机器的facts. 在ansible 2.0 中, 设置delegate_facts为true可以让任务去收集被委托机器的facts.

- hosts: app_servers
  tasks:
    - name: gather facts from db servers
      setup:
      delegate_to: "{{item}}"
      delegate_facts: True
      with_items: "{{groups['dbservers'}}"

该例子会收集dbservers的facts并分配给这些机器, 而不会去收集app_servers的facts

RUN ONCE

通过run_once: true来指定该task只能在某一台机器上执行一次. 可以和delegate_to 结合使用

- command: /opt/application/upgrade_db.py
  run_once: true
  delegate_to: web01.example.org

指定在”web01.example.org”上执行这 如果没有delegate_to, 那么这个task会在第一台机器上执行

异步和轮询

Ansible 有时候要执行等待时间很长的操作, 这个操作可能要持续很长时间, 设置超过ssh的timeout. 这时候你可以在step中指定async 和 poll 来实现异步操作

async 表示这个step的最长等待时长, 如果设置为0, 表示一直等待下去直到动作完成.

poll 表示检查step操作结果的间隔时长.

例1:

---
- name: Test
  hosts: localhost
  tasks:
    - name: wair for
      shell: sleep 16
      async: 10
      poll: 2

结果:

TASK: [wair for] **************************************************************
ok: [localhost]
<job 207388424975.101038> polling, 8s remaining
ok: [localhost]
<job 207388424975.101038> polling, 6s remaining
ok: [localhost]
<job 207388424975.101038> polling, 4s remaining
ok: [localhost]
<job 207388424975.101038> polling, 2s remaining
ok: [localhost]
<job 207388424975.101038> polling, 0s remaining
<job 207388424975.101038> FAILED on localhost

这个step失败, 因为操作时间超过了最大等待时长

例2:

---
- name: Test
  hosts: localhost
  tasks:
    - name: wair for
      shell: sleep 16
      async: 10
      poll: 0

结果:

TASK: [wair for] **************************************************************
<job 621720484791.102116> finished on localhost

PLAY RECAP ********************************************************************

poll 设置为0, 表示不用等待执行结果, 该step执行成功

例3:

---
- name: Test
  hosts: localhost
  tasks:
    - name: wair for
      shell: sleep 16
      async: 0
      poll: 10

结果:

# time ansible-playbook xiama.yml
TASK: [wair for] **************************************************************
changed: [localhost]

PLAY RECAP ********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0


real    0m16.693s

async设置为0, 会一直等待直到该操作完成.

Play执行时的并发限制 一般情况下, ansible会同时在所有服务器上执行用户定义的操作, 但是用户可以通过serial参数来定义同时可以在多少太机器上执行操作.

  • name: test play hosts: webservers serial: 3

webservers组中的3台机器完全完成play后, 其他3台机器才会开始执行, serial参数在ansible-1.8以后就开始支持百分比.

最大失败百分比 默认情况下, 只要group中还有server没有失败, ansible就是继续执行tasks. 实际上, 用户可以通过”max_fail_percentage” 来定义, 只要超过max_fail_percentage台的server失败, ansible 就可以中止tasks的执行.

- hosts: webservers
  max_fail_percentage: 30
  serial: 10
Note: 实际失败机器必须大于这个百分比时, tasks才会被中止. 等于时是不会中止tasks的.

任务暂停

image

ansible-playbook

参考

一、一个简单的示例

下面给出一个简单的ansible-playbook示例,了解下其构成。

# cat user.yml
- name: create user
  hosts: all
  user: root
  gather_facts: false
  vars:
  - user: "test"
  tasks:
  - name: create  user
    user: name="{{ user }}"

三、playbook的构成

playbook是由一个或多个“play”组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中即可以让它们联同起来按事先编排的机制同唱一台大戏。其主要有以下四部分构成

playbooks组成: - Target section: 定义将要执行 playbook 的远程主机组 - Variable section: 定义 playbook 运行时需要使用的变量 - Task section: 定义将要在远程主机上执行的任务列表 - Handler section: 定义 task 执行完成以后需要调用的任务

而其对应的目录层为五个,如下:

一般所需的目录层有:(视情况可变化) - vars 变量层 - tasks 任务层 - handlers 触发条件 - files 文件 - template 模板

2、任务列表和action

tasks:
  - name: make sure apache is running
    service: name=httpd state=running
在众多模块中只有command和shell模块仅需要给定一个列表而无需使用“key=value”格式例如
tasks:
  - name: disable selinux
    command: /sbin/setenforce 0  如果命令或脚本的退出码不为零可以使用如下方式替代
tasks:
 - name: run this command and ignore the result
    shell: /usr/bin/somecommand || /bin/true
或者使用ignore_errors来忽略错误信息
tasks:
  - name: run this command and ignore the result
    shell: /usr/bin/somecommand
    ignore_errors: True

image

3,给task添加触发器notify,触发handler

- name: template configuration file
  template: src=template.j2 dest=/etc/foo.conf
  notify:
  - restart memcached
  - restart apache
handler是task列表这些task与前述的task并没有本质上的不同。
handlers:
  - name: restart memcached
    service: name=memcached state=restarted
  - name: restart apache
    service: name=apache state=restarted

ansible-galaxy

[Ansible Galaxy]https://ipaas.com.cn/blog/post/seanzhau/7185546cc669)

ansible-galaxy是一个工具,我们可以利用它快速的创建一个标准的roles目录结构,还可以通过它在https:/galaxy.ansible.com上下载别人写好的roles,直接拿来用。

通过ansible-galaxy初始化一个roles的目录结构,方法如下:

ansible-galaxy init /etc/ansible/roles/websrvs

安装别人写好的roles:

ansible-galaxy install -p /etc/ansible/roles bennojoy.mysql

列出已安装的roles:

ansible-galaxy list

查看已安装的roles信息:

ansible-galaxy info bennojoy.mysql

卸载roles:

ansible-galaxy remove bennojoy.mysql