Ansible常见模块与使用方法

安装
使用extras仓库里面的最新的ansible包

ansible-2.4.1.0-1.el7.noarch
/etc/ansible                #配置文件目录
/etc/ansible/ansible.cfg    #主配置文件
/etc/ansible/hosts          #定义被管理的客户端
/etc/ansible/roles          #

主程序:

                    ansible
                    ansible-playbook
                    ansible-doc
vim /etc/ansible/hosts

## [webservers]             #定义组名
## alpha.example.org
## beta.example.org
## 192.168.1.100
## 192.168.1.110
## www[001:006].example.com #如果组类拥有同样的命名规范,我们还可以展开

例子

[webserver]
172.18.25.51
172.18.25.52
[dbserver]
172.18.25.52
172.18.25.53

我们这里可以是所有被管控的机器都使用一样的密钥

[ root@node1 ~ ]# ssh-kengen -t rsa -P ''
[ root@node1 ~ ]# for i in 51 52 53 ;do ssh-copy-id -i ~/.ssh/id_rsa.pub
 [email protected].$i; done

然后手动尝试连接验证一下

ansible的简单使用格式:
    ansible  HOST-PATTERN   -m MOD_NAME  -a  MOD_ARGS -f FORKS -C -u USERNAME -c CONNECTION

ansible的常用模块:
获取模块列表:

            ansible-doc  -l
command模块:在远程主机运行命令;
    chdir=:执行命令前切换工作目录至指定的位置;
    creates=/PATH/TO/SOMEFILE_OR_DIR:如果此处给定的文件或目录存在,则不执行命令;
    removes=/PATH/TO/SOMEFILE_OR_DIR:如果此处给定的文件或目录不存在,则不执行命令;
        意为:令此处给定的文件或目录存在时方执行命令;

例子:

[ root@node1 ~ ]# ansible webserver -m command -a "useradd ygl"
        172.18.25.51 | SUCCESS | rc=0 >>


        172.18.25.52 | SUCCESS | rc=0 >>




    shell模块:在远程主机在shell进程下运行命令,支持shell特性,如管道等;
        chdir=:执行命令前切换工作目录至指定的位置;
        creates=/PATH/TO/SOMEFILE_OR_DIR:如果此处给定的文件或目录存在,则不执行命令;
        removes=/PATH/TO/SOMEFILE_OR_DIR:如果此处给定的文件或目录不存在,则不执行命令;
            意为:令此处给定的文件或目录存在时方执行命令;
        executable=/PATH/TO/SHELL:指定运行命令使用的shell解释器;

例子:
[ root@node1 ~ ]# ansible webserver -m shell -a “echo 123 | passwd –stdin ygl”
172.18.25.51 | SUCCESS | rc=0 >>
更改用户 ygl 的密码 。
passwd:所有的身份验证令牌已经成功更新。

172.18.25.52 | SUCCESS | rc=0 >>
更改用户 ygl 的密码 。
passwd:所有的身份验证令牌已经成功更新。  

group模块:管理组账号

    *name=
    state=          #present 创建 #absent 删除
    system=         #是否是系统账号
    gid=            

例子:

        [ root@node1 ~ ]# ansible webserver -m group -a "name=haproxy system=yes state=present"
        172.18.25.52 | SUCCESS => {
            "changed": true, 
            "failed": false, 
            "gid": 993, 
            "name": "haproxy", 
            "state": "present", 
            "system": true
        }
        172.18.25.51 | SUCCESS => {
            "changed": true, 
            "failed": false, 
            "gid": 993, 
            "name": "haproxy", 
            "state": "present", 
            "system": true
        }


        [ root@node1 ~ ]# ansible webserver -m group -a "name=haproxy system=yes state=absent"
        172.18.25.52 | SUCCESS => {
            "changed": true, 
            "failed": false, 
            "name": "haproxy", 
            "state": "absent"
        }
        172.18.25.51 | SUCCESS => {
            "changed": true, 
            "failed": false, 
            "name": "haproxy", 
            "state": "absent"
        }     
user模块:管理用户账号
[ root@node1 ~ ]# ansible-doc -s user
 如果后面接受里面有(required)表示必须要写的,不可省略。

            *name=
            system=
            uid=
            shell=
            group=
            groups=         #附加主
            comment=        #注释
            home=
            generate_ssh_key=   ture/false#是否生成一个ssh_key密钥 
            local=

例子:

        #创建tom用户,同名所属组,附加组为haproxy,uid为3000
        shell是tcsh,并且生成ss_key.
        [ root@node1 ~ ]# ansible webserver -m user -a "name=tom groups=haproxy state=present uid=3000 shell=/bin/tcsh generate_ssh_key=true"
        172.18.25.51 | SUCCESS => {
            "changed": true, 
            "comment": "", 
            "createhome": true, 
            "failed": false, 
            "group": 3000, 
            "groups": "haproxy", 
            "home": "/home/tom", 
            "name": "tom", 
            "shell": "/bin/tcsh", 
            "ssh_fingerprint": "2048 58:f3:82:5f:c6:cb:c4:e0:96:0e:61:9c:63:5f:5f:2d  ansible-generated on node1 (RSA)", 
            "ssh_key_file": "/home/tom/.ssh/id_rsa", 
            "ssh_public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCo9QnI4Q2S5WNjJ7Spj5jwYeLtH8v3JNiG+y1Oj+Qsnbc/AR6hs3tAMEDUW8MkUXqJT8QUwhAxugB5jdl2y4Yc4Y/s2tQ5PS+N2h6/N56xMQyrVqh26RF+yTEHc3LJhUM/cdHEJrnBFvV9h+S6IaxEOHL/mCzXJ46tPTvorIpkPWyvkfjqdGwyac4GGbcFmPa2GXiO0WuIADdK/GTFHTAyq+r3SisYTNDuGFWMl0HCXKujbQhsEwrPvlHfPH9nnuKp5C+4c7mZ8BMyk3MQgbu/0eI3y51YOC3yi/4eVdEYc6AxE8ifcHkjjTSGudifF7vhlBIoYvzbvey8wf4Tct5D ansible-generated on node1", 
            "state": "present", 
            "system": false, 
            "uid": 3000
        }
        172.18.25.52 | SUCCESS => {
            "changed": true, 
            "comment": "", 
            "createhome": true, 
            "failed": false, 
            "group": 3000, 
            "groups": "haproxy", 
            "home": "/home/tom", 
            "name": "tom", 
            "shell": "/bin/tcsh", 
            "ssh_fingerprint": "2048 97:0f:72:fd:fc:13:38:4a:fc:28:63:02:c4:f6:29:53  ansible-generated on node2 (RSA)", 
            "ssh_key_file": "/home/tom/.ssh/id_rsa", 
            "ssh_public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDOXS6KtT6zPnFceO1TNLd1jVssT2419VdbL/2OC3LnALoqS0Dyb7ZSJEIocSgoGAVGmSg0JJTKgBf7aBM6agH44ZrZfTEn24C/4t83uRusVA9N8rnGhqOrTLn0U/Hrjdew7wXfnZaJmuoAyh2lQOESKrYflxWmA3z+RJwq5yQELTGGFpJq5cUYhXW13ItI2cxeDq5l9NJx/lOceNkjGXMtMLjtU0vKhaRudKaeXpLoxdHerVYdVVOvyjfHdRMycQRyfgLl+OivbmyfCx8far7JTWf4W+sSVTx/gh6nK2E/5jIGvrInDZWsvq/cePBGvU6S0Fv/MuW979b6VLaS8Te3 ansible-generated on node2", 
            "state": "present", 
            "system": false, 
            "uid": 3000
        }

修改的话,比如把uid改成4000,
但是像ssh_key这种已经生成了的,把true改成false的话,是不能删除掉之前的密钥的。

copy模块: Copies files to remote locations.
    用法:
        (1) src=  dest=
        (2) content=  dest=
        owner, group, mode 

例子:使用用法(1)

        [ root@node1 ~ ]# ansible all -m copy -a "src=test.txt dest=/tmp/ owner=daemon group=nobody mode=644"
        172.18.25.52 | SUCCESS => {
            "changed": true, 
            "checksum": "909b3eb9cf443e1fe007b9940910c1b5370157b6", 
            "dest": "/tmp/test.txt", 
            "failed": false, 
            "gid": 99, 
            "group": "nobody", 
            "md5sum": "b5ab68405ea7f38841f44964cac71a3a", 
            "mode": "0644", 
            "owner": "daemon", 
            "size": 31, 
            "src": "/root/.ansible/tmp/ansible-tmp-1511897155.3-203125776259926/source", 
            "state": "file", 
            "uid": 2
        }
        172.18.25.51 | SUCCESS => {
            "changed": true, 
            "checksum": "909b3eb9cf443e1fe007b9940910c1b5370157b6", 
            "dest": "/tmp/test.txt", 
            "failed": false, 
            "gid": 99, 
            "group": "nobody", 
            "md5sum": "b5ab68405ea7f38841f44964cac71a3a", 
            "mode": "0644", 
            "owner": "daemon", 
            "size": 31, 
            "src": "/root/.ansible/tmp/ansible-tmp-1511897155.29-136104449376316/source", 
            "state": "file", 
            "uid": 2
        }
        172.18.25.53 | SUCCESS => {
            "changed": true, 
            "checksum": "909b3eb9cf443e1fe007b9940910c1b5370157b6", 
            "dest": "/tmp/test.txt", 
            "failed": false, 
            "gid": 99, 
            "group": "nobody", 
            "md5sum": "b5ab68405ea7f38841f44964cac71a3a", 
            "mode": "0644", 
            "owner": "daemon", 
            "size": 31, 
            "src": "/root/.ansible/tmp/ansible-tmp-1511897155.38-10083863563401/source", 
            "state": "file", 
            "uid": 2
        }

使用用法(2)直接生成一些内容

        [ root@node1 ~ ]# ansible all -m copy -a "content='hello there nhow are you' dest=/tmp/test2.txt owner=daemon group=nobody mode=644"
        172.18.25.53 | SUCCESS => {
            "changed": true, 
            "checksum": "48ac9867d3152d279d7409b994356818ce61b54e", 
            "dest": "/tmp/test2.txt", 
            "failed": false, 
            "gid": 99, 
            "group": "nobody", 
            "md5sum": "65b97a6f52bed5bf307dd96ba01dfae0", 
            "mode": "0644", 
            "owner": "daemon", 
            "size": 24, 
            "src": "/root/.ansible/tmp/ansible-tmp-1511897535.05-274804325591646/source", 
            "state": "file", 
            "uid": 2
        }
        172.18.25.52 | SUCCESS => {
            "changed": true, 
            "checksum": "48ac9867d3152d279d7409b994356818ce61b54e", 
            "dest": "/tmp/test2.txt", 
            "failed": false, 
            "gid": 99, 
            "group": "nobody", 
            "md5sum": "65b97a6f52bed5bf307dd96ba01dfae0", 
            "mode": "0644", 
            "owner": "daemon", 
            "size": 24, 
            "src": "/root/.ansible/tmp/ansible-tmp-1511897535.05-210909367052491/source", 
            "state": "file", 
            "uid": 2
        }
        172.18.25.51 | SUCCESS => {
            "changed": true, 
            "checksum": "48ac9867d3152d279d7409b994356818ce61b54e", 
            "dest": "/tmp/test2.txt", 
            "failed": false, 
            "gid": 99, 
            "group": "nobody", 
            "md5sum": "65b97a6f52bed5bf307dd96ba01dfae0", 
            "mode": "0644", 
            "owner": "daemon", 
            "size": 24, 
            "src": "/root/.ansible/tmp/ansible-tmp-1511897535.04-149048632090006/source", 
            "state": "file", 
            "uid": 2
        }

fetch模块:Fetches a file from remote nodes

file模块: Sets attributes of files
    用法:
        (1) 创建链接文件:*path=  src=  state=link
        (2) 修改属性:path=  owner= mode= group= 
        (3) 创建目录:path=  state=directory
        注意:state属性的可用值
            file,           #表示必须是一个文件
            directory,      #表示不过不存在就创建一个目录
            link,           #表示是一个链接
            hard,           #表示是一个硬链接
            touch,          #表示不存在就创建一个空文件
            absent          #表示删除



        例子:创建目录
            [ root@node1 ~ ]# ansible all -m file -a "path=/tmp/hidir state=directory owner=nobody mode=777"
            172.18.25.52 | SUCCESS => {
                "changed": true, 
                "failed": false, 
                "gid": 0, 
                "group": "root", 
                "mode": "0777", 
                "owner": "nobody", 
                "path": "/tmp/hidir", 
                "size": 6, 
                "state": "directory", 
                "uid": 99
            }
            172.18.25.53 | SUCCESS => {
                "changed": true, 
                "failed": false, 
                "gid": 0, 
                "group": "root", 
                "mode": "0777", 
                "owner": "nobody", 
                "path": "/tmp/hidir", 
                "size": 6, 
                "state": "directory", 
                "uid": 99
            }
            172.18.25.51 | SUCCESS => {
                "changed": true, 
                "failed": false, 
                "gid": 0, 
                "group": "root", 
                "mode": "0777", 
                "owner": "nobody", 
                "path": "/tmp/hidir", 
                "size": 6, 
                "state": "directory", 
                "uid": 99
            }


        例子:创建空文件
        [ root@node1 ~ ]# ansible all -m file -a "path=/tmp/hifile state=touch owner=nobody mode=777"
        172.18.25.51 | SUCCESS => {
            "changed": true, 
            "dest": "/tmp/hifile", 
            "failed": false, 
            "gid": 0, 
            "group": "root", 
            "mode": "0777", 
            "owner": "nobody", 
            "size": 0, 
            "state": "file", 
            "uid": 99
        }
        172.18.25.52 | SUCCESS => {
            "changed": true, 
            "dest": "/tmp/hifile", 
            "failed": false, 
            "gid": 0, 
            "group": "root", 
            "mode": "0777", 
            "owner": "nobody", 
            "size": 0, 
            "state": "file", 
            "uid": 99
        }
        172.18.25.53 | SUCCESS => {
            "changed": true, 
            "dest": "/tmp/hifile", 
            "failed": false, 
            "gid": 0, 
            "group": "root", 
            "mode": "0777", 
            "owner": "nobody", 
            "size": 0, 
            "state": "file", 
            "uid": 99
        }

例子:创建一个链接,注意这个源文件是指的目标服务器上的源文件。

   [ root@node1 ~ ]# ansible all -m file -a "path=/tmp/mytest.txt src=/tmp/test2.txt state=link"
        172.18.25.52 | SUCCESS => {
            "changed": true, 
            "dest": "/tmp/mytest.txt", 
            "failed": false, 
            "gid": 0, 
            "group": "root", 
            "mode": "0777", 
            "owner": "root", 
            "size": 14, 
            "src": "/tmp/test2.txt", 
            "state": "link", 
            "uid": 0
        }
        172.18.25.53 | SUCCESS => {
            "changed": true, 
            "dest": "/tmp/mytest.txt", 
            "failed": false, 
            "gid": 0, 
            "group": "root", 
            "mode": "0777", 
            "owner": "root", 
            "size": 14, 
            "src": "/tmp/test2.txt", 
            "state": "link", 
            "uid": 0
        }
        172.18.25.51 | SUCCESS => {
            "changed": true, 
            "dest": "/tmp/mytest.txt", 
            "failed": false, 
            "gid": 0, 
            "group": "root", 
            "mode": "0777", 
            "owner": "root", 
            "size": 14, 
            "src": "/tmp/test2.txt", 
            "state": "link", 
            "uid": 0
        }

删除符号链接

  [ root@node1 ~ ]# ansible all -m file -a "path=/tmp/mytest.txt  state=absent"
        172.18.25.52 | SUCCESS => {
            "changed": true, 
            "failed": false, 
            "path": "/tmp/mytest.txt", 
            "state": "absent"
        }
        172.18.25.53 | SUCCESS => {
            "changed": true, 
            "failed": false, 
            "path": "/tmp/mytest.txt", 
            "state": "absent"
        }
        172.18.25.51 | SUCCESS => {
            "changed": true, 
            "failed": false, 
            "path": "/tmp/mytest.txt", 
            "state": "absent"
        }

get_url模块: Downloads files from HTTP, HTTPS, or FTP to node
*url=
*dest=
sha256sum=
owner, group, mode

例子: 然三个主机都下载redis并放在/tmp/目录下    
[ root@node1 ~ ]# ansible all -m get_url -a 
"url=http://download.redis.io/releases/redis-4.0.2.tar.gz dest=/tmp/"
172.18.25.51 | SUCCESS => {
    "changed": true, 
    "checksum_dest": null, 
    "checksum_src": "d2588569a35531fcdf03ff05cf0e16e381bc278f", 
    "dest": "/tmp/redis-4.0.2.tar.gz", 
    "failed": false, 
    "gid": 0, 
    "group": "root", 
    "md5sum": "f0497cc1311cd10dfdf215e9e6fd7416", 
    "mode": "0644", 
    "msg": "OK (1713990 bytes)", 
    "owner": "root", 
    "size": 1713990, 
    "src": "/tmp/tmpSYXHve", 
    "state": "file", 
    "status_code": 200, 
    "uid": 0, 
    "url": "http://download.redis.io/releases/redis-4.0.2.tar.gz"
}
172.18.25.53 | SUCCESS => {
    "changed": true, 
    "checksum_dest": null, 
    "checksum_src": "d2588569a35531fcdf03ff05cf0e16e381bc278f", 
    "dest": "/tmp/redis-4.0.2.tar.gz", 
    "failed": false, 
    "gid": 0, 
    "group": "root", 
    "md5sum": "f0497cc1311cd10dfdf215e9e6fd7416", 
    "mode": "0644", 
    "msg": "OK (1713990 bytes)", 
    "owner": "root", 
    "size": 1713990, 
    "src": "/tmp/tmp4EF_zu", 
    "state": "file", 
    "status_code": 200, 
    "uid": 0, 
    "url": "http://download.redis.io/releases/redis-4.0.2.tar.gz"
}
172.18.25.52 | SUCCESS => {
    "changed": true, 
    "checksum_dest": null, 
    "checksum_src": "d2588569a35531fcdf03ff05cf0e16e381bc278f", 
    "dest": "/tmp/redis-4.0.2.tar.gz", 
    "failed": false, 
    "gid": 0, 
    "group": "root", 
    "md5sum": "f0497cc1311cd10dfdf215e9e6fd7416", 
    "mode": "0644", 
    "msg": "OK (1713990 bytes)", 
    "owner": "root", 
    "size": 1713990, 
    "src": "/tmp/tmpKb1mA2", 
    "state": "file", 
    "status_code": 200, 
    "uid": 0, 
    "url": "http://download.redis.io/releases/redis-4.0.2.tar.gz"
}

git模块:Deploy software (or files) from git checkouts
repo= #仓库路径
dest= #克隆后目标存放路径
version= #获取是选取哪个版本,默认是最新的

例子:首先在webserver上面安装git,然后在github上面下载fastdfs并放在/tmp/下
[ root@node1 ~ ]# ansible webserver -m yum -a "name=git state=latest"

[ root@node1 ~ ]# ansible webserver -m git -a"repo=https://github.com/happyfish100/fastdfs.git dest=/tmp/fastdfs"



deploy_helper模块:Manages some of the steps common in deploying projects.

haproxy模块:Enable, disable, and set weights for HAProxy backend servers using socket commands.
    backend=
    host=
    state=
    weight=

cron 模块:Manage cron.d and crontab entries.
    minute=
    day=
    month=
    weekday=
    hour=
    job=
    *name=
    state=
        present:创建
        absent:删除
例子:每隔五分钟所有机器都去172..18.0.1上面同步一次时间。
[ root@node1 ~ ]# ansible all -m cron -a "name='timesync' job='/usr/sbin/ntpdate 172.18.0.1 &> /dev/null' minute='*/5'"
172.18.25.53 | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "failed": false, 
    "jobs": [
        "timesync"
    ]
}
172.18.25.52 | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "failed": false, 
    "jobs": [
        "timesync"
    ]
}
172.18.25.51 | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "failed": false, 
    "jobs": [
        "timesync"
    ]
}
[ root@node1 ~ ]# crontab -l
#Ansible: timesync
*/5 * * * * /usr/sbin/ntpdate 172.18.0.1 &> /dev/null
删除定义的计划任务
[ root@node1 ~ ]# ansible all -m cron -a "name='timesync' job='/usr/sbin/ntpdate 172.18.0.1 &> /dev/null' minute='*/5' state=absent"
172.18.25.52 | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "failed": false, 
    "jobs": []
}
172.18.25.53 | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "failed": false, 
    "jobs": []
}
172.18.25.51 | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "failed": false, 
    "jobs": []
}
创建计划任务,但是不启用,也就是被注释的
    [ root@node1 ~ ]# ansible all -m cron -a "name='timesync' job='/usr/sbin/ntpdate 172.18.0.1 &> /dev/null' minute='*/5' state=present disabled=true"
    172.18.25.52 | SUCCESS => {
        "changed": true, 
        "envs": [], 
        "failed": false, 
        "jobs": [
            "timesync"
        ]
    }
    172.18.25.53 | SUCCESS => {
        "changed": true, 
        "envs": [], 
        "failed": false, 
        "jobs": [
            "timesync"
        ]
    }
    172.18.25.51 | SUCCESS => {
        "changed": true, 
        "envs": [], 
        "failed": false, 
        "jobs": [
            "timesync"
        ]
    }
    [ root@node1 ~ ]# crontab -l
    #Ansible: timesync
    #*/5 * * * * /usr/sbin/ntpdate 172.18.0.1 &> /dev/null
hostname模块:Manage hostname
    name=

pip模块:Manages Python library dependencies.  #管理python库依赖关系
    name=
    state=
    version=

npm模块:Manage node.js packages with npm          #用npm管理node.js包
    name=
    state=
    version=
yum模块:Manages packages with the `yum' package manager
        name=:程序包名称,可以带版本号;
        state=
            present, 
            latest,         #最新的
            installed
            absent, 
            removed
        其它的包管理工具:apt(debian), zypper(suse), dnf(fedora), rpm, dpkg, ...

例子:都yum安装 nginx

[ root@node1 ~ ]# ansible webserver -m yum -a "name=nginx state=latest"

[ root@node1 ~ ]# ansible webserver -m yum -a "list=nginx"
172.18.25.51 | SUCCESS => {
    "changed": false, 
    "failed": false, 
    "results": [
        {
            "arch": "x86_64", 
            "envra": "1:nginx-1.10.2-1.el7.x86_64", 
            "epoch": "1", 
            "name": "nginx", 
            "release": "1.el7", 
            "repo": "epel", 
            "version": "1.10.2", 
            "yumstate": "available"
        }, 
        {
            "arch": "x86_64", 
            "envra": "1:nginx-1.10.2-1.el7.x86_64", 
            "epoch": "1", 
            "name": "nginx", 
            "release": "1.el7", 
            "repo": "installed", 
            "version": "1.10.2", 
            "yumstate": "installed"
        }
    ]
}
172.18.25.52 | SUCCESS => {
    "changed": false, 
    "failed": false, 
    "results": [
        {
            "arch": "x86_64", 
            "envra": "1:nginx-1.10.2-1.el7.x86_64", 
            "epoch": "1", 
            "name": "nginx", 
            "release": "1.el7", 
            "repo": "epel", 
            "version": "1.10.2", 
            "yumstate": "available"
        }, 
        {
            "arch": "x86_64", 
            "envra": "1:nginx-1.10.2-1.el7.x86_64", 
            "epoch": "1", 
            "name": "nginx", 
            "release": "1.el7", 
            "repo": "installed", 
            "version": "1.10.2", 
            "yumstate": "installed"
        }
    ]
}
service模块:管理服务
                    *name=
                    state=
                        started
                        stopped
                        restarted
                    enabled=
                    runlevel=       #运行级别
例子:启动之前使用ansible批量安装的ngixn
        [ root@node1 ~ ]# ansible webserver -m service -a "name=nginx enabled=true state=started"
172.18.25.51 | SUCCESS => {
    "changed": true, 
    "enabled": true, 
    "failed": false, 
    "name": "nginx", 
    "state": "started", 
    "status": {
...
    }
}
172.18.25.52 | SUCCESS => {
    "changed": true, 
    "enabled": true, 
    "failed": false, 
    "name": "nginx", 
    "state": "started", 
    "status": {
 ...
    }
}

使用ansible结合keepalived高可用,nginx反向代理部署小型企业环境

前言:

ansible作为一款灵活、高效、功能丰富的自动化部署工具在企业运维管理中备受推崇。本文演示使用ansible部署小型企业服务框架,实现高可用、负载均衡的目标。如有错误敬请赐教。
目标环境拓扑:
未分类

环境介绍:

前端代理层由两台nginx实现,并安装keepalived实现地址滑动达成高可用。
web层由两套Apache+PHP+WordPress 构建应用环境。数据层由一台mariadb组成,篇幅限制这里并没有做数据库主从复制、读写分离(实际环境数据库一定要实现这两项功能)。

IP一览:

未分类

环境准备:

1.管理端安装ansible,配置ssh秘钥使主机间实现基于秘钥的认证

ssh-keygen  -t rsa  #三次回车,中途的问题是问秘钥存放位置(默认/root/.ssh),是否加密秘钥。实验方便这里不加密
ssh-copy-id -i .ssh/id_rsa.pub [email protected] #将公钥发送给目标主机
ssh-copy-id -i .ssh/id_rsa.pub [email protected]
ssh-copy-id -i .ssh/id_rsa.pub [email protected]
ssh-copy-id -i .ssh/id_rsa.pub [email protected]
ssh-copy-id -i .ssh/id_rsa.pub [email protected]

2.编辑ansible的hosts文件,定义所有的主机
vim /etc/ansible/hosts
未分类
3.为所有主机同步时间

 ansible all -a 'ntpdate 172.18.0.1' #我这里是同步自己局域网的ntp服务器,实验的话选取同一台主机保证时间相同即可

4.创建ansible相关角色的目录

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

配置web的playbook:

1.创建tasks文件

vim /etc/ansible/roles/web/task/main.yml
- name: install web pakgs
  yum: name={{ item }}
  with_items:
  - httpd
  - php
  - php-mysql
- name: config  web
  copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
  notify: restart the service # 注意这里要与handlers里定义的name相同
- name: copy wordpress
  synchronize: src=wordpress dest=/var/www/html/wordpress/
- name: restart the service
  service: name=httpd state=started

2.创建handles

vim /etc/ansible/roles/web/handlers/main.yml
- name: restart the service  #就这
  service: name=httpd state=restarted

3.添加要复制过去的配置文件
放在/etc/ansible/roles/web/files/下 ① WordPress目录 ② httpd.conf #从别的地方考过来
4.修改WordPress连接数据库的配置文件

 cd wordpress
 cp wp-sample-config.php  wp-config.php
 vim wp-config.php

未分类
5.添加web主剧本

vim /etc/ansible/web.yml
- hosts: web
  remote_user: root
  roles:
  - web

6.测试,没问题的话就下一步

ansible-playbook -C /etc/ansible/web.yml

配置代理层:

1.添加task任务

vim /etc/ansible/roles/nginx/tasks/main.yml
- name: install package
  yum: name={{ item }}
  with_items:
  - nginx
  - keepalived
- name: config keepalived
  template: src=keepalived.conf.j2 dest=/etc/keepalived/keepalived.conf
  notify: restart keepalived
- name: config nginx
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
  notify: restart nginx
- name: start service
  service: name={{ item }} state=started enabled=true
  with_items:
  - keepalived
  - nginx

2.添加handlers

vim /etc/ansible/roles/nginx/handlers
- name: restart keepalived
  service: name=keepalived state=restarted
- name: restart nginx
  service: name=nginx state=restarted

3.准备template文件 ①keepalived.conf.j2 ②nginx.conf.j2
4.修改keepalived模板文件

global_defs {
   notification_email {
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id {{ansible_hostname}} #自带变量,通过ansible 主机IP -m setup 查询
   vrrp_mcast_group4 224.0.0.43
}

vrrp_instance VI_1 {
    state {{ state }} #已通过hosts文件定义变量
    interface ens33 #网卡名
    virtual_router_id 51
    priority {{ priority }}
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass lovelinux #设置密码
    }
    virtual_ipaddress {
        172.18.43.88 #虚拟IP
    }
}

5.修改nginx模板文件(定义在http段)

upstream web {                        #新增段
        server 172.18.43.61;
        server 172.18.43.62;
    }
    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

    location / {                     #新增段
        proxy_pass    
        }
    }

6.添加nginx主剧本

vim /etc/ansible/nginx.yml
- hosts: nginx
  remote_user: root
  roles:
  - nginx

7.测试,没问题的话就下一步

ansible-playbook -C /etc/ansible/nginx.yml

配置mariadb:

1.配置mariadb的任务清单

roles/mysql/tasks/main.yml
- name: install mariadb
  yum: name=mariadb-server
- name: copy sql file
  copy: src=mysql.sql dest=/tmp/mysql.sql
- name: start mysql service
  service: name=mariadb state=started
- name: config mysql
  shell: "mysql < /tmp/mysql.sql"

2.设置files文件

vim roles/mysql/files/mysql.sql 
CREATE DATABASE wp;
GRANT ALL ON wp.* TO 'wpuser'@'%' IDENTIFIED BY 'lovelinux';

3.添加mysql主剧本

vim /etc/ansible/mysql.yml
- hosts: mysql
  remote_user: root
  roles:
  - mysql

4.测试,没问题的话就下一步

ansible-playbook -C /etc/ansible/mysql.yml

开始表演(执行剧本):

1.目录结构
未分类
2.分别执行

ansible-playbook  web.yml
ansible-playbook  nginx.yml
ansible-playbook  mysql.yml

3.访问页面http://172.18.43.88/wordpress
未分类

项目总结:

1.在定义web的playbook时复制wordpress时开始用的是copy模块执行总是不成功,报错ERROR! A worker was found in a dead state。在确认自己没有语法错误后,百度查找原因无果最后在Google上找到了答案(英文不好不要心虚,技术问题语法都很简单很容易看懂,个别单词查查有道词典就好了),所以有在IT技术的问题问Google准没错。用synchronize模块要比copy模块高效安全的多,synchronize采用rsync复制文件,所以系统必须安装rsync 包否则无法使用这个模块。使用该模块的优点有①增量复制(只复制与目标主机有差异的文件) ② 复制时采用压缩,对复制大文件支持优秀(用copy复制大文件会出错),以下整理了一些synchronize参数:
archive # 是否采用归档模式同步,即以源文件相同属性同步到目标地址
copy_links # 同步的时候是否复制连接
links # Copy symlinks as symlinks
delete # 删除源中没有而目标存在的文件(即以推送方为主)
dest= # 目标地址
dest_port # 目标接受的端口,ansible配置文件中的 ansible_ssh_port 变量优先级高于该 dest_port 变量
dirs # 以非递归的方式传输目录
2.如mysql主机曾经安装过mariadb可能会出现导入SQL命令失败的情况,这时要将mysql的数据库删掉,默认位置在/var/lib/mysql/下
3.编辑nginx代理时注意语句的位置不要写错
4.出现错误仔细看看错误日志,耐心点问题肯没想的那么难。

ansible playbook支持的atrributes

ansible这个工具的官方文档其实做得特别不好。不仅没有搜索功能,而且对于playbook的各种属性居然没有介绍,特别是gather_facts:这种属性,在特定的场景下关掉是可以减少很多等待时间的。

因为文档上没有,所以基本只能看代码。

# =================================================================================
# Connection-Related Attributes

# TODO: generalize connection
_accelerate          = FieldAttribute(isa='bool', default=False, always_post_validate=True)
_accelerate_ipv6     = FieldAttribute(isa='bool', default=False, always_post_validate=True)
_accelerate_port     = FieldAttribute(isa='int', default=5099, always_post_validate=True)

# Connection
_gather_facts        = FieldAttribute(isa='bool', default=None, always_post_validate=True)
_gather_subset       = FieldAttribute(isa='barelist', default=None, always_post_validate=True)
_gather_timeout      = FieldAttribute(isa='int', default=None, always_post_validate=True)
_hosts               = FieldAttribute(isa='list', required=True, listof=string_types, always_post_validate=True)
_name                = FieldAttribute(isa='string', default='', always_post_validate=True)

# Variable Attributes
_vars_files          = FieldAttribute(isa='list', default=[], priority=99)
_vars_prompt         = FieldAttribute(isa='list', default=[], always_post_validate=True)
_vault_password      = FieldAttribute(isa='string', always_post_validate=True)

# Role Attributes
_roles               = FieldAttribute(isa='list', default=[], priority=90)

# Block (Task) Lists Attributes
_handlers            = FieldAttribute(isa='list', default=[])
_pre_tasks           = FieldAttribute(isa='list', default=[])
_post_tasks          = FieldAttribute(isa='list', default=[])
_tasks               = FieldAttribute(isa='list', default=[])

# Flag/Setting Attributes
_any_errors_fatal    = FieldAttribute(isa='bool', default=False, always_post_validate=True)
_force_handlers      = FieldAttribute(isa='bool', always_post_validate=True)
_max_fail_percentage = FieldAttribute(isa='percent', always_post_validate=True)
_serial              = FieldAttribute(isa='list', default=[], always_post_validate=True)
_strategy            = FieldAttribute(isa='string', default=C.DEFAULT_STRATEGY, always_post_validate=True)

# =================================================================================

还可以通过命令的方式:

python -c 'import ansible.playbook.play as P; print P.Play()._valid_attrs.keys();'

['tasks', 'vars', 'become_user', 'vault_password', 'gather_subset', 'accelerate', 'diff', 'serial', 'port', 'post_tasks', 'environment', 'remote_user', 'become_method', 'gather_timeout', 'strategy', 'no_log', 'pre_tasks', 'vars_files', 'accelerate_port', 'force_handlers', 'tags', 'gather_facts', 'check_mode', 'always_run', 'run_once', 'max_fail_percentage', 'ignore_errors', 'fact_path', 'name', 'roles', 'handlers', 'any_errors_fatal', 'connection', 'hosts', 'become_flags', 'vars_prompt', 'become', 'accelerate_ipv6', 'order']

利用Ansible部署运行Apache(http)的Docker容器

在自动化运维领域,除了saltstack,还有ansible这个批量安装部署工具,在写具体内容先,先谈谈我用过两个工具后的感想。

saltstack是C/S框架,要在客户端装软件,并且启动服务才能进行管理,ansible是通过ssh连接到客户端的,也就是说必须把密钥传给客户端才能进行管理,虽然可以关闭这个验证方式,但是生产环境中肯定是不能关闭的,从这一点看,还是ansible更容易配置,完全可以用脚本循环遍历所有主机来添加密钥。

使用方面,命令复杂程度相似,理解起来更容易的应该是saltstack,命令基本都是英语的组合,ansible则是依靠各种模式,参数来执行管理。

脚本编程方面,编程复杂度方面不尽相同,ansible提供群组的方式来对多主机提供管理,在推送操作到客户端时需给出明确的执行文件(yml),对于文件的存放位置没有明确的规定,saltstack需要在命令行提供主机信息,在推送时执行的是配置文件中提供的目录中的文件(sls),推送的文件也必须在这个目录中。

以上是我个人的一些见解,下面开始实战操作

环境介绍:

  • Centos 6.5
  • Ansible 2.3.0
  • Docker 1.7.1
  • Http 2.4.6-67

一、Docker操作

1. docker安装

这部分略过,如果你对docker安装和一些常用命令不了解,请参考《Docker常用命令和操作》

2. 拉取ansible镜像

docker pull ansible/centos7-ansible    #推荐使用这个镜像

拉取成功后可以在images里查看到这个镜像

未分类

3. 运行镜像,打开一个容器

docker run -it --name ansible 6883

4. 修改配置文件

vi /etc/ansible/hosts
[local]nlocalhostn  >>>>>  
[local]
localhost

这两个回车符在运行时是不能转义的,会报错

5. 提交修改后的容器

docker commit 1277 ansiblev2

6. 编写镜像构建方法

vim Dockerfile
FROM ansiblev2
MAINTAINER bin [email protected]


WORKDIR /opt/ansible    #定义工作区
RUN mkdir /opt/ansible/files    #创建必须目录
RUN mkdir /opt/ansible/template

ADD httpd.conf /opt/ansible/files    #把需要的文件复制到指定位置
ADD index.html.j2 /opt/ansible/template    
ADD web.yml /opt/ansible/

RUN ansible-playbook /opt/ansible/web.yml -c local  #运行ansible进行自动部署

VOLUME /var/www/html    #定义数据卷

CMD ["/usr/sbin/httpd","-X"]    #让httpd服务在前台运行
EXPOSE 80        #开放80端口,httpd.conf配置文件中必须也是80端口

二、Ansible操作

1. 编写服务部署方法

vim web.yml #ansible和saltstack在文字格式方面要求同样严格,如果报错,请查看格式是否正确!

- name: Configure webserver with http        #在运行时的提示信息
  hosts: local        #对本地主机组进行操作
  sudo: True        #运行时切换用户
  tasks:            #建立任务
    - name: install http
      yum: name=httpd update_cache=yes    #安装httpd,更新缓存
    - name: copy http config file
      copy: src=files/httpd.conf dest=/etc/httpd/conf    #文件复制

    - name: enable configuration
      file: >        #竖版写法,建立软连接
         dest=/etc/httpd/configure
         src=/etc/httpd/conf/
         state=link

    - name: copy index.html    #拷贝主页文件
      template: src=template/index.html.j2 dest=/var/www/html/index.html mode=0644

2. index.html.j2的内容

<html>
  <head>
    <title>Welcome to ansible!</title>
  </head>
  <body>
  <h1>http,configured by Ansible</h1>
  <p>If you can see this,Ansible successfully installed http.</p>
  <p>{{ ansible_env }}</p>    #会显示容器的环境变量
  #要想显示更多信息,可以通过ansible hostname -m setup来查看可以引用的变量
  <p>{{ ansible_env.PATH }}</p>    #显示环境变量中的PATH的值
  </body>
</html>

三、构建镜像,启动容器

1. 构建镜像

当前目录结构

未分类

docker build -t ansible/httpd .

2. 启动容器

docker run -d -p 8000:80 --name httpd ansible/httpd  #把容器的80端口映射到本地的8000端口

3. 查看容器运行情况

docker ps -a

未分类

4. 因为在构建镜像的时候指定了数据卷,可以在启动容器的时候挂载数据卷,方便代码修改

docker run -d -p 8001:80 -v /var/www/html:/var/www/html --name http2 ansible/httpd

四、测试主页

http://192.168.6.10:8000

未分类

出现如上显示为部署正常。

ansible安装测试

apt-get install ansible
/etc/ansible/hosts增加

[nginx]
192.168.1.106

/etc/ansible/playbook/
roles site.yaml
site.yaml

- hosts: nginx
  remote_user: root

  roles:

roles/
bash nginx
playbook/roles/bash/tasks/main.yal

- name: 创建用户
  user: name=toy state=present

ls playbook/roles/nginx/

drwxr-xr-x 9 root root 4096 Jul 31 09:54 .
drwxr-xr-x 4 root root 4096 Jul 31 11:15 ..
drwxr-xr-x 2 root root 4096 Jul 31 09:54 default
drwxr-xr-x 2 root root 4096 Aug  1 10:16 files
drwxr-xr-x 2 root root 4096 Jul 31 11:14 handlers
drwxr-xr-x 2 root root 4096 Jul 31 09:54 meta
drwxr-xr-x 2 root root 4096 Aug 29 09:31 tasks
drwxr-xr-x 2 root root 4096 Jul 31 11:14 templates
drwxr-xr-x 2 root root 4096 Jul 31 09:54 vars

cat playbook/roles/nginx/handlers/main.yml

- name: server restart
  service: name=nginx state=restarted

cat playbook/roles/nginx/tasks/main.yml

- include: user.yml
#- name: delsteamshell
#  copy: src=delsteam.sh dest=/tmp/delsteam.sh
#- name: run delsteamshell 
#  shell: /tmp/delsteam.sh

cat playbook/roles/nginx/tasks/main.yml.bak

#- include: user.yml
- name: install nginx
  shell: apt-get install -y nginx-full
- name: provides default.conf
  copy: src=default.conf dest=/etc/nginx/nginx.conf
  tags: nginxconf
  notify:
   - server restart
- name: server start
  service: name=nginx enabled=true state=started

cat playbook/roles/nginx/tasks/user.yml

- name: 创建用户
  user: name=toy state=present

ansible 角色定义及调用(nginx)

Roles的介绍

Roles是ansible自1.2版本引入的新特性,用于层次性,结构化地组织playbook,roles能够根据层次型结构自动自动装在变量文件、tasks以及handlers等。

创建roles的步骤

  • 创建以roles命名的目录:

  • 在roles目录中分别创建以各角色名称命名的目录,如webservers等:

  • 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录:用不到的目录可以创建为空目录,也可以不创建

  • 在playbook文件中,调用各角色

roles内各目录中可用的文件

  • tasks目录:至少创建一个名为main.yml的文件,其定义了此角色的任务列表:此文件可以使用include包含其他的位于此目录中的tasks文件

  • files目录:存放由copy或者script等模块调用的文件

  • templates目录:templates模块会自动在此目录中寻找模板文件

  • handlers目录:此目录中应当包含一个main

  • yml文件:用于定义此角色用到的各handler:在handler中使用include包含的其他的handler文件也应该位于此目录中

  • vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量

  • meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系:ansible 1.3及其以后的版本才支持

  • default目录:为当前角色定义默认变量时使用此目录,应该包含一个main.yml文件

实验环境

ansible:10.0.0.128
client :10.0.0.131

执行

1. 在服务器生成免密钥文件,推送到客户端

[root@ansible ~]# ssh-keygen 
[root@ansible ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub [email protected]

2. 安装ansible

[root@ansible ~]# yum install -y ansible

3. 到/etc/ansible 有个可以自定义roles的目录

[root@ansible ~]# cd /etc/ansible/
[root@ansible ansible]# ls
ansible.cfg  hosts  nginx.yaml  roles

4. 定义要执行的角色路径

[root@ansible ~]# cat /etc/ansible/nginx.yaml 
- hosts: 10.0.0.131
  remote_user: root
  roles:
  - nginx

5. 定义掩码安装nginx,在roles目录下的目录及文件都要自己创建

[root@ansible roles]# ls
nginx
[root@ansible roles]# cd nginx
[root@ansible nginx]# ls
files  handlers  tasks  templates  vars
[root@ansible ansible]# cd roles/
[root@ansible roles]# tree
.
└── nginx
    ├── files
    │   └── nginx-1.12.0.tar.gz
    ├── handlers
    │   └── main.yml
    ├── tasks
    │   └── main.yml
    ├── templates
    │   └── nginx.conf
    └── vars
        └── main.yml

6 directories, 5 files

6. 进入tasks目录创建任务

[root@ansible nginx]# cat tasks/main.yml 
- name: copy nginx packup to remote host
 copy: src=nginx-1.12.0.tar.gz dest=/usr/local/src/nginx-1.12.0.tar.gz
 tags: cppkg
- name: tar nginx
 shell: cd /usr/local/src/; tar -xf nginx-1.12.0.tar.gz
- name: install packger
 yum: name={{ item }} state=latest
 with_items:
   - openssl-devel
   - pcre-devel
   - gcc
- name: useradd
 shell: useradd nginx -s /sbin/nologin
- name: install nginx
 shell: cd /usr/local/src/nginx-1.12.0;./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-pcre;make && make install
- name: copy conf file nginx.conf
 template: src=nginx.conf dest=/usr/local/nginx/conf/nginx.conf
 notify: start nginx

7. 存放nginx压缩包目录

[root@ansible nginx]# ls files/
nginx-1.12.0.tar.gz    ##对应tasks第二行

8. template这一行对应的是template这个目录和主服务端定义的变量

[root@ansible nginx]# cat templates/nginx.conf 
#user  nobody;
worker_processes  
{{ ansible_processor_vcpus }};
#pid        logs/nginx.pid;
events {
    worker_connections  65532;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    server {

     listen       {{ ngxport }};
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            root   /web;
            index  index.html index.htm;
        }
        #error_page  404              /404.html;
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        #location ~ .php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}
    }
    include vhosts/*.conf;
}

9. 查看我们定义的变量,在vars目录下

[root@ansible nginx]# cat vars/main.yml 
ngxport: "8080"

10. 编辑触发器

[root@ansible nginx]# cat handlers/main.yml 
- name: start nginx     
  shell: /usr/local/nginx/sbin/nginx

11. 开始执行

[root@ansible nginx]# ansible-playbook -C /etc/ansible/nginx.yaml(测试)
[root@ansible nginx]# ansible-playbook  /etc/ansible/nginx.yaml 

PLAY [10.0.0.131] ************************************************************* 

GATHERING FACTS *************************************************************** 
ok: [10.0.0.131]

TASK: [nginx | copy nginx packup to remote host] ****************************** 
changed: [10.0.0.131]

TASK: [nginx | tar nginx] ***************************************************** 
changed: [10.0.0.131]

TASK: [nginx | install packger] *********************************************** 
ok: [10.0.0.131] => (item=openssl-devel,pcre-devel,gcc)

TASK: [nginx | useradd] ******************************************************* 
changed: [10.0.0.131]

TASK: [nginx | install nginx] ************************************************* 
changed: [10.0.0.131]

TASK: [nginx | copy conf file nginx.conf] ************************************* 
changed: [10.0.0.131]

NOTIFIED: [nginx | start nginx] *********************************************** 
changed: [10.0.0.131]

PLAY RECAP ******************************************************************** 
10.0.0.131                 : ok=8    changed=6    unreachable=0    failed=0   

12. 查看client客户端nginx服务已经启动

[root@zxb4 ~]# ps -ef |grep nginx
root      34655      1  0 02:13 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx     34656  34655  1 02:13 ?        00:00:01 nginx: worker process
root      34660  28130  0 02:16 pts/1    00:00:00 grep --color=auto nginx
[root@zxb4 ~]# netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      34655/nginx: master 

附加

假如我们经常要增加nginx站点,直接写好模板推送到vhos目录:

[root@ansible templates]# cat temp_server.conf
server
{
listen80;
server_name{{ server_name }};
indexindex.php index.html;
root {{root_dir }};
}

在vars定义变量:

[root@ansible vars]# cat main.yml
ngxport:"8080"
server_name:"www.xxx.com"
root_dir:"/web"

重写tasks步骤:

[root@ansible tasks]# cat main.yml
- name:copy conf file nginx.conf          # 调用templates模块
  template: src=temp_server.conf dest=/usr/local/nginx/conf/vhosts/{{server_name }}.conf
  tags: ngxconf
  notify: reload nginx service                # 调用handlers模块

Ansible使用playbook自动化编译安装Nginx

Ansible批量部署编译安装nginx

一、Ansible介绍

这次为大家介绍一款批量部署工具Ansible,主要有以下几点优点:1、充分利用现有设施。使用 Ansible 无需安装服务端和客户端,只要 SSH 即可。这意味着,任何一台装有 Ansible 的机器都可以成为强大的管理端。我觉得,这种去中心化的思路显得更为灵活。可能有人会担心 SSH 的效率,Ansible 的并行执行及加速模式或许可以打消你的顾虑。2、使用简单,快速上手相当容易。Ansible 上手十分快,用 Ad-Hoc 可以应付简单的管理任务,麻烦点的也可以定义 Playbook 文件来搞定。3、采用人类易读的格式。Ansible 的主机定义文件使用 INI 格式,支持分组,能够指定模式;此外也能动态生成,这对管理云主机应当很有用。而 Playbook 则是 YAML 格式。4、能够使用你熟悉的语言来编写模块。虽然 Ansible 是使用 Python 开发的,但它不会将你限制到某种具体的编程语言,Bash、Python、Perl、Ruby 等等都可以,你擅长什么就用什么。

一言以蔽之,Ansible 背后的简单化哲学深得我心。这也比较符合我选择软件的一贯原则。可能还有人会比较关心目前 Ansible 都有谁在用。毕竟,榜样的力量是无穷。Puppet 不正是因为 Google 在用而吸引了不少眼球么?据我所知,当前使用 Ansible 较为知名的用户包括 Fedora、Rackspace、Evernote 等等。

Ansible企业应用:

未分类

二、主要架构功能

Ansible Core.    //核心功能

Modules:

Core Modules    //核心功能

Customed Modules  //自定义模块

Host Inventory        //主机库和主机清单,用来定义要管理的主机

File

CMDB(配置管理数据)

PlayBooks            //剧本,定义没个主机扮演的角色

Hosts.        //主机

roles.        //角色

Connection Plugins.  //连接插件,连接至被管控主机,完成并发连接,默认一次管理5台,但是可以修改。

三、安装配置

安装:

# yum install ansible -y  (epel仓库中)

程序:

ansible

ansible-playbook  //唱剧本

ansible-doc        //获取帮助文档

配置文件

/etc/ansible/ansible.cfg    //核心配置文件

主机清单:

/etc/ansible/hosts

插件目录:

/usr/share/ansible_plugins/

1、设置ansble到各个主机的免密钥通讯:

[root@cml1~]# ssh-keygen
[root@cml1~]# ssh-copy-id 192.168.5.102

2、定义主机组:

[root@cml1~]# cd /etc/ansible/
[root@cml1ansible]# vim hosts 
[webserver]
192.168.5.102
192.168.5.104

3、查看主机组内的主机:

[root@cml1ansible]# ansible webserver --list-hosts 
  hosts (2):
    192.168.5.102
    192.168.5.104

4、定义角色路径

[root@cml1~]# cat /etc/ansible/nginx.yaml 
- hosts: 192.168.5.102
 remote_user: root
  roles:
  -nginx_install    ###roles目录下的nginx_install目录
  -nginx_config    ###roles目录下的nginx_config目录

5、查看目录结构:

[root@cml1 roles]# tree
.
├── nginx_config
│  ├── default
│  ├── files
│  ├── handlers
│  │  └── main.yml
│  ├── meta
│  ├── tasks
│  │  └── main.yml
│  ├── templates
│  │  └── temp_server.conf
│  └── vars
│      └── main.yml
└── nginx_install
    ├──default
    ├──files
  │  └── nginx-1.12.0.tar.gz
    ├──handlers
  │  └── main.yml
    ├──meta
    ├──tasks
  │  └── main.yml
    ├──templates
  │  └── nginx.conf
└── vars
[root@cml1roles]# cd nginx_install/
[root@cml1nginx_install]# ls
default  files handlers  meta  tasks templates  vars

6、task定义开始任务:

[root@cml1nginx_install]# cd tasks/
[root@cml1tasks]# cat main.yml 
- name: copynginx package to remote host  
  copy: src=nginx-1.12.0.tar.gz  dest=/tmp/nginx-1.12.0.tar.gz  ##拉取nginx解压吧
  tags: cppkg
- name: tarnginx
  shell: cd /tmp;tar -xf nginx-1.12.0.tar.gz  ##解压nginx包
- name: installpakger
  yum: name={{ item }} state=latest    ##安装依赖包
  with_items:
    - openssl-devel
    - pcre-devel
    - gcc
- name: installnginx
  shell: cd /tmp/nginx-1.12.0;./configure--user=nginx --group=nginx --prefix=/usr/local/nginx--with-http_stub_status_module --with-http_ssl_module --with-pcre;make&& make install      ####编译安装
- name: copyconf file nginx.conf          
  template: src=nginx.confdest=/usr/local/nginx/conf/nginx.conf  ###复制在template目录下的配置文件
  tags: ngxconf
- name: copyshell
  copy: src=/opt/create_users.shdest=/tmp/create_users.sh  ##拉取创建用户的shell脚本
- name: createuser nginx
  shell: /bin/bash /tmp/create_users.sh
  tags: addnginx
  notify: start nginx service

为什么要写这个脚本?因为加入有些主机创建的用户已存在就会报错

[root@cml1tasks]# cat /opt/create_users.sh 
#!/bin/bash
a=`cat/etc/passwd | grep nginx | wc -l`
if [ $a == 0];then
      useradd nginx
fi

6、第二行copy对应file目录:

[root@cml1nginx_install]# cd files/
[root@cml1files]# ls
nginx-1.12.0.tar.gz

7、template这一行对应的是template这个目录和主服务端定义的变量:

[root@cml1nginx_install]# cd templates/
[root@cml1templates]# ls
nginx.conf
[root@cml1templates]# cat nginx.conf 

user  nginx;
worker_processes  {{ ansible_processor_vcpus }};

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  65535;
}


http {


    include      mime.types;
    default_type  application/octet-stream;

    #log_format main  '$remote_addr - $remote_user[$time_local] "$request" '
    #                  '$status $body_bytes_sent"$http_referer" '
    #                  '"$http_user_agent""$http_x_forwarded_for"';
  log_format xiaoluo  '$remote_addr -$remote_user  [$time_local]  '
                            '"$request"  $status$body_bytes_sent '
                            '"$http_referer" "$http_user_agent" ';
    #access_log logs/access.log  main;

    sendfile        on;
    #tcp_nopush    on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip on;

    server {
        listen      {{ ngxport }};  
        server_name  wwwNaNl.com
        access_log logs/wwwNaNl.com  xiaoluo;
        #location / {
        #  proxy_pass http://192.168.5.101;
        #}

        #error_page  404              /404.html;

        # redirect server error pages to thestatic page /50x.html
        #
        error_page  500 502 503 504  /50x.html;
        location = /50x.html {
            root  html;
        }

        # proxy the PHP scripts to Apachelistening on 127.0.0.1:80
        #
        #location ~ .php$ {
        #  proxy_pass  http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGIserver listening on 127.0.0.1:9000
        #
        location ~ .php$ {
            root          /web;
            fastcgi_pass  127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME$document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

        # deny access to .htaccess files, ifApache's document root
        # concurs with nginx's one
        #
        #location ~ /.ht {
        #  deny  all;
        #}
    }
  include vhosts/*.conf;
}##需要注意的就是模板变量(客户端自动采集)、和在服务端定义的变量{{ngx_port}}

8、在vars定义变量:

[root@cml1nginx_install]# cd vars/
[root@cml1vars]# cat main.yml 
ngxport:"8080"

9、定义触发器:

[root@cml1nginx_install]# cd handlers/
[root@cml1handlers]# cat main.yml 
- name: startnginx service 
  shell: /usr/loal/nginx/sbin/nginx

10、在nginx_config目录加入我们经常要增加nginx站点,直接写好模板推送到vhos目录:

[root@cml1roles]# cd nginx_config/
[root@cml1nginx_config]# ls
default  files handlers  meta  tasks templates  vars
[root@cml1nginx_config]# cd templates/
[root@cml1templates]# ls
temp_server.conf
[root@cml1templates]# cat temp_server.conf 
server 
{ 
listen 80; 
server_name {{server_name }}; 
index index.phpindex.html; 
root {{root_dir }}; 
}

###在var定义变量:
[root@cml1templates]# cd ../vars/
[root@cml1vars]# cat main.yml 
server_name: "www.xiaoluo.com"
root_dir:"/web"

11、写配置nginx的tasks步骤:

[root@cml1nginx_config]# cd tasks/
[root@cml1tasks]# ls
main.yml
[root@cml1tasks]# cat main.yml 
- name: createvhosts
  shell: mkdir -p /usr/local/nginx/conf/vhosts/
  tags: create_dir
- name: copyconf file nginx.conf          # 调用templates模块
  template: src=temp_server.confdest=/usr/local/nginx/conf/vhosts/{{ server_name }}.conf
  tags: ngxconf
  notify: reload nginx service 
###定义重启触发器:
[root@cml1tasks]# cd ../handlers/
You have newmail in /var/spool/mail/root
[root@cml1handlers]# cat main.yml 
- name: reloadnginx service
  shell: /usr/local/nginx/sbin/nginx-t;/usr/local/nginx/sbin/nginx -s reload

测试:

[root@cml1ansible]# ansible-playbook -C nginx.yaml 

PLAY[192.168.5.104] ********************************************************** 

GATHERING FACTS*************************************************************** 
ok:[192.168.5.104]

TASK:[nginx_install | copy nginx package to remote host] ********************* 
changed:[192.168.5.104]

TASK:[nginx_install | tar nginx] ********************************************* 
skipping:[192.168.5.104]
ok:[192.168.5.104]

TASK:[nginx_install | install pakger] **************************************** 
changed: [192.168.5.104]=> (item=openssl-devel,pcre-devel,gcc)

TASK:[nginx_install | install nginx] ***************************************** 
skipping:[192.168.5.104]
ok:[192.168.5.104]

TASK:[nginx_install | copy conf file nginx.conf] ***************************** 
changed:[192.168.5.104]

TASK:[nginx_install | copy shell] ******************************************** 
changed:[192.168.5.104]

TASK:[nginx_install | create user nginx] ************************************* 
skipping:[192.168.5.104]
ok: [192.168.5.104]

TASK:[nginx_config | create vhosts] ****************************************** 
skipping:[192.168.5.104]
ok:[192.168.5.104]

TASK:[nginx_config | copy conf file nginx.conf] ****************************** 
changed:[192.168.5.104]

NOTIFIED:[nginx_config | reload nginx service] ******************************* 
skipping:[192.168.5.104]
ok:[192.168.5.104]

PLAY RECAP******************************************************************** 
192.168.5.104              : ok=6    changed=5  unreachable=0    failed=0[root@cml1 ansible]# ansible-playbook  nginx.yaml 
PLAY [192.168.5.104] ********************************************************** 
GATHERING FACTS *************************************************************** 
ok: [192.168.5.104]
TASK: [nginx_install | copy nginx package to remote host] ********************* 
ok: [192.168.5.104]
TASK: [nginx_install | tar nginx] ********************************************* 
changed: [192.168.5.104]
TASK: [nginx_install | install pakger] **************************************** 
ok: [192.168.5.104] => (item=openssl-devel,pcre-devel,gcc)
TASK: [nginx_install | install nginx] ***************************************** 
changed: [192.168.5.104]
TASK: [nginx_install | copy conf file nginx.conf] ***************************** 
ok: [192.168.5.104]
TASK: [nginx_install | copy shell] ******************************************** 
ok: [192.168.5.104]
TASK: [nginx_install | create user nginx] ************************************* 
changed: [192.168.5.104]
TASK: [nginx_config | create vhosts] ****************************************** 
changed: [192.168.5.104]
TASK: [nginx_config | copy conf file nginx.conf] ****************************** 
ok: [192.168.5.104]
NOTIFIED: [nginx_install | start nginx service] ******************************* 
changed: [192.168.5.104]
PLAY RECAP ******************************************************************** 
192.168.5.104              : ok=11  changed=5    unreachable=0    failed=0[root@cml3 ~]# ifconfig
ens34: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.5.104  netmask 255.255.255.0  broadcast 192.168.5.255


[root@cml3 ~]# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address          Foreign Address        State      PID/Program name              
tcp        0      0 0.0.0.0:80              0.0.0.0:*              LISTEN      29264/nginx: master 
tcp        0      0 0.0.0.0:8080            0.0.0.0:*              LISTEN      29264/nginx: master 

四、定义日志文件

下面是介绍如何定义日志:(在ansible1.9.1版本之后有个bug所以定义不了日志文件只能降版本到1.9.1了)

1、ansible倒回去版本:1.9.1

需要安装gcc、python-devel

[root@cml1 ~]#yum install python-pip
[root@cml1 ~]#pip install ansible==1.9.1

2、callback插件:

[root@cml1tasks]# vim /etc/ansible/ansible.cfg
callback_plugins  = /usr/share/ansible/plugins/callback
bin_ansible_callbacks= True

3、在callback目录下创建日志处理文件:

[root@cml1tasks]# cd /usr/share/ansible/plugins/callback
[root@cml1callback]# ls
log.py  log.pyc
[root@cml1callback]# cat log.py
import os
import time
import json

TIME_FORMAT="%b%d %Y %H:%M:%S"
MSG_FORMAT="%(now)s- %(category)s - %(data)snn"

if notos.path.exists("/var/log/ansible/hosts"):
  os.makedirs("/var/log/ansible/hosts")

def log(host,category, data):
    if type(data) == dict:
        if 'verbose_override' in data:
            # avoid logging extraneous datafrom facts
            data = 'omitted'
        else:
            data = data.copy()
            invocation = data.pop('invocation',None)
            data = json.dumps(data)
            if invocation is not None:
                data = json.dumps(invocation) +" => %s " % data

    path =os.path.join("/var/log/ansible/hosts", host)
    now = time.strftime(TIME_FORMAT,time.localtime())
    fd =open(path, "a")
    fd.write(MSG_FORMAT % dict(now=now,category=category, data=data))
    fd.close()

classCallbackModule(object):
    """
    logs playbook results, per host, in/var/log/ansible/hosts
    """

    def on_any(self, *args, **kwargs):
        pass

    def runner_on_failed(self, host, res,ignore_errors=False):
        log(host, 'FAILED', res)

    def runner_on_ok(self, host, res):
        log(host, 'OK', res)

    def runner_on_skipped(self, host,item=None):
        log(host, 'SKIPPED', '...')

    def runner_on_unreachable(self, host, res):
        log(host, 'UNREACHABLE', res)

    def runner_on_no_hosts(self):
        pass

    def runner_on_async_poll(self, host, res,jid, clock):
        pass

    def runner_on_async_ok(self, host, res,jid):
        pass

    def runner_on_async_failed(self, host, res,jid):
        log(host, 'ASYNC_FAILED', res)

    def playbook_on_start(self):
        pass

    def playbook_on_notify(self, host,handler):
        pass

    def playbook_on_no_hosts_matched(self):
        pass

    def playbook_on_no_hosts_remaining(self):
        pass

    def playbook_on_task_start(self, name,is_conditional):
        pass

    def playbook_on_vars_prompt(self, varname,private=True, prompt=None, encrypt=None, confirm=False, salt_size=None,salt=None, default=None):
        pass

    def playbook_on_setup(self):
        pass

    def playbook_on_import_for_host(self, host,imported_file):
        log(host, 'IMPORTED', imported_file)

    def playbook_on_not_import_for_host(self,host, missing_file):
        log(host, 'NOTIMPORTED', missing_file)

    def playbook_on_play_start(self, name):
        pass

    def playbook_on_stats(self, stats):
        pass

Ansible服务部署与使用 – ansible-playbook剧本

第4章 ansible-playbook 剧本

4.1 ansible基础知识部分补充

4.1.1 ansible软件特点:

  • 可以实现批量管理

  • 可以实现批量部署

  • ad-hoc(批量执行命令)—针对临时性的操作

ansible linuxidc -m command -a “hostname” <- 批量执行命令举例

  • 编写剧本-脚本(playbook)—针对重复性的操作

4.1.2 ansible核心功能:

pyYAML—–用于ansible编写剧本所使用的语言格式(saltstack—python)

rsync-ini语法 sersync-xml语法 ansible-pyYAML语法

paramiko—远程连接与数据传输

Jinja2—–用于编写ansible的模板信息

4.2 ansible剧本编写规则说明

4.2.1 pyYAML语法规则

规则一:缩进

yaml使用一个固定的缩进风格表示数据层结构关系,Saltstack需要每个缩进级别由两个空格组成。一定不能使用tab键

注意:编写yaml文件,就忘记键盘有tab

规则二:冒号

CMD=”echo”

yaml:

mykey:

每个冒号后面一定要有一个空格(以冒号结尾不需要空格,表示文件路径的模版可以不需要空格)

规则三:短横线

想要表示列表项,使用一个短横杠加一个空格。多个项使用同样的缩进级别作为同一个列表的一部分

核心规则:有效的利用空格进行剧本的编写,剧本编写是不支持tab的

4.3 剧本书写格式

### 剧本的开头,可以不写
- hosts: all         <- 处理所有服务器,找到所有服务器;  -(空格)hosts:(空格)all
tasks:             <- 剧本所要干的事情;                (空格)(空格)task:
- command: echo hello linuxidc linux.  
  (空格)(空格)空格)(空格)-(空格)模块名称:(空格)模块中对应的功能
 ansible all -m command -a "echo hello linuxidc linux"     

    剧本编写内容扩展:剧本任务定义名称

- hosts: 172.16.1.7  <- 处理指定服务器                   -(空格)hosts:(空格)all
task:                <- 剧本所要干的事情;                (空格)(空格)task:
- name:
command: echo hello linuxidc linux.                   
(空格)(空格)空格)(空格)-(空格)模块名称:(空格)模块中对应的功能

4.3.1 剧本格式示例

[root@m01 ansible-playbook]# vim rsync_sever.yml
- hosts: 172.16.1.41
  tasks:
    - name: install rsync
      yum: name=rsync state=installed

4.4 剧本编写后检查方法

01:ansible-playbook --syntax-check 01.yml 

        --- 进行剧本配置信息语法检查

02:ansible-playbook -C 01.yml             

           --- 模拟剧本执行(彩排)

4.4.1 语法检查

[root@m01 ansible-playbook]# ansible-playbook --syntax-check 01.yml
playbook: 01.yml

4.4.2 模拟剧本执行

[root@m01 ansible-playbook]# ansible-playbook -C 01.yml
PLAY [all] ****************************************************************

TASK [Gathering Facts] ****************************************************
ok: [172.16.1.41]
ok: [172.16.1.8]
ok: [172.16.1.31]

TASK [cron] ***************************************************************
ok: [172.16.1.8]
ok: [172.16.1.41]
ok: [172.16.1.31]

PLAY RECAP ****************************************************************
172.16.1.31                : ok=2    changed=0    unreachable=0    failed=0
172.16.1.41                : ok=2    changed=0    unreachable=0    failed=0
172.16.1.8                 : ok=2    changed=0    unreachable=0    failed=0

4.5 剧本示例

4.5.1 剧本编写内容扩展:剧本任务编写多个任务

- hosts: all
  tasks:
    - name: restart-network
      cron: name='restart network' minute=00 hour=00 job='/usr/sbin/ntpdate time.nist.gov >/dev/null 2>&1'
    - name: sync time
      cron: name='sync time' minute=*/5 job="/usr/sbin/ntpdate pool.ntp.com >/dev/null 2>&1"

4.5.2 剧本编写内容扩展:剧本任务编写多个主机

- hosts: 172.16.1.7
  tasks:
    - name: restart-network
      cron: name='restart network' minute=00 hour=00 job='/usr/sbin/ntpdate time.nist.gov >/dev/null 2>&1'
    - name: sync time
      cron: name='sync time' minute=*/5 job="/usr/sbin/ntpdate pool.ntp.com >/dev/null 2>&1"
- hosts: 172.16.1.31
  tasks:
    - name: show ip addr to file
      shell: echo $(hostname -i) >> /tmp/ip.txt

4.6 剧本编写方式

01 多主机单任务编写方式

02 多主机多任务编写方式

03 不同主机多任务编写方式


第5章 常见错误

5.1 ansible编写剧本排错思路

  • ansible-playbook编写完,检査语法和模拟测试运行

  • 打开剧本,定位异常问題原因,将剧本中的内容转换命令执行一次

cron: name=linuxidc64 minute=ee hour=03 job='/bin/sh /server/scripts/test.sh &>/dev/null'
ansible linuxidc -m cron -a "name=linuxidc64 minute=00 hour=03 job='/bin/sh /server/scripts/test.sh &>/dev/null
  • 将参数中的脚本文件推送到远程服务器,在远程服务器本地执行脚本 sh -x test.sh

说明:ansible执行时,加1上-vvvv显示ansible详细执行过程,也可以定位异常原因!

5.1.1 排错逻辑

  1. 剧本执行中的错误

  2. 把剧本中的内容转换为ansible命令执行

ansible linuxidc -m yum -a "name=rsync state=installed"
  1. 把ansible服务器上执行的命令放在被管理主机上执行
yum install -y rsync

5.2 ansible 无法正常使用

5.2.1 在被控端上 root@notty 进程一直存在

[root@backup ~]# ps -ef|grep sshd
root      35274      1  0 15:25 ?        00:00:00 /usr/sbin/sshd
root      37004  35274  0 16:23 ?        00:00:00 sshd: root@pts/2 
root      37062  35274  0 16:55 ?        00:00:00 sshd: root@notty 
root      37154  37006  0 16:55 pts/2    00:00:00 grep --color=auto sshd

5.2.2 解决办法

首先,将该进程干掉

kill pid

5.2.3 然后使用ansible的 -vvvv 参数查看执行的错误信息

Loading callback plugin minimal of type stdout, v2.0 from /usr/lib/python2.6/site-packages/ansible/plugins/callback/__init__.pyc
META: ran handlers
Using module file /usr/lib/python2.6/site-packages/ansible/modules/system/ping.py
<172.16.1.8> ESTABLISH SSH CONNECTION FOR USER: None
<172.16.1.8> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/923ebeb605 172.16.1.8 '/bin/sh -c '"'"'echo ~ && sleep 0'"'"''
……

找到在哪里出错。

5.2.4 可能的错误

在 /etc/ssh/sshd_config 文件中的第132行为空,导致sftp 无法连接,出错~

133 Subsystem      sftp    /usr/libexec/openssh/sftp-server

5.3 常见问题二

[root@m01 ~]# ansible  -k 172.16.1.51 -m ping
SSH password:
[WARNING]: No hosts matched, nothing to do

**原因分析:88

在ansible的hosts文件中,没有配置相应主机地址信息

5.3.1 常见问题三

# ansible -k 172.16.1.51 -m ping
SSH password:
172.16.1.51|FAILED! => {
"failed": true,
"msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
}

原因分析:

因为没有受控端的指纹信息,在known_hosts文件中

本博文中所使用的系统版本为: CentOS release 6.9 (Final) 内核版本为: 2.6.32-696.10.1.el6.x86_64 望读者注意!

Ansible服务部署与使用-Ansible模块

第3章 Ansible中的模块说明

3.1 ping 模块:测试连通性

[root@m01 ~]# ansible all -m ping 
172.16.1.8 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
172.16.1.41 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
172.16.1.31 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

连接正常返回 pong 通过帮助信息可以获得 ↓

通过 ansible-doc -v ping 可以获得该模块的说明

ansible-doc -s file 参看模块的具体信息

[root@m01 ~]# ansible-doc -v ping
Using /etc/ansible/ansible.cfg as config file
> PING    (/usr/lib/python2.6/site-packages/ansible/modules/system/ping.py)

  A trivial test module, this module always returns `pong' on successful contact. It does not make sense in playbooks, but it is useful from `/usr/bin/ansible' to verify the ability to login and that a usable  python is configured. This is NOT ICMP ping, this is just a trivial test module.

3.2 command 模块 默认模块

3.2.1 command命令常用参数说明

未分类

不指定模块的时候默认使用的模块就是command ↓

[root@m01 ~]# ansible all -a "date"
172.16.1.41 | SUCCESS | rc=0 >>
Thu Oct 19 17:12:15 CST 2017

172.16.1.31 | SUCCESS | rc=0 >>
Thu Oct 19 17:12:15 CST 2017

172.16.1.8 | SUCCESS | rc=0 >>
Thu Oct 19 17:12:15 CST 2017

使用ansible自带模块执行命令 如果要用 > < | & ‘ ‘ 使用shell模块

[root@m01 ~]# ansible all -m command -a "date"
172.16.1.8 | SUCCESS | rc=0 >>
Thu Oct 19 17:12:27 CST 2017

172.16.1.31 | SUCCESS | rc=0 >>
Thu Oct 19 17:12:28 CST 2017

172.16.1.41 | SUCCESS | rc=0 >>
Thu Oct 19 17:12:27 CST 2017

chdir参数的使用:

[root@m01 ~]# ansible linuxidc -m command -a "chdir=/tmp pwd"
172.16.1.31 | SUCCESS | rc=0 >>
/tmp

172.16.1.8 | SUCCESS | rc=0 >>
/tmp

172.16.1.41 | SUCCESS | rc=0 >>
/tmp

creates 文件是否存在,不存在就执行命令

[root@m01 ~]# ansible linuxidc -m command -a "creates=/etc/hosts date"
172.16.1.31 | SUCCESS | rc=0 >>
skipped, since /etc/hosts exists

removes 文件是否存在,不存在就不执行命令,

[root@m01 ~]# ansible linuxidc -m command -a "removes=/etc/hosts date"
172.16.1.31 | SUCCESS | rc=0 >>
Fri Oct 20 13:32:40 CST 2017

3.3 shell模块 万能模块

执行linux命令时可以用

远程节点执行命令

说明: shell 模块在远程执行脚本时,远程主机上一定要有相应的脚本

[root@m01 ~]# ansible linuxidc -m shell -a "/bin/sh /server/scripts/ssh-key.sh"
172.16.1.31 | SUCCESS | rc=0 >>
fenfa 172.16.1.31 [  OK  ]

fenfa 172.16.1.41 [  OK  ]

fenfa 172.16.1.8 [  OK  ]

3.4 script 模块 执行脚本模块

在本地执行脚本时,将脚本中的内容传输到远程节点上运行

[root@m01 ~]# ansible all -m script -a "/server/scripts/free.sh"
172.16.1.8 | SUCCESS => {
    "changed": true,
    "rc": 0,
    "stderr": "Shared connection to 172.16.1.8 closed.rn",
    "stdout": "             total       used       free     shared    buffers     cachedrnMem:          474M       377M        97M       532K        54M       202Mrn-/+ buffers/cache:       120M       354MrnSwap:         767M         0B       767Mrn",
    "stdout_lines": [
        "             total       used       free     shared    buffers     cached",
        "Mem:          474M       377M        97M       532K        54M       202M",
        "-/+ buffers/cache:       120M       354M",
        "Swap:         767M         0B       767M"
    ]
}

说明:

使用scripts模块,不用将脚本传输到远程节点,脚本本身不用进行授权,即可利用script模块执行。直接执行脚本即可,不需要使用sh

3.5 copy模块 把本地文件发送到远端

3.5.1 copy模块常用参数

未分类

说明: src和content不能同时使用

3.5.2 copy常用命令参数测试

使用copy 模块,将/etc/hosts 文件 传输到各个服务器送,权限修改为0600 属主属组为linuxidc

[root@m01 ~]# ansible linuxidc -m copy -a "src=/etc/hosts dest=/tmp/ mode=0600 owner=linuxidc group=oldboy "
172.16.1.8 | SUCCESS => {
    "changed": true,
    "checksum": "b3c1ab140a1265cd7f6de9175a962988d93c629b",
    "dest": "/tmp/hosts",
    "gid": 500,
    "group": "linuxidc",
    "md5sum": "8c2b120b4742a806dcfdc8cfff6b6308",
    "mode": "0600",
    "owner": "linuxidc",
    "size": 357,
    "src": "/root/.ansible/tmp/ansible-tmp-1508410846.63-224022812989166/source",
    "state": "file",
    "uid": 500
}
……

检查结果

[root@m01 ~]# ansible all -m shell -a "ls -l /tmp/hosts"
172.16.1.31 | SUCCESS | rc=0 >>
-rw------- 1 linuxidc oldboy 357 Oct 19 19:00 /tmp/hosts

172.16.1.41 | SUCCESS | rc=0 >>
-rw------- 1 linuxidc oldboy 357 Oct 11 15:12 /tmp/hosts

172.16.1.8 | SUCCESS | rc=0 >>
-rw------- 1 linuxidc oldboy 357 Oct 19 19:00 /tmp/hosts

移动远程主机上的文件 remote_src=true 参数

[root@m01 ~]# ansible linuxidc -m copy -a " src=/server/scripts/ssh-key.sh  dest=/tmp/ remote_src=true"
172.16.1.41 | SUCCESS => {
    "changed": true,
    "checksum": "d27bd683bd37e15992d2493b50c9410e0f667c9c",
    "dest": "/tmp/ssh-key.sh",
    "gid": 0,
    "group": "root",
    "md5sum": "dc88a3a419e3657bae7d3ef31925cbde",
    "mode": "0644",
    "owner": "root",
    "size": 397,
    "src": "/server/scripts/ssh-key.sh",
    "state": "file",
    "uid": 0
}

定义文件中的内容 content=linuxidcedu.com 默认没有换行

[root@m01 ~]# ansible linuxidc -m copy -a "content=linuxidcedu.com dest=/tmp/linuxidc666.txt"
172.16.1.8 | SUCCESS => {
    "changed": true,
    "checksum": "291694840cd9f9c464263ea9b13421d8e74b7d00",
    "dest": "/tmp/linuxidc666.txt",
    "gid": 0,
    "group": "root",
    "md5sum": "0a6bb40847793839366d0ac014616d69",
    "mode": "0644",
    "owner": "root",
    "size": 13,
    "src": "/root/.ansible/tmp/ansible-tmp-1508466752.1-24733562369639/source",
    "state": "file",
    "uid": 0
}

3.6 file模块 设置文件属性

3.6.1 file模块常用参数

未分类

注意:重命名和创建多级目录不能同时实现

3.6.2 常用参数测试

创建目录

[root@m01 ~]# ansible linuxidc -m file -a "dest=/tmp/linuxidc_dir state=directory"
172.16.1.41 | SUCCESS => {
    "changed": true,
    "gid": 0,
    "group": "root",
    "mode": "0755",
    "owner": "root",
    "path": "/tmp/linuxidc_dir",
    "size": 4096,
    "state": "directory",
    "uid": 0
}

创建文件

[root@m01 ~]# ansible linuxidc -m file -a "dest=/tmp/linuxidc_file state=touch"
172.16.1.8 | SUCCESS => {
    "changed": true,
    "dest": "/tmp/linuxidc_file",
    "gid": 0,
    "group": "root",
    "mode": "0644",
    "owner": "root",
    "size": 0,
    "state": "file",
    "uid": 0
}

创建软连接

[root@m01 ~]# ansible linuxidc -m file -a "src=/tmp/linuxidc_file dest=/tmp/linuxidc_file_link state=link"
172.16.1.41 | SUCCESS => {
    "changed": true,
    "dest": "/tmp/linuxidc_file_link",
    "gid": 0,
    "group": "root",
    "mode": "0777",
    "owner": "root",
    "size": 16,
    "src": "/tmp/linuxidc_file",
    "state": "link",
    "uid": 0
}

删除目录文件信息

[root@m01 ~]# ansible linuxidc -m file -a "dest=/tmp/linuxidc_dir state=absent"
172.16.1.41 | SUCCESS => {
    "changed": true,
    "path": "/tmp/linuxidc_dir",
    "state": "absent"

[root@m01 ~]# ansible linuxidc -m file -a "dest=/tmp/linuxidc_file state=absent"
172.16.1.31 | SUCCESS => {
    "changed": true,
    "path": "/tmp/linuxidc_file",
    "state": "absent"

创建多级目录

[root@m01 ~]# ansible linuxidc -m copy -a "src=/etc/hosts dest=/tmp/01/0/0/0/0/0/0/0/"
172.16.1.31 | SUCCESS => {
    "changed": true,
    "checksum": "b3c1ab140a1265cd7f6de9175a962988d93c629b",
    "dest": "/tmp/01/0/0/0/0/0/0/0/hosts",
    "gid": 0,
    "group": "root",
    "md5sum": "8c2b120b4742a806dcfdc8cfff6b6308",
    "mode": "0644",
    "owner": "root",
    "size": 357,
    "src": "/root/.ansible/tmp/ansible-tmp-1508466973.39-99676412390473/source",
    "state": "file",
    "uid": 0
}

注意:重命名和创建多级目录不能同时实现

3.7 fetch 模块 拉取文件

3.7.1 fetch常用参数说明

未分类

3.7.2 常用参数实例

从远程拉取出来文件

[root@m01 cp]# ansible linuxidc -m fetch -a "dest=/tmp/backup src=/etc/hosts"
172.16.1.8 | SUCCESS => {
    "changed": true,
    "checksum": "b3c1ab140a1265cd7f6de9175a962988d93c629b",
    "dest": "/tmp/backup/172.16.1.8/etc/hosts",
    "md5sum": "8c2b120b4742a806dcfdc8cfff6b6308",
    "remote_checksum": "b3c1ab140a1265cd7f6de9175a962988d93c629b",
    "remote_md5sum": null
}
[root@m01 cp]# tree /tmp/backup/
/tmp/backup/
├── 172.16.1.31
│   └── etc
│       └── hosts
├── 172.16.1.41
│   └── etc
│       └── hosts
└── 172.16.1.8
    └── etc
        └── hosts

flat 参数,拉去的时候不创建目录(同名文件会覆盖)

[root@m01 tmp]# ansible linuxidc -m fetch -a "dest=/tmp/backup/ src=/etc/hosts flat=yes"
172.16.1.8 | SUCCESS => {
    "changed": false,
    "checksum": "b3c1ab140a1265cd7f6de9175a962988d93c629b",
    "dest": "/tmp/backup/hosts",
    "file": "/etc/hosts",
    "md5sum": "8c2b120b4742a806dcfdc8cfff6b6308"

3.8 mount模块 配置挂载点模块

3.8.1 mount模块常用参数

未分类

3.8.2 mount参数实例

挂载

[root@m01 tmp]# ansible 172.16.1.8 -m mount -a "fstype=nfs opts=rw path=/mnt/  src=172.16.1.31:/data/ state=mounted"
172.16.1.8 | SUCCESS => {
    "changed": true,
    "dump": "0",
    "fstab": "/etc/fstab",
    "fstype": "nfs",
    "name": "/mnt/",
    "opts": "rw",
 "passno": "0",
  "src": "172.16.1.31:/data/"
}

卸载

[root@m01 tmp]# ansible 172.16.1.8 -m mount -a "fstype=nfs opts=rw path=/mnt/  src=172.16.1.31:/data/ state=unmounted"
172.16.1.8 | SUCCESS => {
   "changed": true,
    "dump": "0",
    "fstab": "/etc/fstab",
    "fstype": "nfs",
    "name": "/mnt/",
    "opts": "rw",
    "passno": "0",
    "src": "172.16.1.31:/data/"
}

3.9 cron模块 定时任务

3.9.1 cron模块常用参数

未分类

3.9.2 cron模块参数实践

添加定时任务

[root@m01 ~]# ansible linuxidc -m cron -a "minute=0 hour=0 job='/bin/sh  /server/scripts/hostname.sh &>/dev/null' name=linuxidc01"
172.16.1.8 | SUCCESS => {
    "changed": true,
    "envs": [],
    "jobs": [
     "linuxidc01"
    ]
}

删除定时任务

[root@m01 ~]# ansible linuxidc -m cron -a "minute=00 hour=00 job='/bin/sh  /server/scripts/hostname.sh &>/dev/null' name=linuxidc01 state=absent"
172.16.1.8 | SUCCESS => {
    "changed": true,
    "envs": [],
    "jobs": []
}

只用名字就可以删除

[root@m01 ~]# ansible linuxidc -m cron -a "name=linuxidc01  state=absent"
172.16.1.31 | SUCCESS => {
    "changed": true,
    "envs": [],
    "jobs": []
}

注释定时任务

注意: 注释定时任务的时候必须有job的参数

[root@m01 ~]# ansible linuxidc -m cron -a "name=linuxidc01 job='/bin/sh  /server/scripts/hostname.sh &>/dev/null'  disabled=yes"
172.16.1.31 | SUCCESS => {
    "changed": true,
    "envs": [],
    "jobs": [
    "linuxidc01"
    ]
}

取消注释

[root@m01 ~]# ansible linuxidc -m cron -a "name=linuxidc01 job='/bin/sh  /server/scripts/hostname.sh &>/dev/null'  disabled=no"
172.16.1.41 | SUCCESS => {
    "changed": true,
    "envs": [],
   "jobs": [
       "linuxidc01"
    ]
}

3.10 yum 模块

3.10.1 yum 模块常用参数

未分类

3.10.2 yum模块参数实践

[root@m01 ~]# ansible linuxidc -m yum -a "name=nmap state=installed  "
172.16.1.31 | SUCCESS => {
    "changed": true,
    "msg": "",
    "rc": 0,
    "results": [
        "Loaded plugins: fastestmirror, securitynSetting up Install ProcessnLoading mirror speeds from cached hostfilen * base: mirrors.aliyun.comn * epel: mirrors.aliyun.comn * extras: mirrors.aliyun.comn * updates: mirrors.aliyun.comnResolving Dependenciesn--> Running transaction checkn---> Package nmap.x86_64 2:5.51-6.el6 will be installedn--> Finished Dependency ResolutionnnDependencies Resolvednn================================================================================n Package        Arch             Version                   Repository      Sizen================================================================================nInstalling:n nmap           x86_64           2:5.51-6.el6              base           2.8 MnnTransaction Summaryn================================================================================nInstall       1 Package(s)nnTotal download size: 2.8 MnInstalled size: 9.7 MnDownloading Packages:nRunning rpm_check_debugnRunning Transaction TestnTransaction Test SucceedednRunning Transactionnr  Installing : 2:nmap-5.51-6.el6.x86_64                                     1/1 nr  Verifying  : 2:nmap-5.51-6.el6.x86_64                                     1/1 nnInstalled:n  nmap.x86_64 2:5.51-6.el6                                                      nnComplete!n"
    ]
}

3.11 service模块 服务管理

3.11.1 service模块常用参数说明

未分类

说明 :service 管理的服务必须存在在/etc/init.d/下有的服务脚本

3.11.2 service 模块参数实践

重启定时任务

[root@m01 ~]# ansible linuxidc -m service -a "name=crond state=restarted"
172.16.1.8 | SUCCESS => {
    "changed": true,
    "name": "crond",
    "state": "started"
}

3.12 ansible中的常用模块

未分类

3.13 其他模块补充

3.13.1 hostname 修改主机名模块

[root@m01 ~]# ansible 172.16.1.8 -m hostname -a "name=web01"
172.16.1.8 | SUCCESS => {
    "ansible_facts": {
        "ansible_domain": "etiantian.org",
        "ansible_fqdn": "www.etiantian.org",
       "ansible_hostname": "web01",
        "ansible_nodename": "web01"
    },
    "changed": false,
    "name": "web01"
}

3.13.2 selinux 管理模块

[root@m01 ~]# ansible 172.16.1.8 -m selinux -a "state=disabled"
172.16.1.8 | SUCCESS => {
    "changed": false,
    "configfile": "/etc/selinux/config",
    "msg": "",
    "policy": "targeted",
    "state": "disabled"
}

3.13.3 get_url 模块 == 【wget】

[root@m01 ~]# ansible 172.16.1.8 -m get_url -a "url=http://lan.linuxidc.com/RDPWrap-v1.6.1.zip dest=/tmp/"
172.16.1.8 | SUCCESS => {
    "changed": true,
    "checksum_dest": null,
    "checksum_src": "ad402705624d06a6ff4b5a6a98c55fc2453b3a70",
    "dest": "/tmp/RDPWrap-v1.6.1.zip",
    "gid": 0,
    "group": "root",
    "md5sum": "b04dde546293ade71287071d187ed92d",
    "mode": "0644",
    "msg": "OK (1567232 bytes)",
    "owner": "root",
    "size": 1567232,
    "src": "/tmp/tmp4X4Von",
    "state": "file",
    "status_code": 200,
    "uid": 0,
    "url": "http://lan.linuxidc.com/RDPWrap-v1.6.1.zip"
}

url= 下载文件的地址 dest 下载到哪里

timeout 超时时间

url_password 密码

url_username 用户名

Ansible服务部署与使用-Ansible介绍

第2章 Ansible软件介绍

  • python 语言是运维人员必须会的语言
  • ansible 是一个基于python 开发的自动化运维工具
  • 其功能实现基于ssh远程连接服务
  • ansible 可以实现批量系统配置,批量软件部署,批量文件拷贝,批量运行命令等功能

除了ansible之外,还有saltstack 等批量管理软件

2.1 自动化批量管理方式说明

2.1.1 ssh+key方式的说明

免密码登录验证是单向的,方向从私钥(钥匙) >==> 公钥(锁)

SSH免密码登录基于用户的,最好不要跨不同的用户

SSH连接慢解决;即修改sshd_config配罝文件参数信息

批量分发1000台初始都需要输入一次密码,并且第一次连接要确认(expect/sshpass)

expect批量管理服务器参考 http://www.linuxidc.com/Linux/2017-10/148048.htm

2.1.2 企业级生产场景批量管理-自动化管理方案

①.最简单/最常用/最强大的选择是ssh key+shell/pssh方案,一般中小型企业会用(50-100台以下规模企业)

a.利用ssh key执行命令,并将命令放在脚本里面

b.利用ssh key执行命令,将命令放在脚本里面,并加上相应循环语句或判断语句

②.sina cfengine/puppet较早的批量管理工具;现在基本上没有企业用

③.门户级别比较流行的,puppet批量管理工具(复杂/笨重)

④.saltstack批量管理工具;特点:简单,功能强大(配罝复杂>—赶集网/小米/一些CDN公司 批量管理路线:ssh key–>cfengine–>puppet–>saltstack/ansible

PS:使用ansible软件的前提是ssh key公钥分发充成

2.1.3 如何完成成集群规模架构一键自动化实现(步骤说明)

①.1台服务器先配置好(kickstart,cobbler无人值守安装)。高级实现云计算(按需分配,动态调整)(openstack,kvm)

②.linux基本优化,包括ssh服务(可以自动化实现)。

创建密钥信息(自动化免交互创建)

ssh-keygen -t dsa -P "" -f ~/.ssh/id_dsa >/dev/null 2>&1

进行批量分发密钥(sshpass,expect自动化实现)

⑤.ansible软件安装(可以自动化实现)

⑥.网络服务自动化安装(ansible实现)

(搭建yum仓库,定制rpm包)

2.2 ansible软件特点概述

  • 不需要单独安装客户端(no agents),基于系统自带的sshd服务,sshd就相当于ansible的客户端

  • 不需要服务端(no sever)

  • 需要依靠大量的模块实现批量管理

  • 配置文件 /etc/ansible/ansible.cfg (前期不用配置)

ansible软件相关参考链接信息

http://docs.ansible.com/ansible/intro_installation.html

http://www.ansible.com.cn/

http://docs.ansible.com/modules_by_category.html

http://www.ansible.cn/docs/

2.2.1 ansible软件中查看模块相关信息方法

[root@m01 ~]# ansible-doc -l

列出所有模块信息

[root@m01 ~]# ansible-doc -s cron 

参看指定模块的帮助

2.3 部署ansible软件

2.3.1 第一个里里程碑:部署ssh+key免密码登录方式

参见第一章内容

2.3.2 第二个里程碑:被管理端安装ansible相关管理软件

[root@m01 ~]# yum install libselinux-python -y

该软件是用来对selinux进行设置的,确保即使服务器selinux服务开启,依旧能够通过ansible 软件管理。

2.3.3 第三个里程碑:管理端安装ansible软件,配置hosts文件

[root@m01 ~]# yum install ansible -y

软件安装完成,进行修改ansible下的hosts文件,注意文件的路径

[root@m01 ~]# vim /etc/ansible/hosts
[linuxidc]
172.16.1.31
172.16.1.41
172.16.1.8

文件信息说明:

  • 中括号中的名字代表组名

  • 主机(hosts)部分可以使用域名、主机名、IP地址表示;一般此类配置中多使用IP地址;

  • 组名下的主机地址就是ansible可以管理的地址

至此ansible 服务就部署完成 ↑

2.4 查看ansible软件相关信息

2.4.1 ansible实践部署地址规划

未分类

2.4.2 ansible软件的版本信息

[root@m01 ~]# ansible --version
ansible 2.3.2.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.6.6 (r266:84292, Aug 18 2016, 15:13:37) [GCC 4.4.7 20120313 (Red Hat 4.4.7-17)]

2.4.3 软件目前主要会用到的文件

[root@m01 ~]# rpm -ql ansible
/etc/ansible/hosts            #定义anisble软件可以管理的主机信息
/usr/bin/ansible              #ansible执行命令
/usr/bin/ansible-playboot   # ansible执行剧本命令

2.4.4 /etc/ansible下的文件

[root@m01 ansible]# ll
total 28
-rw-r--r-- 1 root root 18066 Sep  6 06:38 ansible.cfg  #ansible配置文件
-rw-r--r-- 1 root root  1016 Sep  6 06:38 hosts       #定义ansible可以管理的主机信息
drwxr-xr-x 2 root root  4096 Sep  6 06:38 roles   #主要在自动化的时候部署多台主机时使用

2.5 ansible软件的使用/参数

2.5.1 ansible远程批量执行命令

语法:

ansible linuxidc -a "uptime"

ansible linuxidc -m command -a "uptime"

ansible 定义的组/单个ip/域名/all  -m command -a "uptime"

说明:

-m 指定使用的模块

-a 指定使用模块中相应的命令参数

命令参数只能是基本命令,并不支持管道操作

all 为hosts文件中的组全部管理

未分类
图2-1 ansible命令语法格式示意图

2.5.2 未分发公钥如何实现远程管理主机及指定ansible端口信息

配置hosts文件时配置上密码

vim /etc/ansible/hosts
[linuxidc]
172.16.1.31:52113  ansible_ssh_user=root ansible_ssh_pass=123456
172.16.1.41
172.16.1.8

IP:端口 用户 密码

[linuxidc]
www.linuxidc.com:52113 ansible_ssh_user=linuxidc

指定端口 用户名

测试修改端口后的结果 使用ping 模块

[root@m01 ~]# ansible linuxidc -m ping
www.linuxidc.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

2.6 ansible软件常用参数表

未分类

2.6.1 ansible命令执行结果色彩说明

绿色:表示没有发生任何改变

红色:执行命令操作出现异常

黄色:执行命令后,对受控主机产生影响,发生了配置改变