Ad-Hoc简而言之是“临时命令”,英文中作为形容词有“特别的”,“临时”的含义。
Ansible提供两种完成任务方式:一种是Ad-Hoc命令集,即命令ansible,另外一种就是Ansible-playbook了,即命令Ansible-playbook。
Ad-Hoc适合解决一些简单或者平时工作中临时遇到的任务
Ansible-playbook适合解决复杂或需固化下来的任务
深入Ansible是从接触Ansible-playbook开始的,灵活运用Ansible-playbook才能更好的体会到Ansible的强大所在。
Ad-Hoc命令集由/usr/bin/ansible实现,其命令用法如下:
ansible [options]
可用选项如下:
-v,--verbose:输出更详细的执行过程信息,-vvv可得到执行过程所有信息。
-i,PATH,--inventory(清单)=PATH:指定inventory(清单)信息,默认/etc/ansible/hosts
-f NUM,--forks=NUM:并发线程数,默认5个线程。
--private-key=PRIVATE_KEY_FILE:指定密钥文件。
-m NMAE,--module-name=NAME:指定执行使用的模块。
-M DIRECTORY,--module-path=DIRECTORY:指定模块存放路径,默认/usr/share/ansible,也可以通过ANSIBLE_LIBRARY设定默认路径。
-a ‘ARGUMENTS’,--args=‘ARGUMENTS’:模块参数。
-k,--ask-pass SSH:认证密码
-K,--ask-sudo-pass sudo:用户的密码(--sudo时使用)。
-o,--one-line:标准输出至一行。
-s,--sudo:相当于Linux系统下的sudo命令。
-t DIRECTORY,--tree=DIRECTORY:输出信息至DIRECTORY目录下,结果文件以远程主机命名。
-T SECONDS,--timeout=SECONDS:指定连接远程主机的最大超时,单位是秒。
-B NUM,--background=NUM:后台执行命令,超NUM秒后中止正在执行的任务。
-P NUM,--poll=NUM:定期返回后台任务进度。
-u USERNAME,--user=USERNAME:指定远程主机以USERNAME运行命令。
-U SUDO_USERNAME,--sudo-user=SUDO_USERNAME:使用sudo,相当于LInux下的sudo命令。
-c CONNECTION,--connection=CONNECTION:指定连接方式,可用选项paramiko(SSH)、ssh、local,local方式常用于crontab和kickstarts。
-l SUBSET,--limit=SUBSET:指定运行主机。
-l ~REGEX,--limit=~REGEX:指定运行主机(正则)。
--list-hosts:列出符合条件的主机列表,不执行任何命令。
实例:
(1.)检查proxy组所有主机是否存活。
执行命令:
ansible proxy -f 5 -m ping
返回结果:
上述执行结果:
其中192.168.1.18是指命令执行的主机,Success表示命令执行成功,">>{}"表示详细返回结果如下。
"changed":false 表示没有对主机做变更"ping":"pong"表示执行了ping命令返回结果为pong。
(2.)返回proxy组所有主机的hostname,并打印最详细的执行过程到标准输出。
执行命令:
ansible proxy -s -m command -a 'hostname' -vvv
上述执行结果:
ESTABLISH CONNECTION FOR USER:root :远程主机192.168.1.18监听用户root的22号端口
REMOTE_MODULE command hostname :远程执行命令hostname
"/bin/sh -c 'mkdir -p $HOME/.ansible/tmp/ansible-tmp-1537154337.4-134606313491356 && echo $HOME/.ansible/tmp/ansible-tmp-1537154337.4-134606313491356'"] :生成临时目录用于存放Ansible远程执行脚本。
PUT /tmp/tmp4f_9zu TO /root/.ansible/tmp/ansible-tmp-1537154337.4-134606313491356/command :改名临时脚本并存放至临时目录。
EXEC ['ssh', '-C', '-tt', '-q', '-o', 'ControlMaster=auto', '-o', 'ControlPersist=60s', '-o', 'ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r', '-o', 'StrictHostKeyChecking=no', '-o', 'Port=22', '-o', 'IdentityFile="/root/.ssh/id_rsa_storm1"', '-o', 'KbdInteractiveAuthentication=no', '-o', 'PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey', '-o', 'PasswordAuthentication=no', '-o', 'ConnectTimeout=10', '192.168.1.18', u"/bin/sh -c 'LANG=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 /usr/bin/python /root/.ansible/tmp/ansible-tmp-1537154337.4-134606313491356/command; rm -rf /root/.ansible/tmp/ansible-tmp-1537154337.4-134606313491356/ >/dev/null 2>&1'"] :使用sudo方式并以Python脚本方式执行命令。
192.168.1.18 | success | rc=0 >> :返回结果成功。
(3.)对192.168.1.18服务器以root执行sleep20,设置最大连接超时时间时长为2s,且设置为后台运行模式,执行过程没2s输出一次进度,如5s还未执行完则终止该任务。
执行命令:
time ansible 192.168.1.18 -B 5 -P 2 -T 2 -m command -a 'sleep 20' -u root
执行结果如下:
第一行:background launch...表示使用-B使该命令后台运行。
下面每隔2s输出一次执行进度
下面每隔2s输出一次执行进度
real 0m55.664s 程序执行总时长
user 0m0.269s 系统用户层执行时长
sys 0m0.118s 系统内核层执行时长
接下来通过df、free命令查看系统设置,通过Ad-Hoc实现。
(1.)批量查看apps组所有主机的磁盘容量(使用command模块)。
执行命令:
ansible apps -a "df -lh"
返回结果如下:
success表示执行成功
(2.)批量查看远程主机内存使用情况(shell模块)。
ansible apps -m shell -a "free -m "
返回结果如下:
ansible和Ansible-playbook默认会fork 5个线程并发执行命令,但在实际工作中,如果主机数量众多,Ansible并发5个线程是远不能满足企业所需的。
接下来我们定义[apps]组,多次执行同样的Ad-Hoc命令来查看其返回的结果。
(1.)定义[apps]组,编辑/etc/ansible/hosts的配置
[apps]
192.168.1.18
192.168.1.27
192.168.1.29
192.168.1.30
(2.)多次执行Ansible命令,执行命令如下:
ansible apps -m ping -f 3
对比返回结果:
上述执行的结果分析如下:
同样的命令多次执行,但每次的输出结果都不一定一样。
输出结果是不是按照/etc/ansible/hosts中[apps]定义的主机顺序输出。
如果主机数量很多,我们需要调大线程数,该如何操作呢?这里ansible为我们提供了便捷的选项 ,-f指定线程数。
Ansible使用multiprocessing管理多线程。
接下来为大家介绍Ad-Hoc的模块使用。另外,Ansible也提供了类似于man功能的help说明工具ansible-doc。
正式学习Ansible模块使用前,有必要先了解ansible-doc用法
命令用法:
ansible-doc [options] [module...]
可用选项如下:
--version:显示工具版本号
-h,--help:显示该help说明。
-M MODULE_PATH,--module-path=MODULE_PATH:指定Ansible模块的默认加载目录。
-l,--list:列出所有可用模块。
-s,--snippet:只显示playbook说明的代码段。
-v:等同于--version,显示工具版本号。
接下来看些简单的实例:
(1.)显示所有可用的模块
执行命令:
ansible-doc -l
执行结果:
(2.)以yum模块为例,我们希望获取yum模块的HELP说明。
执行命令:
ansible-doc yum
执行结果:
其他模块HELP说明以此类推。下面通过Ansible内置模块来完成一些具体工作。
1.安装httpd服务并查看服务的版本号
(1.)安装httpd服务
执行命令:
ansible apps -m yum -a 'name=httpd state=present'
返回结果如下:
其中:
changed:主机是否有变更,True为有;false为没有(第一次运行或事先没有安装,返回值一般是True,否则为false)。
msg:安装过程信息
rc:0,resultcode:结果返回码,非0返回码往往是红色并且错误的返回,非常明显。
(2.).查看服务版本号
执行命令:
ansible apps -m command -a '/usr/sbin/httpd -V'
返回结果如下:
部分执行结果解释:
192.168.1.18:表示命令执行的对象
success:表示命令执行的返回状态为成功状态。
rc=0:表示命令执行的状态码为0
>>:该符号后返回的所有内容为执行/usr/sbin/httpd -V命令返回的信息。
2.为所有服务器安装ntp服务,并设置为开机自启动。
(1.)安装ntp服务
执行命令:
ansible apps -s -m yum -a "name=ntp state=present"
返回结果如下:
(2.)启动ntp服务,并设置为开机自启动。
执行命令:
ansible apps -m service -a "name=ntp state=started enabled=yes"
执行结果如下:
返回的结果不再一一介绍了,相信已经懂了。
Ad-Hoc组定义:Ad-Hoc的组功能定义在Inventory(清单)文件中,默认路径是/etc/ansible/hosts,书写格式遵循INI风格,中括号中的字符为组名。可以将同一个主机名称之后使用冒号加端口号来标明。
本次架构规划了前端Proxy、web Service和后面DB一套完整应用,下面便是架构拓扑图:
如上图所示是简化后的互联网web服务架构, 用户请求通过proxy转发至后端WebServers响应,通过NoSQL服务缓冲后,最终将请求传送到DB这样的一个过程。
准备部署环境如下:
定义 Inventorycat(清单) /etc/ansible/hosts:
[proxy]
192.168.1.18
[app]
192.168.1.27
192.168.1.29
[nosql]
192.168.1.30
[db]
192.168.1.19
应用分布如下:
[proxy]组:Nginx
[app]组:Nginx+PHP+Django
[nosql]组:Redis
[db]组:Mariadb
接下来我们按Proxy、WebServers 依次顺序部署应用。
(1.)Ad-Hoc配置管理Proxy(即Nginx)
小提示:
首先配置好对方nginx的yum源让主机能够安装上nginx服务。
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
利用ansible安装Nginx执行命令:
ansible proxy -m yum -a "name=nginx state=present"
安装结果:
部分执行结果解释:
changed:true,//表示本次命令对执行的目标有变更,True为第一次安装,如再执行一次则为false,表示执行的目标没有变更,这里的false和true不代表该命令执行成功或失败,只是表示执行目标是否被变更。
rc:0,//resultcode的简写,表示命令执行结果返回状态,非0均为异常,命令执行失败
results:[ //执行结果信息返回
安装完Nginx让我们来检查一下Nginx是否安装成功,可以执行如下命令:
ansible proxy -m command -a "nginx -v"
如果安装成功则显示如下结果:
如上所示是Nginx就安装好了,其实通过Ansible的YUM模块来安装Nginx有很多种方法,通过网络YUM源安装是其中的一种,
那么还可以从本地YUM源安装,以及通过去仓库拉去相关服务的源也是可以的。
(2.)Ad-Hoc配置管理Web Servers
安装完了Nginx前端代理服务,同时Web Servers需要部署Nginx 、PHP和Django,其中Nginx、PHP依然通过YUM模块实现,Django推荐使用PIP或easy_install方式。
小提示:因为断电原因后面的ip有所变化,不过一样好理解!!!
同样和之前安装的Nginx服务一样要把Nginx、PHP的YUM源配置上
Nginx、PHP安装命令如下:
ansible app -m yum -a "name=nginx state=present"
ansible app -m yum -a "name=php state=present"
显示Nginx安装执行结果:
显示PHP安装执行结果:
Django命令安装如下:
(1.)安装MySQL-python和python-setuptools依赖包。
ansible app -m yum -a "name=MySQL-python state=present"
ansible app -m yum -a "name=php state=present"
安装MySQL-python显示结果如下:
安装python-setuptools显示如下:
(2.)安装Django:
ansible app -m pip -a "name=django state=present"
安装显示结果:
检查Django安装是否正常 ,执行命令如下:
ansible app -m command -a "python -c 'import django; print django.get_version()'"
显示结果如下:
如果上述安装报错请检查python版本,其中Django依赖Python2.7+版本。
截止目前,proxy & webservers部署完毕了。
接下来我们使用类似的方法配置NoSQL和DB服务。
Redis安装命令如下:
ansible nosql -m yum -a "name=redis state=present"
显示结果如下:
Redis安装完,进行检查看安装是否正常,执行命令如下:
ansible nosql -m command -a "redis-cli --version"
显示版本结果如下:
安装Mariadb,具体操作步骤如下:
(1.)添加yum源,vim编辑/etc/yum.repos.d/mariadb.repo添加如下内容:
[mariadb]
name = Mariadb
baseurl=http://yum.mariadb.org/10.1/centos/7.2/x86_64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
(2.)安装MariaDB-server,执行如下命令:
ansible db -m yum -a "name=MariaDB-server state=present"
显示结果如下:
(3.)安装MariaDB-client,执行命令如下:
ansible db -m yum -a "name=MariaDB-client state=present"
显示结果如下:
截止目前,所有的应用成功部署完毕。
前面我们通过搭建了一套主流web应用框架熟悉了Ansible的组管理,接下来为大家介绍如何针对特定服务器做为变更。
Ansible有多种方式实现针对特定主机做变更。
(1.)--limit:通过 --limit参数限定主机做变更。
在APP组启动192.168.1.19的NTP服务,执行下列命令查看启动后的NTP服务的状态:
ansible app -m command -a "systemctl status ntpd.service" --limit "192.168.1.19"
显示结果如下:
(2.)指定IP:通过指定具体IP限定主机做变更。
启动192.168.1.19的NTP服务,执行下列命令查看启动后的NTP服务的状态:
ansible 192.168.1.19 -m command -a "systemctl status ntpd.service"
显示结果如下:
(3.)用 “:”做分隔符,指定多台机器做变更。
启动192.168.1.19和192.168.1.14的NTP服务,执行下列命令查看启动后的NTP服务的状态:
ansible "192.168.1.14:192.168.1.19" -m command -a "systemctl status ntpd.service"
显示结果如下:
(4.)通过“*”泛匹配,更灵活地针对多台主机做变更。
启动192.168.1.*所有主机的NTP服务,执行下列命令查看启动后的NTP服务的状态:
ansible 192.168.1.* -m command -a "systemctl status ntpd.service"
显示结果如下:
到目前为止Ad-Hoc组管理 及特定主机变更我们已经掌握,这对灵活管理海量服务器有很大帮助。
关于组及指定主机管理介绍到此结束。接下来为大家介绍的是Ad-Hoc基于用户管理。
ansible系统用户模块有如下两个:
Linux系统用户管理:user
windows系统用户管理:win_user
Linux用户管理:
User模块功能诸多,模块属性如下:
append yes:增量添加group no:全量变更group,只设置groups指定的group组。
comment: 可选设置用户账户的描述(又名GECOS)
createhome:默认选项yes,当创建用户期时或家目录不存在时 为用户创建HOME目录。
expires(1.9版本增加):1.9版本的新增功能,用户过期时间,不支持的平台该参数将被忽略,现在支持Linux和FreeBSD
force:强制,当和state=absent结合使用时,效果等同于userdel --force
generate_ssh_key: 是否生成SSH key,不会覆盖已有的SSH key
group :(可选)设置用户属组
groups:设置用户附加群组,使用逗号分隔多个群组,如果参数为空(即‘groups=’),则删除用户所有附加组(属组不受影响)
home:(可选)设置用户家目录
login_class:(可选)设置FreeBSD、OPenBSD、NetBSD系统的用户登录class
move_home:如设置为yes,结合使用home=,临时迁移用户家目录到特定目录。
name:用户名
non_unique:(可选)和-u结合使用,允许改变用户ID为非唯一值。
password:(可选)设置用户密码为该项指定的密码(加密后的密码)
remove:结合state=absent使用相当于userdel --remove
seuser(2.1版本增加):(可选)设置seuser类型启用SELinux
shell :(可选)设置用户shell
skeleton:(可选)设置用户的skel目录,需和createhome参数结合使用。
ssh_key_bits:(可选)指定生成的SSH key加密位数。
ssh_key_comment:(默认值:ansible-generated on $HOSTNAME)(可选)定义SSH key注释
ssh_key_file:(默认值.ssh/id_rsa)(可选)指定SSH key 文件名,如果该文件名是相对路径,则默认路径为用户家目录。
ssh_key_passphrase:设置SSH key密码,如果没有提供密码,则默认没有加密。
ssh_key_type:(可选)设置SSH Key 类型,具体可用的SSH key类型取决于目标主机
state:present Present:新建(使存在)用户,absent:删除用户
system:当创建新账户时,该选项为yes,为用户设置系统账户,该设置对已经存在的用户无效。
uid:(可选)设置用户UID
update_password(1.3版本增加):always:只有当密码不相同时才会更新密码,on_create:只为新用户设置密码。
接下来为大家介绍用户相关的五大场景应用,以供参考。
场景1:新增用户
需求描述:新增用户dba,使用BASH Shell,附加组为admins,dbagroup,家目录为/home/dba/。
该场景中我们可以掌握如下技能点:
(1.)groups设定:groups=用户组1,用户组2......
(2.)增量添加属组:append=yes
(3.)表名属组状态为新建:state=present
执行如下命令:
ansible db -m user -a "name=dba shell=/bin/bash groups=admins,dbagroup append=yes home=/home/dba/ state=present"
返回结果如下:
场景2:修改用户属组
需求描述:修改DBA附件组为dbagroups(即删除admins组权限)。
该场景中我们可以掌握如下技能点。
全量变更属组信息:append=no
执行命令如下:
ansible db -m user -a "name=dba groups=dbagroup append=no"
返回结果如下:
提示:删除admins组权限的命令中append值为no。另外,细心的朋友会发现,新增用户时,ansible默认为用户添加用户组(primary group)。
场景3:修改用户属性
需求描述:设置dba用户的过期时间为2016/6/1 18:00:00(UNIXTIME:1464775200)。
该场景中我们可以掌握如下技能点。
(1.)设置用户登录过期时间:expire=1464775200
(2.)UNIX时间转换:2016/6/1 18:00:00需转换为UNIXTIME格式(不做介绍,请自行百度)
执行如下命令:
ansible db -m user -a "name=dba expires=1464775200"
这样,我们已经完成了DBA用户的过期时间设置。
场景4:删除用户
需求描述:删除用户DBA,并删除其家目录和邮件列表。
该场景中我们可以掌握如下技能点:
(1.)表明属组状态为删除:state=absent
(2.)设定remove=yes:remove=yes
执行命令如下:
ansible db -m user -a "name=dba state=absent remove=yes"
返回显示结果如下:
结果检查:到对应主机使用root用户查看/etc/passwd是否存在dba用户。或执行命令id dba确认是否有返回结果。
场景5:变更用户密码
需求描述:设置系统用户tom的密码为redhat123
执行命令如下:
ansible db -m user -a "name=tom shell=/bin/bash password=to46pW3GOukvA update_password=always"
显示结果如下:
注意:password后面的密码并非真正的密码。官网上介绍了两种密码加密方式。
(1.)查找安装包名称
执行命令如下:
yum whatprovides */mkpasswd
执行结果如下:
(2.)安装软件包
执行命令如下:
yum -y install expect
显示结果如下:
(3.)使用mkpasswd生成密码。
执行如下命令:
mkpasswd --method=SHA-512
方式2:使用Python的passlib、getpass库生成密码。
(1.)安装passlib(Python版本建议2.7以上)
执行如下命令:
pip install passlib
执行显示结果:
(2.)生成密码
python3.x系列版本请使用如下命令(sha512加密算法)。
python -c "from passlib.hash import sha512_crypt; import getpass; print (sha512_crypt.encrypt(getpass.getpass()))"
python3.x系列版本请使用如下命令(普通加密算法)。
python -c 'import crypt; print (crypt.crypt("redhat123","dba"))'
python2.x系列版本请使用如下命令(sha512加密算法)。
python -c "from passlib.hash import sha512_crypt; import getpass ; print sha512_crypt.encrypt(getpass.getpass())"
python2.x系列版本请使用如下命令(普通加密算法)。
python -c 'import crypt; print (crypt.crypt("redhat123","dba"))'
以MySQL用户管理为例。
新增MySQL用户stanley,设置登录密码为magedu@bj,对zabbix.*表有ALL权限。
执行如下命令:
ansible db -m mysql_user -a 'login_host=localhost login_password=magedu login_user=root name=stanley password=magedu@bj priv=zabbix.*:ALL state=present'
登录验证步骤如下:
(1.)在MySQL服务器上进行测试登录
MySQL -u stanley -p maedu@bj
(2.)执行如下命令,验证权限是否正确:
show grants for 'stanley'@'localhost';