一、ansible简介
1、ansible是什么?
ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
项目地址:https://github.com/ansible/ansible
最新稳定版:v2.2.2.0-1
2、特性
基于python语言实现,由paramiko,PyYAML和Jinjia2三个关键模块构建
no agents:不需要在被管控主机上安装任何客户端;
no server:无服务器端,使用时直接运行命令即可;
modules in any languages:基于模块完成各种任务,可使用任意语言开发模块;
YAML,not code:使用yaml语言定制playbook(剧本);
ssh by default:基于SSH工作;
1) 基于密钥认证
2)在inventory文件中指定帐号和密码
主从模式:
master:ansible,是ssh client
slave:ssh server
支持Playbooks
strong multi-tier solution:强大的多层解决方案
3、优点
轻量级,部署简单,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;
批量任务执行可以写成脚本,而且不用分发到远程就可以执行;
使用python编写,维护更简单,ruby语法过于复杂;
命令或Playbooks执行结果幂等
支持sudo。
4、组织结构
ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。
如下图所示:
主要包括:
1)ansible core:ansible核心
2)connection plugins:连接插件
负责和被监控端实现通信;
3)host inventory:主机清单
是一个配置文件;在里面定义被管理的主机。
包括被管理的每个主机的IP,掩码,sshd监听的端口号、帐号和密码,可以将被管理的主机分组
4)各种核心模块、自定义模块;
5)Playbooks:YAML文件格式,也支持jinjia2模版语言来定义模版
剧本执行多个任务时,非必需可以让节点一次性运行多个任务
6)借助于插件完成记录日志邮件等功能;
二、ansible安装和配置
1、ansible安装
epel源中就提供了最新稳定的版本
[root@Node6 ~]# yum list|grep ansible ansible.noarch 2.2.1.0-1.el6 epel [root@Node6 ~]# yum install ansible [root@Node6 ~]# rpm -ql ansible|less /etc/ansible /etc/ansible/ansible.cfg /etc/ansible/hosts /etc/ansible/roles /usr/bin/ansible /usr/bin/ansible-console /usr/bin/ansible-doc /usr/bin/ansible-galaxy /usr/bin/ansible-playbook /usr/bin/ansible-pull /usr/bin/ansible-vault /usr/lib/python2.6/site-packages/
ansible不是服务,没有任何服务需要运行,使用时直接使用ansible命令运行即可,所谓 no server
2、ansible配置
ansible的配置文件:
[root@Node6 ~]# cd /etc/ansible/ [root@Node6 ansible]# ls ansible.cfg hosts roles
ansible.cfg:ansible的主配置文件
hosts:主机清单配置文件
roles:角色配置目录
先看/etc/ansible/hosts:
[root@Node6 ansible]# cat 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 # Ex 1: Ungrouped hosts, specify before any group headers. ### 可以使用主机名(要能解析)或ip地址列在这里 ## green.example.com ## blue.example.com ## 192.168.100.1 ## 192.168.100.10 # Ex 2: A collection of hosts belonging to the 'webservers' group ### 可以将多个主机定义组 ## [webservers] ## alpha.example.org ## beta.example.org ## 192.168.1.100 ## 192.168.1.110 # If you have multiple hosts following a pattern you can specify # them like this: ### 某种风格主机名的集合;下面这个例子表示主机名:www001.example.com --> www006.example.com 6个主机 ## www[001:006].example.com # Ex 3: A collection of database servers in the 'dbservers' group ## [dbservers] ## ## db01.intranet.mydomain.net ## db02.intranet.mydomain.net ## 10.25.1.56 ## 10.25.1.57 # Here's another example of host ranges, this time there are no # leading 0s: ## db-[99:101]-node.example.com ########################################################### # 需要已经做过密钥认证 node4 # 需要能解析该主机名 [xj] 192.168.10.1:22 192.168.10.2
四、ansible命令使用
1、获取帮助信息
通过 ansible-doc 命令获取ansible使用帮助信息
[root@Node6 ~]# ansible-doc --help Usage: ansible-doc [options] [module...] Options: -h, --help show this help message and exit -l, --list List available modules # 列出所有可用的模块 -M MODULE_PATH, --module-path=MODULE_PATH specify path(s) to module library (default=None) # 指定模块的路径 -s, --snippet Show playbook snippet for specified module(s) # 显示指定模块的帮助信息 -v, --verbose verbose mode (-vvv for more, -vvvv to enable connection debugging) --version show program's version number and exit [root@Node6 ~]# ansible-doc -s yum # 查看 yum 模块的帮助信息 - name: Manages packages with the `yum' package manager action: yum conf_file # The remote yum configuration file to use for the transaction. disable_gpg_check # Whether to disable the GPG checking of signatures of packages being installed. Has an effect only if state is `present' or `latest'. disablerepo # `Repoid' of repositories to disable for the install/update operation. These repos will not persist beyond the transaction. When specifying multiple repos, separate them with a ",". enablerepo # `Repoid' of repositories to enable for the install/update operation. These repos will not persist beyond the transaction. When specifying multiple repos, separate them with a ",". exclude # Package name(s) to exclude when state=present, or latest list # Various (non-idempotent) commands for usage with `/usr/bin/ansible' and `not' playbooks. See examples. name= # Package name, or package specifier with version, like `name-1.0'. When using state=latest, this can be '*' which means run: yum -y update. You can also pass a url or a local path to a rpm file (using state=present). To operate on several packages this can accept a comma separated list of packages or (as of 2.0) a list of packages. state # Whether to install (`present' or `installed', `latest'), or remove (`absent' or `removed') a package. update_cache # Force updating the cache. Has an effect only if state is `present' or `latest'. validate_certs # This only applies if using a https url as the source of the rpm. e.g. for localinstall. If set to `no', the SSL certificates will not be validated. This should only set to `no' used on personally controlled sites using self- signed certificates as it avoids verifying the source site. Prior to 2.1 the code worked as if this was set to `yes'.
2、ansbile 命令使用语法
ansible
host-patten:
对哪些主机生效;多个ip之间使用","分隔,all表示所有主机,也可以使用主机清单文件中定义的组名;在主机清单文件中指定的是ip这里就使用ip,指定是主机名就使用主机名
-f forks:启动的并发线程数
-m module_name:要使用的模块
-a args:模块特有的参数
例子:
[root@Node6 ~]# ansible node4 -a "hostname" node4 | SUCCESS | rc=0 >> Node4 [root@Node6 ~]# ansible 192.168.10.1,192.168.10.2 -a "hostname" 192.168.10.1 | SUCCESS | rc=0 >> Node1 192.168.10.2 | SUCCESS | rc=0 >> Node2 [root@Node6 ~]# ansible all -a 'hostname' 192.168.10.1 | SUCCESS | rc=0 >> Node1 192.168.10.2 | SUCCESS | rc=0 >> Node2 node4 | SUCCESS | rc=0 >> Node4 [root@Node6 ~]# ansible All -a 'hostname' [WARNING]: No hosts matched, nothing to do [root@Node6 ~]# ansible ALL -a 'hostname' [WARNING]: No hosts matched, nothing to do
五、ansible常用模块
1、command 命令模块
默认模块,用于在远程主机上执行命令
[root@Node6 ~]# ansible node4 -m command -a "hostname -I" node4 | SUCCESS | rc=0 >> 192.168.10.4 192.168.100.13 [root@Node6 ~]# ansible all -a "hostname -I" # command是默认模块,-m moudule_name 可以省略 192.168.10.2 | SUCCESS | rc=0 >> 192.168.10.2 192.168.100.4 192.168.10.1 | SUCCESS | rc=0 >> 192.168.10.1 192.168.100.9 node4 | SUCCESS | rc=0 >> 192.168.10.4 192.168.100.13 [root@Node6 ~]# ansible all,localhost -a "hostname -I" localhost | SUCCESS | rc=0 >> 192.168.10.8 192.168.100.17 192.168.10.2 | SUCCESS | rc=0 >> 192.168.10.2 192.168.100.4 node4 | SUCCESS | rc=0 >> 192.168.10.4 192.168.100.13 192.168.10.1 | SUCCESS | rc=0 >> 192.168.10.1 192.168.100.9
2、cron 计划任务模块
用于在远程主机设置计划任务
[root@Node6 ~]# ansible-doc -s cron - name: Manage cron.d and crontab entries. action: cron backup # If set, create a backup of the crontab before it is modified. The location of the backup is returned in the `backup_file' variable by this module. cron_file # If specified, uses this file instead of an individual user's crontab. If this is a relative path, it is interpreted with respect to /etc/cron.d. (If it is absolute, it will typically be /etc/crontab). To use the `cron_file' parameter you must specify the `user' as well. day # Day of the month the job should run ( 1-31, *, */2, etc ) ### 指定天 disabled # If the job should be disabled (commented out) in the crontab. Only has effect if state=present env # If set, manages a crontab's environment variable. New variables are added on top of crontab. "name" and "value" parameters are the name and the value of environment variable. hour # Hour when the job should run ( 0-23, *, */2, etc ) ### 指定小时 insertafter # Used with `state=present' and `env'. If specified, the environment variable will be inserted after the declaration of specified environment variable. insertbefore # Used with `state=present' and `env'. If specified, the environment variable will be inserted before the declaration of specified environment variable. job # The command to execute or, if env is set, the value of environment variable. Required if state=present. ### 指定要执行任务 minute # Minute when the job should run ( 0-59, *, */2, etc ) ### 指定分钟 month # Month of the year the job should run ( 1-12, *, */2, etc ) ### 指定月份 name # Description of a crontab entry or, if env is set, the name of environment variable. Required if state=absent. Note that if name is not set and state=present, then a new crontab entry will always be created, regardless of existing ones. reboot # If the job should be run at reboot. This option is deprecated. Users should use special_time. special_time # Special time specification nickname. state # Whether to ensure the job or environment variable is present or absent. ### 添加或者移除任务 user # The specific user whose crontab should be modified. weekday # Day of the week that the job should run ( 0-6 for Sunday- Saturday, *, etc ) ### 指定星期几 (END)
例子:
[root@Node6 ~]# ansible xj -f 2 -m cron -a 'minute=*/3 job="echo hello &> /root/cron.txt" name="test cron job of xj"' 192.168.10.2 | SUCCESS => { "changed": true, "envs": [], "jobs": [ "test cron job of xj" ] } 192.168.10.1 | SUCCESS => { "changed": true, "envs": [], "jobs": [ "test cron job of xj" ] } [root@Node1 ~]# crontab -l # 调用crond服务 #Ansible: test cron job of xj */3 * * * * echo hello &> /root/cron.txt [root@Node1 ~]# cat cron.txt hello [root@Node6 ~]# ansible xj -f 2 -m cron -a 'name="test cron job of xj" state="absent"' # 移除cron 任务 192.168.10.1 | SUCCESS => { "changed": true, "envs": [], "jobs": [ "None" ] } 192.168.10.2 | SUCCESS => { "changed": true, "envs": [], "jobs": [ "None" ] }
3、user,group 用户,组管理
[root@Node6 ~]# ansible xj -m user -a "name=user4 createhome=no system=yes shell=/sbin/nologin" 192.168.10.2 | SUCCESS => { "changed": true, "comment": "", "createhome": false, "group": 495, "home": "/home/user4", "name": "user4", "shell": "/sbin/nologin", "state": "present", "system": true, "uid": 496 } 192.168.10.1 | SUCCESS => { "changed": true, "comment": "", "createhome": false, "group": 496, "home": "/home/user4", "name": "user4", "shell": "/sbin/nologin", "state": "present", "system": true, "uid": 496 }
4、copy 复制或新建文件
src= 定义本地源文件路径可以是相对路径和绝对路径
dest= 定义远程目标文件路径,只能是绝对路径
content= 取代src选项,用此处指定的信息生成为目标文件内容
[root@Node6 ~]# ansible xj -m copy -a "src=/etc/fstab dest=/tmp/fstab.txt mode=640" 192.168.10.2 | SUCCESS => { "changed": true, "checksum": "b43214f5dd10c80fa48a7c99875c21ff263eaa94", "dest": "/tmp/fstab.txt", "gid": 0, "group": "root", "md5sum": "f317c0c8d83588c44c02c84041dfc287", "mode": "0640", "owner": "root", "size": 805, "src": "/root/.ansible/tmp/ansible-tmp-1491217643.44-272268881932863/source", "state": "file", "uid": 0 } 192.168.10.1 | SUCCESS => { "changed": true, "checksum": "b43214f5dd10c80fa48a7c99875c21ff263eaa94", "dest": "/tmp/fstab.txt", "gid": 0, "group": "root", "md5sum": "f317c0c8d83588c44c02c84041dfc287", "mode": "0640", "owner": "root", "size": 805, "src": "/root/.ansible/tmp/ansible-tmp-1491217643.49-272925226793088/source", "state": "file", "uid": 0 } [root@Node6 ~]# ansible xj -m copy -a 'content="1\n2" dest=/tmp/src/1.txt' 192.168.10.2 | FAILED! => { "changed": false, "checksum": "860bfb3bbfa6c2aa4a3a0c99b5ef584e98954612", "failed": true, "msg": "Destination directory /tmp/src does not exist" } 192.168.10.1 | SUCCESS => { "changed": true, "checksum": "860bfb3bbfa6c2aa4a3a0c99b5ef584e98954612", "dest": "/tmp/src/1.txt", "gid": 0, "group": "root", "md5sum": "a1fe7d8e64a2b3f20e90b79387bff527", "mode": "0644", "owner": "root", "size": 3, "src": "/root/.ansible/tmp/ansible-tmp-1491218012.26-77327477558155/source", "state": "file", "uid": 0 } [root@Node1 src]# cat 1.txt 1 2[root@Node1 src]# ### 需要自己添加换行符
5、file 设置文件属性
[root@Node6 ~]# ansible xj -m file -a "owner=sshd group=sshd mode=755 path=/tmp/src/1.txt" ### 修改文件权限,属有者,属有组 192.168.10.2 | FAILED! => { "changed": false, "failed": true, "msg": "file (/tmp/src/1.txt) is absent, cannot continue", "path": "/tmp/src/1.txt", "state": "absent" } 192.168.10.1 | SUCCESS => { "changed": true, "gid": 74, "group": "sshd", "mode": "0755", "owner": "sshd", "path": "/tmp/src/1.txt", "size": 3, "state": "file", "uid": 74 } [root@Node6 ~]# ansible xj -m file -a "src=/etc/fstab path=/tmp/src/111 state=link" ### 创建软链接文件 192.168.10.2 | FAILED! => { "changed": false, "failed": true, "msg": "Error while linking: [Errno 2] No such file or directory", "path": "/tmp/src/111", "state": "absent" } 192.168.10.1 | SUCCESS => { "changed": true, "dest": "/tmp/src/111", "gid": 0, "group": "root", "mode": "0777", "owner": "root", "size": 10, "src": "/etc/fstab", "state": "link", "uid": 0 }
6、ping 测试指定主机是否能连接
[root@Node6 ~]# ansible xj -m ping 192.168.10.1 | SUCCESS => { "changed": false, "ping": "pong" } 192.168.10.2 | SUCCESS => { "changed": false, "ping": "pong" }
7、service 管理服务
enabled= 是否开机自动启动,取值为 true 或者 false
name= 服务名称
state= 状态,取值有started,stopped,restarted
[root@Node6 ~]# ansible 192.168.10.1 -m service -a "name=httpd enabled=yes state=started" 192.168.10.1 | SUCCESS => { "changed": true, "enabled": true, "name": "httpd", "state": "started" }
8、shell 在远程主机上运行命令,尤其使用管道,变量等复杂命令
[root@Node6 ~]# ansible xj -a "tail /etc/passwd|tail -1 /etc/passwd" 192.168.10.2 | FAILED | rc=1 >> tail: option used in invalid context -- 1 192.168.10.1 | FAILED | rc=1 >> tail: option used in invalid context -- 1 [root@Node6 ~]# ansible xj -m shell -a "tail /etc/passwd|tail -1 /etc/passwd" 192.168.10.1 | SUCCESS | rc=0 >> user4:x:496:496::/home/user4:/sbin/nologin 192.168.10.2 | SUCCESS | rc=0 >> user3:x:501:501::/home/user3:/bin/bash [root@Node6 ~]# ansible xj -a "echo '123'|passwd --stdin user3" 192.168.10.2 | SUCCESS | rc=0 >> 123|passwd --stdin user3 192.168.10.1 | SUCCESS | rc=0 >> 123|passwd --stdin user3 [root@Node6 ~]# ansible xj -m shell -a "echo '123'|passwd --stdin user3" 192.168.10.1 | SUCCESS | rc=0 >> Changing password for user user3. passwd: all authentication tokens updated successfully. 192.168.10.2 | SUCCESS | rc=0 >> Changing password for user user3. passwd: all authentication tokens updated successfully.
9、yum 安装程序包
name= 指明要安装的程序包,可以带上版本号
state= present,latest表示安装,absent表示卸载
[root@Node6 ~]# ansible 192.168.10.2 -m yum -a "name=httpd" 192.168.10.2 | SUCCESS => { "changed": true, "msg": "", "rc": 0, "results": [ "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * epel: mirrors.aliyun.com\n * extras: mirrors.aliyun.com\n * updates: mirrors.aliyun.com\nSetting up Install Process\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.2.15-56.el6.centos.3 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n httpd x86_64 2.2.15-56.el6.centos.3 updates 834 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package(s)\n\nTotal download size: 834 k\nInstalled size: 3.0 M\nDownloading Packages:\nRunning rpm_check_debug\nRunning Transaction Test\nTransaction Test Succeeded\nRunning Transaction\n\r Installing : httpd-2.2.15-56.el6.centos.3.x86_64 1/1 \n\r Verifying : httpd-2.2.15-56.el6.centos.3.x86_64 1/1 \n\nInstalled:\n httpd.x86_64 0:2.2.15-56.el6.centos.3 \n\nComplete!\n" ] }
10、script 将本地脚本在远程节点上运行
[root@Node6 ~]# ls -l "/tmp/1.sh" -rw-r--r-- 1 root root 44 Apr 3 19:49 /tmp/1.sh ### 可以没有执行权限 [root@Node6 ~]# cat "/tmp/1.sh" echo 111 echo 222 touch /tmp/src/script.txt [root@Node6 ~]# ansible 192.168.10.1 -m script -a "/tmp/1.sh" 192.168.10.1 | SUCCESS => { "changed": true, "rc": 0, "stderr": "", "stdout": "111\r\n222\r\n", "stdout_lines": [ "111", "222" ] }
11、setup 收集远程主机的facts
每个被管理节点在接收并运行管理命令之前,会将自己主机相关信息,如果操作系统版本,IP地址等报告给ansible,得到的变量名和其值可以直接引用。
[root@Node6 ~]# ansible 192.168.10.1 -m setup 192.168.10.1 | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ ### facts变量:值 "192.168.10.1", "192.168.100.9" ], "ansible_all_ipv6_addresses": [ "fe80::20c:29ff:fe99:d24e", "fe80::20c:29ff:fe99:d258" ], "ansible_architecture": "x86_64", "ansible_bios_date": "07/02/2015", "ansible_bios_version": "6.00", "ansible_cmdline": { "KEYBOARDTYPE": "pc", "KEYTABLE": "us", ... [root@Node6 ~]# ansible 192.168.10.1 -m setup|grep -A 5 ansible_processor ### 查看cpu信息 "ansible_processor": [ "GenuineIntel", "Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz" ], "ansible_processor_cores": 1, "ansible_processor_count": 1, "ansible_processor_threads_per_core": 1, "ansible_processor_vcpus": 1, "ansible_product_name": "VMware Virtual Platform", "ansible_product_serial": "VMware-56 4d 9e 9d 56 67 65 5c-2f b3 ca 41 e1 99 d2 4e", "ansible_product_uuid": "564D9E9D-5667-655C-2FB3-CA41E199D24E", "ansible_product_version": "None", "ansible_python": {
注意:
使用ansible时,不一定一定要使用相应的模块,可以直接使用command、shell、script 模块更方便