Ansible详解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ansible详解相关的知识,希望对你有一定的参考价值。

一、template模板
二、playbook中的条件判断
三、PlayBook中的循环
四、角色(roles)

一、template模板
template使用了Jinjia2格式作为文件模版,进行文档内变量的替换的模块。它的每次使用都会被ansible标记为”changed”状态。基于模板方式生成一个文件复制到远程主机
常用参数:

参数名     是否必须     默认值     选项     说明
backup     no         no     yes/no     建立个包括timestamp在内的文件备份,以备不时之需.
dest     yes             远程节点上的绝对路径,用于放置template文件。//必须是绝对路径
group     no             设置远程节点上的的template文件的所属用户组
mode     no             设置远程节点上的template文件权限。类似Linux中chmod的用法 //group,owner
owner     no             设置远程节点上的template文件所属用户
src     yes             本地Jinjia2模版的template文件位置。 //绝对或者相对路径

一般编程语言都有把自己嵌入到文本的模板语言
    php:直接嵌入
    python:Jinja2 //ansible就是python写的
        
Jinja2 中常用的编程元素
    字面量:字符串,单引号或者双引号引用即可
        数字:整数和浮点数
        列表:[item1,item2,...]
        元祖:(item1,itme2,...) //不可变
        字典:{key1:value1,key2:value2,...}
        布尔型:true/false
    算数运算:
        +,-,*,/,%, //,**     //:表示只要熵
    比较运算:
        ==,!=,>=,<=,<,
        逻辑运算符:
            and,or,not
ansible-doc -s template
利用模板:实现对不同主机的nginx配置成不同的启动processor
    vim nginx.conf.j2
        worker_processes {{ ansible_processor_vcpus }}; //使用模板变量
        listen {{ http_port }};  //自定义变量
    注:这个参数是在setup模板中
        worker_processes {{ ansible_processor_vcpus-1 }}; //可以直接增加或减去
    template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf mode=0644
    template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=bin group=wheel mode="u=rw,g=r,o=r"
    
vim ansible/hosts
    [websrvs]
    192.168.4.100 http_port=888
    192.168.4.116 http_port=808  //使用主机变量
    
[[email protected] ~]# cat nginx.yaml

- hosts: websrvs
  remote_user: root
  tasks:
  - name: install nginx
    yum: name=nginx state=present
  - name: install conf
    template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf mode=0644
    notify: restart nginx
    tags: instconf
  - name: start nginx service 
    service: name=nginx state=started
  handlers:
  - name: restart nginx
    service: name=nginx state=restarted

ansible-playbook --check nginx.yaml
ansible-playbook  nginx.yaml
    注意:6和7的配置nginx配置文件不一样
    执行结果
RUNNING HANDLER [restart nginx]
************************************************
changed: [192.168.4.110]  //发生改变的话,就会执行 restart nginx
changed: [192.168.4.106]
    
handlers:用于当关注的资源发生变化时触发一定的操作。
    “notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作
    取而代之,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。
    
二、playbook中的条件判断
多个条件:and/when/or
1.条件测试:tasks上使用when语句,在tasks上使用,Jinja2的语法格式。根据不同的OS分配不同的机制
    字符串要加引号{单双都可},数值一定不加引号
ansible all -m setup | grep "ansible_distribution" //版本信息
    "ansible_distribution": "CentOS",
    "ansible_distribution_major_version": "6",
    "ansible_distribution_release": "Final",
    "ansible_distribution_version": "6.6",        
    
    tasks:
    - name: install conf file
      template: src=nginx.conf.7
      when: ansible_distribution_major_version == '7'        4tasks:
    - name: install conf file
      template: src=nginx.conf.6
      when: ansible_distribution_major_version == '6'
    
条件测试1: when

- hosts: websrvs
  remote_user: root
  tasks:
  - name: copy file 6
    template: src=/tmp/6.txt dest=/tmp
    when: ansible_distribution_major_version == '6'
    notify: restart nginx
  - name: copy file 7
    template: src=/tmp/7.txt dest=/tmp
    when: ansible_distribution_major_version == '7'
    notify: restart nginx
handlers:
- name: restart nginx
  service: name=nginx state=restarted

2.register
示例,判断sda6是否存在。存在就执行一些相应的脚本,则可以为该判断注册一个register变量,并用它来判断是否存在,存在返回 succeeded, 失败就是 failed.

- name: Create a register to represent the status if the /dev/sda6 exsited
  shell: df -h | grep sda6
  register: dev_sda6_result
  ignore_errors: True
  tags: docker
    
- name: Copy docker-thinpool.sh to all hosts
  copy: src=docker-thinpool.sh dest=/usr/bin/docker-thinpool mode=0755
  when: dev_sda6_result | succeeded
  tags: docker

假如我们想忽略某一错误,通过执行成功与否来做决定,我们可以像这样:
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
    
三、PlayBook中的循环    
循环:迭代,需要重复执行的任务;
例如需要同时安装,nginx,httpd,php-fpm,php-mysql,mariabd等
    对迭代项的引用,固定变量名为"item"
    而后,要在task中使用with_items给定要迭代的元素列表
    列表方法:
        字符串:
        字典:
    
1.标准循环:        

- name: install some packages
  yum: name={{ item }} state=present
  with_items:
  - nginx
  - memcached
  - php-fpm
    //将可以安装多个软件同时安装
循环测试脚本:item    
[[email protected] ~]# cat e.yaml 
- hosts: websrvs
  remote_user: root
  tasks:
  - name: install pkgs 
    yum: name={{ item }} state=present
    with_items:
    - telnet
    - vim
    - tree

    
循环测试脚本3.
    创建三个用户分别属于不同组
[[email protected] ~]# cat f.yaml

- hosts: websrvs
  remote_user: root
  tasks:
  - name: group add
    group: name={{ item }} state=present     //注意:引用的时候使用的是{{ }}没有s,列举参数的时候使用的是复数,items
    with_items:
    - group11
    - group12
    - group13 
  - name: add users
    user: name={{ item.name }}  group={{ item.group }} state=present
    with_items:
    - { name: 'user11', group: 'group11' }
    - { name: 'user12', group: 'group12' }
    - { name: 'user13', group: 'group13' }

==============================
[[email protected] ~]# cat c.yaml

- hosts: testweb
  remote_user: root
  tasks:
  - name: install user
    user: name={{ item.name }} state=present groups={{ item.groups }}
    with_items:
      - { name: 'testuser1', groups: 'wheel' }
      - { name: 'testuser2', groups: 'root' }

//创建testuser1{wheel},testuser2{root}    
注意:
    1.hosts 不是host
    2.严格对齐,列表和内容分开
    3.name: 'user11' //中间必须有空格,字符必须用引号,
    4.目标主机存在user11或其中一个用户的话,也会返回错误
    5.whih_itmes后的内容为下一个key-value (先加空格)

2.嵌套循环:

-name:give users access to multiple databases
 mysql_user:name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password=foo
 with_nested:
  -['alice','bob']        //表示item[0],nested:嵌套
  -['clientdb','employeedb','providerdb']
  
- name: here, 'users' contains the above list of employees
  mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password=foo
  with_nested:
    - "{{users}}"
    - [ 'clientdb', 'employeedb', 'providerdb' ]

[[email protected] ~]# cat c.yaml

- hosts: testweb
  remote_user: root
  tasks:
  - name: install user
    user: name={{ item.name }} state=present groups={{ item.groups }}
    with_items:
      - { name: 'testuser1', groups: 'wheel' }
      - { name: 'testuser2', groups: 'root' }
  - name: give users access to multiple databases
    command: "echo name={{ item[0] }} priv={{ item[1] }} test={{ item[2] }}"
    with_nested:
      - [ 'alice', 'bob' ]
      - [ 'clientdb', 'employeedb', 'providerdb' ]
      - [ '1', '2', ]
    tags: netsted

输出:

skipping: [192.168.2.122] => (item=[u'alice', u'clientdb', u'1'])
skipping: [192.168.2.122] => (item=[u'alice', u'clientdb', u'2'])
skipping: [192.168.2.122] => (item=[u'alice', u'employeedb', u'1'])
skipping: [192.168.2.122] => (item=[u'alice', u'employeedb', u'2'])
skipping: [192.168.2.122] => (item=[u'alice', u'providerdb', u'1'])
skipping: [192.168.2.122] => (item=[u'alice', u'providerdb', u'2'])
skipping: [192.168.2.122] => (item=[u'bob', u'clientdb', u'1'])
skipping: [192.168.2.122] => (item=[u'bob', u'clientdb', u'2'])
skipping: [192.168.2.122] => (item=[u'bob', u'employeedb', u'1'])
skipping: [192.168.2.122] => (item=[u'bob', u'employeedb', u'2'])
skipping: [192.168.2.122] => (item=[u'bob', u'providerdb', u'1'])
skipping: [192.168.2.122] => (item=[u'bob', u'providerdb', u'2'])

3.字典循环
假如你有以下变量:
users:
  alice:
    name: Alice Appleworth
    telephone: 123-456-7890
  bob:
    name: Bob Bananarama
    telephone: 987-654-3210
你想打印出每个用户的名称和电话号码.你可以使用 with_dict 来循环哈希表中的元素:
tasks:
  - name: Print phone records
    debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})"
    with_dict: "{{users}}"

4.遍历文件whith_file,whith_fileglob
with_file 是将每个文件的文件内容作为item的值

- hosts: all
  tasks:
    # first ensure our target directory exists
    - file: dest=/etc/fooapp state=directory
    # copy each file over that matches the given pattern  //注意copy必须要用 “-”
    - copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600
      with_fileglob:
        - /playbooks/files/fooapp/*

with_fileglob 是将每个文件的全路径作为item的值, 在文件目录下是非递归的, 如果是在role里面应用改循环, 默认路径是roles/role_name/files_directory

5.并行数据循环
已知变量:
    alpha: [ 'a', 'b', 'c', 'd' ]
    numbers:  [ 1, 2, 3, 4 ]
如果你想得到’(a, 1)’和’(b, 2)’之类的集合.可以使用’with_together’:
tasks:
    - debug: msg="{{ item.0 }} and {{ item.1 }}"
      with_together:
        - "{{alpha}}"
        - "{{numbers}}"

还有更多的循环介绍方法请参考本文尾部链接地址...

四、角色:(roles)
一个主机可以担任多种角色:
    定义为多个身份,用的时候直接调用该身份即可

角色名就是目录名,任何角色都不能引用自己所属目录之外的其他目录文件
    roles/
        mysql/
        httpd/
        nginx/
        memcached/
    
每个角色,以特定的层级目录结构进行组织: 注意:大多数都是复数"s",除了meta
    mysql/
        files/        存放由copy或script模块等调用的文件
        templates/  template模块查找所需要的模板文件目录;
        handlers/   至少应该包含一个名为main.yml文件
        vars/        至少一个main.yml
        tasks/        基本元素:至少一个名为main.yml的文件,其他的文件需要在此文件中通过include进行包含
        meta/        main.yml,定义当前角色的特殊设定,及其依赖关系
        default/      设定默认变量时使用此目录中的main.yml文件
        
调用角色:
- hosts: websrvs
  remote_user: root
  roles:
  - mysql        //会自动到mysql目录中跑一遍
  - memcached    
  - nginx

mkdir /etc/ansible/roles/nginx/{files,tasks,templates,handlers,vars,default,meta} -pv
cd /etc/ansible/roles/nginx/

1.tasks    
[[email protected] nginx]# cat tasks/main.yml

- name: install nginx pkg
  yum: name=nginx state=present
- name: install conf file
  template: src=nginx.conf dest=/etc/nginx/nginx.conf.test   ///nginx.conf不在同级目录,但是role可以直接识别为template中的文件
- name: start nginx
  service: name=nginx state=started enabled=true

templates 目录中有存放的nginx.conf

2.在其他地方创建nginx.yaml //这个可以放在其他地方

- hosts: websrvs
  remote_user: root
  roles:
  - nginx

执行:  
    ansible-playbook --check nginx.yaml

/etc/ansible/roles/nginx/
├── default
├── files
├── handlers
├── meta
├── tasks
│   └── main.yml
├── templates
│   └── nginx.conf
└── vars

3.添加handler
修改handlers/main.yml
- name: restart nginx        //注意,前面的 - 不可少,代表是handler的一个清单
  service: name=nginx state=restarted

创建tasks/main.yml        

- name: install nginx pkg
  yum: name=nginx state=present
- name: install conf file
  template: src=nginx.conf dest=/etc/nginx/nginx.conf.test
  notify: restart nginx
  tags: instconf
- name: start nginx
  service: name=nginx state=started enabled=true

修改一下nginx.conf //否则不会触发handler
ansible-playbook -t instconf --check g.yaml    

4.变量
[[email protected] yaml]# cat h.yaml

- hosts: websrvs
  remote_user: root
  vars:
  - username: testuser1
  - groupname: testgroup1
  tasks:
  - name: create group
    group: name={{ groupname }} state=present
  - name: create user
    user: name={{ username }} group={{ groupname }} state=present

在playbook中定义变量的方法
    vars:
    - var1: value1
    - var2: value2
ansible-playbook -e "groupname=mygrp1" -e "username=myuser"  --check h.yaml
    //可以覆盖变量,在命令行中定义的变量,会覆盖

5.变量使用,roles中
    vim nginx/vars/main.yml  
        username: nginx
    vim templates/nginx.conf
        user {{ username }} //让nginx以该用户的身份运行
    其他不修改
    ansible

问题:
[[email protected] yaml]# ansible-playbook --check g.yaml
ERROR! The vars/main.yml file for role 'nginx' must contain a dictio
nary of variables
原因:vars/main.yml 前面不需要 - ,和其他的main.yml不一样

ansible-playbook -e "username=adm" --check nginx.yml //假如想改变运行nginx的用户,直接修改即可

6.在playbook中调用角色方法2
vim nginx.yaml
- hosts: websrvs
  remote_user: root
  roles:
  - {role: nginx, username: nginx} //向该角色传递变量

    键role用于指定角色名称,后续的k/v用于传递变量给角色
    
    还可以基于条件测试,实现角色调用;
    例如:
    roles:
    - {role: nginx,when: "ansible_distribution_major_version == '7' }
        //条件满足时,应用该角色
    
[[email protected] yaml]# cat i.yaml
- hosts: websrvs
  remote_user: root
  roles:
  - { role: nginx, username: nginx, when: "ansible_distribution_major_version == '7'" }
//只有在OS为7才会执行

7.安装memcached,占用内从空间为当前可用空间的1/3
 mkdir -pv memcached/{tasks,vars,templates,hanlers}

vim tasks/main.yml 
- name: install pack
  yum: name=memcached state=present
- name: install conf
  template: src=memcached.j2 dest=/etc/sysconfig/memcached
  notify: restart memcached
  tags: memconf
- name: start memcached
  service: name=memcached state=started enabled=true
  
vim templates/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ ansible_memtotal_mb//4  }}"  //除以4,可能是小数,因此// 取出整数
OPTIONS=""
    
vim handlers/main.yml    
- name: restart memcached
  service: name=memcached state=restarted
vim lnm.yaml  //同时调用两个role
- hosts: websrvs
  remote_user: root
  - roles:
  - { role: nginx, when: ansible_distribution_version == '7' }
  - { role: memcached, when: ansible_hostname == 'memcached' }

ansible-playbook -t memconf lnm.yaml
出错原因:
    1.main.yml中,template是没有s的,但是目录名是有s的
    2.notify不是nofify

=======================================================    
yaml和yml格式的区别:
    1.yml不需要hosts,remote_user //这些在yaml中定义
        - name: install pkgs
          yum: name=memcached state=present
                
    2.yaml一定要-hosts,-remote_user
        - hosts: all
          remote_user: root
          roles:
          - { role: nginx,when:ansible_distribution_version == '7' }
ansible all -m setup  //查看所有内置变量
www.ansible.com.cn //站点,

推荐:参考ansible官方role的写法,自行创建role进行练习
http://blog.csdn.net/kellyseeme/article/details/50619562
http://www.ansible.com.cn/docs/playbooks_loops.html
https://www.cnblogs.com/v394435982/p/5593274.html

以上是关于Ansible详解的主要内容,如果未能解决你的问题,请参考以下文章

ansible plugins简介

ansible roles详解+搭建LAMP架构

运维简介&Ansible详解

自动化运维工具——ansible详解案例分享

ansible深入理解和操作——03(roles详解+搭建LAMP架构)

Ansible详解