运维工具的分类:
    agentless:无代理端程序,通过依赖于SSH协议,安全性有限;
        ansible,fabric,saltstack;
    agent:基于代理程序实现安全通信;
        puppet,Zabbix,func; 
主要功能:
    1.批量的系统部署;
    2.批量的程序部署;
    3.批量的运行命令;

ansible的特性:
    1.模块化:ansible核心仅仅提供了一组命令行工具(框架),真正的运维管理功能需要各个模块来实现;
    2.基于python语言开发实现的,需要有Paromiko,jinja2,PyYMAL三个关键模块的支持;
    3.Agentless,部署简单,默认依靠SSH协议;
    4.支持自定义模块;
    5.支持playbook;
    6.快速失败,执行效率O(1),幂等性;

ansible应用程序的结构:
    ansible核心:提供核心命令行工具;
    Host Inventory:主机清单,指定ansible能够操纵和管理的主机列表及分组情况;
    Playbook:剧本,可以重复执行或同时执行一个或多个任务的具有YAML语言的格式的文件文件;
    一般,文件的后缀名称为:.yml或.yaml;
    modules:
        核心模块;
        自定义模块;
    插件(Connection Plugins):
        连接器插件:在与后端被管设备进行通信之前用于建立通信会话连接的插件;
        邮件发送的插件
        日志记录的插件

ansible的安装:
    到目前为止,ansible的rpm包只能由EPEL源提供;

    使用yum命令来安装即可;(CentOS 7.5(1803))
        # yum install ansible

ansible的程序环境:
    主配置文件:/etc/ansible/ansible.cfg
    主机清单文件:/etc/ansible/hosts
    主程序:
        /usr/bin/ansible
        /usr/bin/ansible-doc
        /usr/bin/ansible-playbook

主机清单的文件格式:
    1.单纯的主机列表:
        将主机名或IP地址按照每行一个的格式写入/etc/ansible/hosts文件;
    2.主机分组:
        [websrvs]
        IP_ADDR1
        ...
        HOSTNAME1
        ...

        [dbsrvs]
        IP_ADDR2
        ...
        HOSTNAME2
        ...

        [wang]
        172.16.75.2
    3.主机范围表示:
        web01-web10
        web[01:10]
        172.16.72.[2:10]
首先主控设备和被控设备之间要实现基于密钥的ssh通信:
[root@3 ~]# ssh-keygen -t rsa -P '123456' 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Created directory '/root/.ssh'.
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:YVqUBbBJLgN1aFuVZdlzMuR+ahlj+UVHh0Bex4XATko root@3
The key's randomart image is:
+---[RSA 2048]----+
|  ....+o+*+*=o.+*|
|   .o+.+o.EoB.+oo|
|   .oo+ +. +o=  o|
|    .o + ..... ..|
|      . S   * . .|
|           . B . |
|            + .  |
|           .     |
|                 |
+----[SHA256]-----+
[root@3 ~]# ls .ssh
id_rsa  id_rsa.pub
[root@3 ~]# ssh-copy-id -i .ssh/id_rsa.pub [email protected]
[root@3 ~]# ssh-copy-id -i .ssh/id_rsa.pub [email protected]
[root@3 ~]# ssh-copy-id -i .ssh/id_rsa.pub [email protected]
[root@3 ~]# ssh-copy-id -i .ssh/id_rsa.pub [email protected]
[root@3 ~]# ssh 172.16.75.5  //登录尝试
Enter passphrase for key '/root/.ssh/id_rsa': 
各主机都可登陆后,编辑/etc/ansible/hosts文件
规定出我们所提供的服务器,保存即可:
172.16.75.4
172.16.75.5
172.16.75.6
172.16.75.13
我们用ansible中的ping模块,ping一下我们的被控设备,因为我们之前设置了ssh密码所以在ping的时候,
每一台被控设备被ping通之前都需要输入一次密码,之后再ping的时候,就不需要了:
[root@3 ~]# ansible all -m ping
172.16.75.5 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
172.16.75.13 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
172.16.75.4 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
172.16.75.6 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
还可以将被控设备进行分组:
[root@3 ~]# vim /etc/ansible/hosts
[test1]
172.16.75.4
172.16.75.5

[test2]
172.16.75.6
172.16.75.13
这时,我们在以组为单位进行测试:
[root@3 ~]# ansible test1 -m ping
Enter passphrase for key '/root/.ssh/id_rsa': //要输入ssh中设置的密码
172.16.75.4 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
Enter passphrase for key '/root/.ssh/id_rsa': 
172.16.75.5 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
当然在主控设备和被控设备之间实现基于密钥的ssh通信时我们可以不设置密码,
这样在实验的时候就简单方便多了。

ansible命令:
    ansible - Define and run a single task 'playbook' against a set of hosts

    格式:
        ansible  [options]

        常用选项:
            -a MODULE_ARGS, --args MODULE_ARGS
                在使用某些模块时,用于指定该模块所需要的参数;
            -e, --extra-vars
                在ansible的命令行中用于设置执行ansible任务时的自定义变量;
            -m MODULE_NAME, --module-name MODULE_NAME
                在执行ansible任务时,所选择使用的模块;如果未给出该选项,默认选择使用"command"模块;
            -C, --check
                并不真正的在被管主机上运行任务,而是测试看结果是否会发生改变;

ansible-doc命令:
    ansible-doc - plugin documentation tool
    格式:
        ansible-doc [-l|-F|-s] [options] [-t  ] [plugin]

        常用选项:
            -l, --list:
                列表显示当前所有可用的ansible模块;
            -s, --snippet:
                获取模块的使用规则,其结果通常是剧本中的用法;

常用的ansible模块:
    1.command模块:
        Executes a command on a remote node

        示例:
            [root@3 ~]# ansible all -m command -a "useradd testuser01"
            [root@3 ~]# ansible all -m command -a "id testuser01"

    2.shell模块(使用管道或者通配符时使用此模块 ):
        Execute commands in nodes.

        示例:
            [root@3 ~]# ansible all -m shell -a "echo qhdlink | passwd --stdin testuser01"

    3.user模块:
        Manage user accounts

        常用的参数:
            name: 指定欲管理的用户账户名称;必选参数;
            create_home: 是否为用户创建家目录,除非显式给出"no"值,默认创建;
            system: 是否将用户创建为系统用户;
            uid: 为指定的用户指定一个固定的UID;
            group: 为指定的用户指定一个主要组;
            groups: 为指定的用户添加一个附加组;
            state: 此次ansible任务的执行状态;必选参数;
                present:创建;
                absent:删除;
            force: 当state=absent时,该任务相当于"userdel --force";
            remove: 当state=absent时,该任务相当于"userdel --remove | userdel -r";
            shell: 为指定的用户指定一个默认登录shell;

        示例:
            [root@3 ~]# ansible all -m user -a "name=testuser02 system=yes uid=333 
            create_home=no shell=/sbin/nologin state=present"
            [root@3 ~]# ansible all -m user -a "name=testuser01 state=absent remove=yes"

    4.group模块:
        Add or remove groups

        常用的参数:
            gid: 为指定组名的组指定一个GID;
            name: 指定组名;必选参数
            state: 此次ansible任务的执行状态;必选参数;
                present:创建;
                absent:删除;
            system: 是否将组设置为系统组;

        示例:
            [root@3 ~]# ansible all -m group -a "name=wzc system=yes gid=345 state=present"
            [root@3 ~]# ansible all -m group -a "name=wzc state=absent"

    5.copy模块:
        Copies files to remote locations

        常用的参数:
            dest: 此次ansible的复制任务的目标位置,必须用绝对路径表示;
                注意:
                    1.如果src指定的路径是目录,则dest必须指定目录;
                    2.如果dest的路径是以"/"做结尾或src是一个目录时,若dest不存在,则创建;
                    3.如果src和dest都是文件,若dest表示的路径中有目录不存在,则不会创建并报告错误;
            src: 此次ansible的复制任务的源文件的位置,可以使用相对路径也可以使用绝对路径;
                注意:
                    1.如果src所指定的路径是以"/"结尾,仅复制该目录下的文件到目标位置;
                    2.如果src所指定的路径不以"/"结尾,就会复制所有路径中包含的目录的内容到目标位置;

类似于rsync;
mode: 设置目标位置文件的权限属性;
owner: 设置目标位置文件的属主;
group: 设置目标位置文件的属组;
force: 如果目标位置文件已经存在,是否覆盖;默认为yes;

        示例:
            [root@3 ~]# ansible test1 -m copy -a "content='hello\neverybody\n' force=yes 
            dest=/tmp/hello.txt mode=0600 owner=testuser02"
            [root@3 ~]# ansible test1 -m copy -a "src=/etc/yum.repos.d/CentOS-Base.repo 
            dest=/tmp owner=ftp group=daemon mode=0640"

    6.cron模块:
        Manage cron.d and crontab entries

        常用的参数:
            name: cron任务的名称;在删除时必须指定,创建时如果不指定,则自动创建一个新的cron任务;
            month: 月份;
            day: 天;
            hour: 小时;
            minute: 分钟;
            weekday: 星期;
            job: 此次定义的工作的具体内容,即:命令;
            state: 
                present:创建;
                absent:删除;
            user: 指定此次修改的计划任务的所有者;

        示例:
        在各被控设备中定制计划任务:
        [root@3 ~]# ansible all -m cron -a "name='Update Time' minute=*/10 job='/usr/sbin/ntpdate 
        172.16.72.3 &> /dev/null' state=present"
        172.16.75.4 | CHANGED => {
            "changed": true, 
            "envs": [], 
            "jobs": [
                "Update Time"
            ]
        }
        172.16.75.13 | CHANGED => {
            "changed": true, 
            "envs": [], 
            "jobs": [
                "Update Time"
            ]
        }
        172.16.75.6 | CHANGED => {
            "changed": true, 
            "envs": [], 
            "jobs": [
                "Update Time"
            ]
        }
        172.16.75.5 | CHANGED => {
            "changed": true, 
            "envs": [], 
            "jobs": [
                "Update Time"
            ]
        }
        到被控设备中查看结果:
        [root@4 ~]# crontab -l
        #Ansible: Update Time
        */10 * * * * /usr/sbin/ntpdate 172.16.72.3 &> /dev/null

        在各被控设备中删除已经定制计划任务:
        [root@3 ~]# ansible all -m cron -a "name='Update Time'  state=absent"
        172.16.75.5 | CHANGED => {
            "changed": true, 
            "envs": [], 
            "jobs": []
        }
        172.16.75.6 | CHANGED => {
            "changed": true, 
            "envs": [], 
            "jobs": []
        }
        172.16.75.13 | CHANGED => {
            "changed": true, 
            "envs": [], 
            "jobs": []
        }
        172.16.75.4 | CHANGED => {
            "changed": true, 
            "envs": [], 
            "jobs": []
        }
        到被控设备中查看结果:
        [root@4 ~]# crontab -l
        [root@4 ~]#    //没有内容,以为我们在上述操作中包计划任务删除了

    7.hostname模块:
        Manage hostname

        参数:
            name: 指定主机名;

        注意:如果直接拿来设置主机名,会导致所有主机同名;绝大多数情况下,会结合变量进行主机名的设置,
        以保证不同的主机被设置不同的主机名;

        示例:
        [root@3 ~]# ansible 172.16.75.4 -m hostname -a "name=www.wzc4.com"
        172.16.75.4 | SUCCESS => {
            "ansible_facts": {
                "ansible_domain": "wzc4.com", 
                "ansible_fqdn": "www.wzc4.com", 
                "ansible_hostname": "www", 
                "ansible_nodename": "www.wzc4.com"
            }, 
            "changed": true, 
            "name": "www.wzc4.com"
        }
        [root@3 ~]# ansible 172.16.75.5 -m hostname -a "name=www.wzc5.com"
        172.16.75.5 | SUCCESS => {
            "ansible_facts": {
                "ansible_domain": "wzc5.com", 
                "ansible_fqdn": "www.wzc5.com", 
                "ansible_hostname": "www", 
                "ansible_nodename": "www.wzc5.com"
            }, 
            "changed": true, 
            "name": "www.wzc5.com"
        }
        [root@3 ~]# ansible 172.16.75.6 -m hostname -a "name=www.wzc6.com"
        172.16.75.6 | SUCCESS => {
            "ansible_facts": {
                "ansible_domain": "wzc6.com", 
                "ansible_fqdn": "www.wzc6.com", 
                "ansible_hostname": "www", 
                "ansible_nodename": "www.wzc6.com"
            }, 
            "changed": true, 
            "name": "www.wzc6.com"
        }
        设置后我可以到相应的被控设备中进行查看:
        [root@6 ~]# hostname
        www.wzc6.com

    8.※script模块:
        Runs a local script on a remote node after transferring it

        示例:
        [root@3 ~]# vim wang.sh
        #!/bin/bash
        #
        RESULT=$[8*8]
        echo $RESULT > /tmp/result.txt
        [root@3 ~]# bash wang.sh
        [root@3 ~]# ls /tmp
        result.txt
        ssh-KVa0apXzLIGs
        systemd-private-ffdc1f169b5043de8d909b21e2879be4-chronyd.service-SVcLuO
        systemd-private-ffdc1f169b5043de8d909b21e2879be4-colord.service-NcK0Ud
        systemd-private-ffdc1f169b5043de8d909b21e2879be4-cups.service-nJ3xkU
        systemd-private-ffdc1f169b5043de8d909b21e2879be4-httpd.service-XyJKo5
        systemd-private-ffdc1f169b5043de8d909b21e2879be4-mariadb.service-NN5DhV
        systemd-private-ffdc1f169b5043de8d909b21e2879be4-rtkit-daemon.service-6DybaR
        tracker-extract-files.0
        yum_save_tx.2018-07-26.15-38.MSxPB9.yumtx
        yum_save_tx.2018-08-13.15-25.8tKTAR.yumtx
        yum_save_tx.2018-08-13.16-43.xOgRwj.yumtx
        [root@localhost ~]# cat /tmp/result.txt 
        64
        在被控设备中,执行主控设备中的脚本:
        [root@3 ~]# ansible test1 -m script -a "/root/wang.sh"
        172.16.75.4 | CHANGED => {
            "changed": true, 
            "rc": 0, 
            "stderr": "Shared connection to 172.16.75.4 closed.\r\n", 
            "stderr_lines": [
                "Shared connection to 172.16.75.4 closed."
            ], 
            "stdout": "", 
            "stdout_lines": []
        }
        172.16.75.5 | CHANGED => {
            "changed": true, 
            "rc": 0, 
            "stderr": "Shared connection to 172.16.75.5 closed.\r\n", 
            "stderr_lines": [
                "Shared connection to 172.16.75.5 closed."
            ], 
            "stdout": "", 
            "stdout_lines": []
        }
        在被控设备中查看结果:
        [root@4 ~]# cat /tmp/result.txt
        64

    9.service模块:
        Manage services

        常用的参数:
            name: 指定要管理的服务的名称;
            enabled: 设置要管理的服务是否随操作系统启动而启动;
            state: 
                started
                stopped
                restarted
                reloaded

        示例:
        在没被指定任务的主机中查看3306端口是否打开:
        [root@5 ~]# ss -tnl
        State      Recv-Q Send-Q Local Address:Port               Peer Address:Port              
        LISTEN     0      128     *:111                 *:*                  
        LISTEN     0      5      192.168.122.1:53                  *:*                  
        LISTEN     0      128     *:22                  *:*                  
        LISTEN     0      128    127.0.0.1:631                 *:*                  
        LISTEN     0      100    127.0.0.1:25                  *:*                  
        LISTEN     0      128    :::111                :::*                  
        LISTEN     0      128    :::22                 :::*                  
        LISTEN     0      128       ::1:631                :::*                  
        LISTEN     0      100       ::1:25                 :::*     
        我们可以在主控设备中打开服务:
        [root@3 ~]# ansible 172.16.75.5 -m service -a "name=mariadb enabled=yes state=started"
        172.16.75.5 | CHANGED => {
        "changed": true, 
        "enabled": true, 
        "name": "mariadb", 
        "state": "started", 
        "status": {
         ……
         }
        在被控设备中查看服务是否开启:
        [root@5 ~]# ss -tnl
        State      Recv-Q Send-Q Local Address:Port               Peer Address:Port              
        LISTEN     0      50      *:3306      //服务正常开启          *:*                  
        LISTEN     0      128     *:111                 *:*                  
        LISTEN     0      5      192.168.122.1:53                  *:*                  
        LISTEN     0      128     *:22                  *:*                  
        LISTEN     0      128    127.0.0.1:631                 *:*                  
        LISTEN     0      100    127.0.0.1:25                  *:*                  
        LISTEN     0      128    :::111                :::*                  
        LISTEN     0      128    :::22                 :::*                  
        LISTEN     0      128       ::1:631                :::*                  
        LISTEN     0      100       ::1:25                 :::*

    10.yum模块:
        Manages packages with the `yum' package manager

        常用的参数:
            name: 指定此次要管理的程序包的名称,还可以加上版本号;如果想要一次管理多个程序包,
            可以使用","分隔程序包名称的列表;
            state:
                `present' or `installed', `latest' :都表示安装;
                `absent' or `removed' :都表示卸载;
        示例:
            [root@3 ~]# ansible websrvs -m yum -a "name=httpd,php-fpm state=present"

    11.※setup模块:
        Gathers facts about remote hosts:关于远程主机的变量的相关内容

        示例:
        [root@3 ~]# ansible 172.16.75.5 -m setup
        172.16.75.5 | SUCCESS => {
            "ansible_facts": {
                "ansible_all_ipv4_addresses": [
                    "192.168.122.1", 
                    "192.168.68.54", 
                    "172.16.75.5"
                ], 
                "ansible_all_ipv6_addresses": [
                    "fe80::f72a:4d4b:bc9f:f31f", 
                    "fe80::2a67:77ba:109f:558f", 
                    "fe80::8268:e185:d13d:2712", 
                    "fe80::d493:483c:f1c9:2bd5"
                ], 
                "ansible_apparmor": {
                    "status": "disabled"
                }, 
                "ansible_architecture": "x86_64", 
                "ansible_bios_date": "07/02/2015", 
                "ansible_bios_version": "6.00",... //很多,这里就不写了

YAML
YAML介绍

    YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言,
    包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等。
    Clark Evans在2001年在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。

    YAML Ain't Markup Language,即YAML不是XML。不过,在开发的这种语言时,YAML的意思其实是:
    "Yet Another Markup Language"(仍是一种标记语言)。其特性:
        YAML的可读性好
        YAML和脚本语言的交互性好
        YAML使用实现语言的数据类型
        YAML有一个一致的信息模型
        YAML易于实现
        YAML可以基于流来处理
        YAML表达能力强,扩展性好

    更多的内容及规范参见http://www.yaml.org

YAML语法
    YAML的语法和其他高阶语言类似,并且可以简单表达列表、数据字典、键值对等数据结构。
    其结构(Structure)通过空格来展示,列表里的项用"-"来代表,数据字典里的键值对用":"分隔。

list

    列表的所有元素均使用“-”打头,例如:
    # A list of tasty fruits
    - Apple
    - Orange
    - Strawberry
    - Mango

dictionary

    字典通过key与value进行标识,例如:
    ---
    # An employee record
    name: Example Developer
    job: Developer
    skill: Elite

    也可以将key:value放置于{}中进行表示,例如:
    ---
    # An employee record
    {name: Example Developer, job: Developer, skill: Elite}

下面是一个示例。

    name: John Smith
    age: 41
    gender: Male
    spouse:
        name: Jane Smith
        age: 37
        gender: Female
    children:
        -   name: Jimmy Smith
            age: 17
            gender: Male
        -   name: Jenny Smith
            age 13
            gender: Female

    YAML文件扩展名通常为.yaml,如example.yaml。

playbook的核心元素:基本结构;
    - hosts: 
        remote_user: 
        vars: 
            var1: value1
            var2: value2
        tasks: 
            - name1: 
                module_name: 
                tags: 
                notify: 
            - name2
                ...
            ...
        roles: 
            - role_name1
            - role_name2
            ...
        handlers: 

ansible-playbook命令:
    ansible-playbook - Runs Ansible playbooks, executing the defined tasks on the targeted hosts.

    格式:
        ansible-playbook [options] playbook.yml [playbook2 ...]

        常用选项:
            -C, --check
                测试运行剧本中任务,不做任何改变;
            -e, --extra-vars
                在命令行中设置额外的变量或者修改某个指定的变量的值;
            -t, --tags
                指明只运行那些与指定的标记匹配的任务;

测试playbook的示例(:
[root@localhost ansible]# vim test.yml

  • hosts: all //指定被控主机
    remote_user: root //远程连接被控主机所使用的用户
    tasks:
    • name: create group gwzc11 //我们创建这个任务的目的(就是为这个任务取个名字)
      group: name=gwzc1 gid=455 system=yes //所调用的模块,以及调用模块后所给出参数
    • name: create user uwzc1
      user: name=uwzc1 uid=456 system=yes create_home=no group=gwzc1
      [root@3 ansible]# ansible-playbook --check test.yml

PLAY [all] *****

TASK [Gathering Facts] *****
ok: [172.16.75.4]
ok: [172.16.75.13]
ok: [172.16.75.6]
ok: [172.16.75.5]

TASK [create group gwzc1] **
changed: [172.16.75.6]
changed: [172.16.75.5]
changed: [172.16.75.13]
changed: [172.16.75.4]

TASK [create user uwzc1] ***
changed: [172.16.75.4]
changed: [172.16.75.13]
changed: [172.16.75.5]
changed: [172.16.75.6]

PLAY RECAP *****
172.16.75.13 : ok=3 changed=2 unreachable=0 failed=0
172.16.75.4 : ok=3 changed=2 unreachable=0 failed=0
172.16.75.5 : ok=3 changed=2 unreachable=0 failed=0
172.16.75.6 : ok=3 changed=2 unreachable=0 failed=0

利用playbook安装nginx应用:

  • hosts: 172.16.75.6
    remote_user: root
    tasks:
    • name: install nginx
      yum: name=nginx state=present
      [root@3 ansible]# ansible-playbook --check test.yml

PLAY [172.16.75.6] *****

TASK [Gathering Facts] *****
ok: [172.16.75.6]

TASK [install nginx] ***
changed: [172.16.75.6]

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

handlers:
    处理器;
    事实上,handlers也是定义了任务,但该任务并非每次都必然被执行,只是在特殊的条件下触发执行;
    在ansible中,特殊条件一般是指handlers接收到了其他任务发送的通知信息;

变量:variables
变量的定义方式:
1.facts:利用setup模块从被管设备上取回的变量,可以直接使用;
注意:如果使用ansible命令行工具向被管设备执行任务时,默认并没有可用的facts变量;只有在运行ansible-playbook命令执行playbook时,首先会获取被管设备上的facts变量,从而可以直接调用;

    如果想要调用facts变量,都需要在playbook中调用;

 2.在hosts inventory中定义变量:
    1) 为不同的主机定义同一变量的不同变量值;

    示例:在/etc/ansible/hosts文件中定义;
            [root@localhost ansible]# vim hosts 

            # This is the default ansible 'hosts' file.
            #
            # It should live in /etc/ansible/hosts
            #
            #   - Comments begin with the '#' character
            #   - Blank lines are ignored
            #   - Groups of hosts are delimited by [header] elements
            #   - You can enter hostnames or ip addresses
            #   - A hostname/ip can be a member of multiple groups

            [test1]
            172.16.75.4  nname=www1.wang.com
            172.16.75.5  nname=www2.wang.com

            [wang]
            172.16.75.4
            [root@3 ansible]# ansible test1 -m hostname -a "name={{ nname }}"
            172.16.75.4 | SUCCESS => {
                    "ansible_facts": {
                            "ansible_domain": "wang.com", 
                            "ansible_fqdn": "www1.wang.com", 
                            "ansible_hostname": "www1", 
                            "ansible_nodename": "www1.wang.com"
                    }, 
                    "changed": true, 
                    "name": "www1.wang.com"
            }
            172.16.75.5 | SUCCESS => {
                    "ansible_facts": {
                            "ansible_domain": "wang.com", 
                            "ansible_fqdn": "www2.wang.com", 
                            "ansible_hostname": "www2", 
                            "ansible_nodename": "www2.wang.com"
                    }, 
                    "changed": true, 
                    "name": "www2.wang.com"
            }

2) 向某个主机组中传递变量值:

                示例:
                    [test1:vars]
                    ngx_port=80

                    在templates中调用生效;

3.在ansible命令行或ansible-playbook命令行中通过-e选项传递变量值;
                -e var1=value1 -e var2=value2 ...

4.在YAML格式的playbook文件中定义并引用(只能使用以下格式);
                    vars:
                        var1: value1
                        var2: value2
                        ...

5.在roles中定义变量;

6.在playbook中调用roles时,向roles传递变量值;

7.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 (new in version 1.8)
        sudo 命令路径(适用于1.8及以上版本)

    ansible_connection
        与主机的连接类型.比如:local, ssh 或者 paramiko. Ansible 1.2 以前默认使用 paramiko.1.2 
        以后默认使用 'smart','smart' 方式会根据是否支持 ControlPersist, 来判断'ssh' 方式是否可行.

    ansible_ssh_private_key_file
        ssh 使用的私钥文件.适用于有多个密钥,而你不想使用 SSH 代理的情况.

    ansible_shell_type
        目标系统的shell类型.默认情况下,命令的执行使用 'sh' 语法,可设置为 'csh' 或 'fish'.

    ansible_python_interpreter
        目标主机的 python 路径.适用于的情况: 系统中有多个 Python, 或者命令路径不是"/usr/bin/python",
        比如  \*BSD, 或者 /usr/bin/python
        不是 2.X 版本的 Python.我们不使用 "/usr/bin/env" 机制,因为这要求远程用户的路径设置正确,
        且要求 "python" 可执行程序名不可为 python以外的名字(实际有可能名为python26).
        与 ansible_python_interpreter 的工作方式相同,可设定如 ruby 或 perl 的路径....

        变量调用的方式:
            {{ var_name }}

        12.template模块:
            Templates a file out to a remote server

                模板文件:纯文本文件,嵌套了某种编程语言脚本代码的文本文件;

                python语言将自身代码嵌套进纯文件文件的脚本语言,Jinja2;以"j2"后缀命名的文件;

                在jinja2脚本文件中,表达式的最简单的表现形式,称为"字面量";

                字面量:
                    字符串:通常是使用单引号或双引号引用的内容;
                    列表:可变化的数据结构;
                        [item1, item2, ...]
                    元组:不可变数据结构;
                        (item1, item2, ...)
                    字典:
                        {key1: value1, key2: value2, ...}
                    布尔型:true | false

                操作符号:
                    算术运算符:+, -, *, /, %, //, **
                    比较操作符:==, !=, <, >, <=, >=
                    逻辑运算符:and, or, not

            template模块的常用参数:
                src:在ansible主控设备上的Jinja2格式的模板文件的路径;.j2
                dest:将模板文件复制到远程主机后的文件路径;
                owner、group、mode、setype等;

ansible的角色(roles):
角色:一个完整的应用服务的配置集合;

默认情况下,存放各个角色的目录是:/etc/ansible/roles

在上述目录中,创建一个与要管理的应用服务相关或相同的目录名称即可;
    /etc/ansible/roles/httpd
    /etc/ansible/roles/nginx
    ...

在每个应用服务项目中,都需要有一套严格标准的目录结构:
    /etc/ansible/roles/nginx/{files/,templates/,tasks/,handlers/,vars/,meta/,default/}/main.yml

    files/:
        用于存放由copy模块或script模块所用到的静态文件;
    templates/:
        template模块查找和复制所需的Jinja2格式的模板文件的目录;
        因此,存储于该目录中的文件都必须以".j2"为文件的后缀名称;
    tasks/:
        定义ansible所执行的任务所使用的yml文件的集合;至少要包含一个main.yml文件作为访问入口;
        如果该目录中有其他的yml格式的文件,需要在main.yml文件中以include命令将其包含;
    handlers/:
        定义处理器时所使用的yml文件的集合;至少要包含一个main.yml文件作为访问入口;
        如果该目录中有其他的yml格式的文件,需要在main.yml文件中以include命令将其包含;
    vars/:
        定义自定义变量时所使用的yml文件的集合;至少要包含一个main.yml文件作为访问入口;
        如果该目录中有其他的yml格式的文件,需要在main.yml文件中以include命令将其包含;
    meta/:
        定义当前角色的某些特定属性和依赖关系;至少要包含一个main.yml文件作为访问入口;
        如果该目录中有其他的yml格式的文件,需要在main.yml文件中以include命令将其包含;
    default/:
        定义默认变量时使用的目录,至少要包含一个main.yml文件作为访问入口;
        如果该目录中有其他的yml格式的文件,需要在main.yml文件中以include命令将其包含;

memcached角色配置示例:
1.完善目录结构:
[root@3 ansible]# mkdir -pv /etc/ansible/roles/memcached/{files,templates,tasks,handlers,vars,meta,default}
2.在tasks目录中创建主任务playbook:main.yml

  • name: install memcached
    yum: name=memcached state=present
    tags: instmemc
  • name: provide config file
    template: src=memcached.j2 dest=/etc/sysconfig/memcached
    tags: provcfg
    notify: restart memcached
  • name: start memcached service
    service: name=memcached state=started
    tags: servicestart

    3.在handlers目录中创建处理其主任务playbook:main.yml

  • name: restart memcached
    service: name=memcached state=restarted

    4.在templates目录中提供配置文件,memcached.j2
    [root@3 memcached]# cp /etc/sysconfig/memcached memcached/templates/memcached.j2
    [root@3 memcached]# vim templates/memcached.j2
    PORT="11211"
    USER="memcached"
    MAXCONN="1024"
    CACHESIZE="{{ ansible_memtotal_mb//4 }}" //修改成这样,定义以此主机4分之一的内存来开启memcached
    OPTIONS=""
    [root@3 ansible] vim memcached.yml

  • hosts: 172.16.75.13
    remote_user: root
    roles:
    • memcached
      完成后调用roles:
      [root@3 ansible] vim memcached.yml
  • hosts: 172.16.75.13
    remote_user: root
    roles:
    • memcached
      [root@3 ansible]# ansible-playbook memcached.yml

PLAY [172.16.75.13] ****

TASK [Gathering Facts] *****
ok: [172.16.75.13]

TASK [memcached : install memcached] ***
changed: [172.16.75.13]

TASK [memcached : provide config file] *****
ok: [172.16.75.13]

TASK [memcached : start memcached service] *****
changed: [172.16.75.13]

PLAY RECAP *****
172.16.75.13 : ok=4 changed=2 unreachable=0 failed=0

同理我们还可以用这个方法安装nginx:
[root@3 roles]# mkdir -pv /etc/ansible/roles/nginx/{files,templates,tasks,handlers,vars,meta,default}
[root@3 nginx]# vim tasks/main.yml

  • name: install nginx package
    yum: name=nginx state=present
  • name: provide nginx config file
    template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
    notify: reload nginx config
    tags: provconf
  • name: start nginx service
    service: name=nginx state=started enabled=true
    [root@3 nginx]# vim handlers/main.yml
  • name: reload nginx config
    service: name=nginx state=reloaded
    [root@3 nginx]# cp /etc/nginx/nginx.conf templates/nginx.conf.j2
    [root@3 ansible]# vim nginx.yml
  • hosts: 172.16.75.6
    remote_user: root
    roles:
    • nginx
      [root@3 ansible]# ansible-playbook --check nginx.yml

PLAY [172.16.75.6] *****

TASK [Gathering Facts] *****
ok: [172.16.75.6]

TASK [nginx : install nginx package] ***
changed: [172.16.75.6]

TASK [nginx : provide nginx config file] ***
changed: [172.16.75.6]

TASK [nginx : start nginx service] *****
changed: [172.16.75.6]

RUNNING HANDLER [nginx : reload nginx config] **
changed: [172.16.75.6]

PLAY RECAP *****
172.16.75.6 : ok=5 changed=4 unreachable=0 failed=0
测试成功;

在playbook中调用roles的方法1:

  • hosts: hosts_group_name
    remote_user: root
    roles:
    • role_name1
    • role_name2
      ...

在playbook中调用roles的方法2:在调用roles的时候向roles传递变量:

  • hosts: hosts_group_name
    remote_user: root
    roles:

    • { role: role_name1, var1: value1, var2: value2, ...}
    • { role: role_name2, var1: value1, var2: value2, ...}
      ...

    role键用于指定角色名称,必须给出的内容;后续的键值对用于向前面的角色传递变量;

在playbook中调用roles的方法3:在调用角色的时候可以根据某个条件来执行:

  • hosts: hosts_group_name
    remote_user: root
    roles:
    • { role: role_name1, when: condition}