运维的痛点:
海量的设备越来越多,每台设备单独管理需要投入更多人力;
传统运维效率低,大多工作人为完成;
传统运维工作繁琐,人工操作容易出错;
传统运维每日重复做相同的事情;
传统运维没有标准化流程,执行的过程不可控,执行的结果不统一;
传统运维的脚本繁多,不能方便管理。
自动化运维工具就是要解决上面所有问题。
市场上主流的三大开源自动化配置管理工具有:Puppet、Ansible、SaltStack。
Puppet:
使用一种描述性的语言给客户端声明了一些状态配置;puppet基于传统的C/S架构,架构中通常有一台服务器,负责对下游客户端的控制。每个被控制的设备都要安装puppet客户端。puppet使用ruby语言编写,而ruby语言是解析型语言,所谓解析型语言,就是ruby语言的每次执行,都需要借助翻译器将ruby语言翻译成可以被CPU直接执行的机器码。
SaltStack:
SaltStack是基于Python开发的一套C/S架构配置管理工具(功能不仅仅是配置管理,如使用salt-cloud配置AWS EC2实例),它的底层使用ZeroMQ消息队列pub/sub方式通信,使用SSL证书签发的方式进行认证管理。采用号称世界上最快的消息队列ZeroMQ使得SaltStack能快速在成千上万台机器上进行各种操作,而且采用RSA Key方式确认身份,传输采用AES加密,这使得它的安全性得到了保障。
Ansible
ansible是一个基于python开发的轻量级自动化运维管理工具,可以用来批量执行命令,安装程序,支持playbook编排。它通过ssh协议来连接主机,去中心化,相对比puppet和saltstack无需安装客户即可实现文件传输、命令执行、应用部署、配置管理、任务编排等,显得更为简单与轻量。ansible只是提供一种框架,其基于模块工作的,本身没有批量部署。
技术特性对比
优缺点对比
?1)、响应速度的考量
SaltStack的master和minion主机是通过ZeroMQ传输数据,而Ansible是通过标准SSH进行数据传输,SaltStack的响应速度要比Ansible快很多。标准SSH连接的时候比较耗费时间,ZeroMQ传输的速度会快很多,所以单单从响应速度方面考虑SaltStack会是更好的选择。但是在一般的运维场景下Ansible的响应速度也可以满足需求。
2)、安全的考量
Ansible和SaltStack都需要和远程主机进行连接,它们的最大的安全问题就是MITM攻击,通过伪装成Master主机和远程主机进行通信,从而进行攻击。 SaltStack使用ZeroMQ进行数据传输,ZeroMQ本身数据传输不支持加密,SaltStack可以通过使用AES数据加密方法来对数据进行加密传输,但是SaltStack的minion主机以守护进程的方式运行在远端暴露了很多容易被攻击的点。
3)、运维成本的考量
SaltStack需要在Master和Minion主机启动守护进程,自身需要检测守护进程的运行状态,增加运维成本。Ansible和远端主机之间的通信是通过标准SSH进行,远程主机上只需要运行SSH进程就可以进行运维操作,SSH是机房主机中一般都安装和启动的进程,所以在Ansible进行运维的时候只需要关注Ansible主机的运行状态。Ansible对机房运维不会增加过多的运维成本。从工具本身的运维角度来说,Ansible要比SaltStack简单很多。
? 在SaltsStack架构中服务端叫作Master,客户端叫作Minion,都是以守护进程的模式运行,一直监听配置文件中定义的ret_port(saltstack客户端与服务端通信的端口,负责接收客户端发送过来的结果,默认4506端口)和publish_port(saltstack的消息发布系统,默认4505端口)的端口。当Minion运行时会自动连接到配置文件中定义的Master地址ret_port端口进行连接认证。
Master:控制中心,salt命令运行和资源状态管理
Minion : 需要管理的客户端机器,会主动去连接Mater端, 并从Master端得到资源状态信息,同步资源管理信息
States:配置管理的指令集
Modules:在命令行中和配置文件中使用的指令模块,可以在命令行 中运行
Grains:minion端的变量,静态的
Pillar:minion端的变量,动态的比较私密的变量,可以通过 配置文件实现同步minions定义 highstate:为minion端下发永久添加状态,从sls配置文件读取. 即同步状态配置
salt_schedule:会自动保持客户端配置
1)安装部署
建议从官网下载安装包,配置saltstack的yum源,可以离线安装部署
服务端
yum install -y salt-master.noarch
客户端
yum install -y salt-minion.noarch
saltstack官方提供了各种版本系统安装方法(地址:http://repo.saltstack.com/#rhel)
2)服务启动和客户端配置
[root@master ~]#systemctl enable salt-master
[root@master ~]#systemctl start salt-master
客户端上:
[root@client ~]# sed -i "s/#master: salt/master: masterip/g" /etc/salt/minion
[root@client ~]# sed -i "s/#id:/id: clientip/g" /etc/salt/minion
[root@client ~]#systemctl enable salt-minion
[root@client ~]#systemctl start salt-minion
minion在第一次启动时,会在/etc/salt/pki/minion/下自动生成minion.pem(private key)和 minion.pub(public key),然后将 minion.pub发送给master。master在接收到minion的public key后,通过salt-key命令accept minion public key,这样在master的/etc/salt/pki/master/minions下的将会存放以minion id命名的 public key,然后master就能对minion发送指令了。
认证命令如下:
[root@master ~]# salt-key –L ? ? #查看当前证书签证情况
Accepted Keys:
Unaccepted Keys:
192.168.100.100
Rejected Keys:
salt-key –a 接受某个客户端请求
salt-key –A 接受所有客户端请求
salt-key –d 删除单个客户端
salt-key –D 删除所有客户端
1、测试连接情况 salt ?* ?test.ping ? ? ? ?
# 测试saltstack minion与master的连通性。
?'*'表示所有目标机器 test.ping 只是模块里的一个功能,用来测试连通性
# 测试指定受控端主机是否存活
[root@master ~]# salt "node1" test.ping
node1: ? ?
? ? ? ? True
2、远程执行命令 salt [options] ‘<目标机>’ <功能> [arguments]
# 例如: #对机器node1使用uptime命令
salt ?'node1' cmd.run 'uptime'
3、文件分发模块
# salt-cp 分发文件到minion上,不支持目录分发,通常在master运行
salt-cp [options] '<target>' SOURCE DEST
salt-cp '*' testfile.html /tmp salt-cp 'node*' /opt/index.html /tmp/a.html
4、其他常用模块命令
salt '*' network.active_tcp ? ? ?# 查看tcp连接情况
salt '*' network.get_hostname ? ?# 查看主机名
salt '*' service.available sshd ?# 查看ssh服务是否可达
salt '*' service.get_all ? ? ? ? # 查看所有启动的服务
salt '*' service.status nginx ? ?# 查看指定服务是否在线
salt '*' sys.doc pkg ? ? ? ? ? #查看pkg模块文档
# salt内置的执行模块列表 http://docs.saltstack.cn/ref/modules/all/index.html
salt states的核心是sls文件,该文件使用YAML语法定义了一些k/v的数据。
sls文件存放根路径在master配置文件中定义,默认为/srv/salt,该目录在操作系统上不存在,需要手动创建。
在salt中可以通过salt://代替根路径,例如你可以通过salt://top.sls访问/srv/salt/top.sls。 在states中top文件也由master配置文件定义,默认为top.sls,该文件为states的入口文件。 一个简单的sls文件如下:
# 1.描述了要装一个httpd服务
apache-install: ?# 这个是一个名称,可以随便写
? pkg.installed: ?# pkg是状态模块,installed是状态模块中的方法
? ? - name: httpd ?# 描述了我在里要装一个httpd包
# 2.描述了httpd服务是启动状态,并且是开机自启动状态
apache-service: ?# 这个是一个名称,可以随便写
? service.running: ?# 描述了httpd服务是运行的状态
? ? - name: httpd
? ? - enable: True ?# 描述httpd服务开机自动启动
# salt ?node1 apache.sls?
功能:获取机器基本信息(cpu、内存)
# 1、查看系统版本 # salt node1 ?grains.item os
# 2、查看cpu型号 # salt node1 grains.item cpu_model
# 3、获取ipv4地址 # salt node1 ?grains.item fqdn_ip4
# 4、查询内核版本 # salt node1 ?grains.item kernelrelease
# 5、查看主机名 # salt node1 grains.item nodename
# 6、查看系统版本号 centos6、centos7等 # salt node1 ?grains.item osmajorrelease
# 7、查看salt版本 ? ? # salt node1 ? grains.item saltversion
# 8、查看cpu数据量 # salt node1 ?grains.item num_cpus
# 9、查看内存大小 # salt node1 ? grains.item mem_total
# 10、查看ipv4地址 # salt node1 ? grains.item ipv4?
ansible基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
ansible是基于模块工作的,本身没有批量部署的能力。 真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。 核心组件包括:
(1)、连接插件connection plugins:负责和被监控端实现通信;
(2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
(3)、各种模块核心模块、command模块、自定义模块;
(4)、借助于插件完成记录日志邮件等功能;
(5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
1)、在线安装
root> yum -y install epel-release root> yum install ansible
2)、离线安装
Yum分析下载依赖 根据目标主机所用操作系统在实验环境安装一个新的操作系统,利用yum分析依赖并下载依赖包到指定目录。
root>yum install -y ?ansible ?--downloadonly --downloaddir=/root/ansible
打包并上传到目标主机
root>tar -cvf ansible.tar ./root/ansible
目标主机解压并执行安装脚本
root>tar -xvf ansible.tar && cd ansible && sh install.sh
其中安装脚本就是根据Yum依赖顺序依次rpm -Uvh 依赖包
Ansible 配置文件/etc/ansible/ansible.cfg?
vim /etc/ansible/ansible.cfg
[defaults]
#inventory ? ? = /etc/ansible/hosts ? ? ?# 主机列表配置文件
#library ? ? ? = /usr/share/my_modules/ ?# 库文件存放目录
#remote_tmp ? ?= $HOME/.ansible/tmp ? ? ?# 临时py命令文件存放在远程主机目录
#local_tmp ? ? = $HOME/.ansible/tmp ? ? ?# 本机的临时命令执行目录 ?
#forks ? ? ? ? = 5 ? ? ? ? ? ? ? ? ? ? ? # 默认并发数,同时可以执行5次
#sudo_user ? ? = root ? ? ? ? ? ? ? ? ? ?# 默认sudo 用户
#ask_sudo_pass = True ? ? ? ? ? ? ? ? ? ?# 每次执行ansible命令是否询问ssh密码
#ask_pass ? ? ?= True ? ? ? ? ? ? ? ? ? ?# 每次执行ansible命令是否询问ssh口令
#remote_port ? = 22 ? ? ? ? ? ? ? ? ? ? ?# 远程主机的端口号(默认22)
建议优化项:?
host_key_checking = False ? ? ? ? ? ? ? # 检查对应服务器的host_key,建议取消注释
log_path=/var/log/ansible.log ? ? ? ? ? # 日志文件,建议取消注释
module_name ? = command ? ? ? ? ? ? ? ? # 默认模块
Inventory 文件用来定义你要管理的主机。其默认位置在?/etc/ansible/hosts?,如果不保存在默认位置,也可通过?-i?选项指定。
被管理的机器可以通过其 IP 或域名指定。未分组的机器需保留在 hosts 的顶部,分组 可以使用?[]?指定,如:
[web]
linuxtoy.org
同时,分组也能嵌套:
[vps:children]
web
db
此外,也可以通过数字和字母模式来指定一系列连续主机,如:
[1:3].linuxtoy.org # 等价于 1.linuxtoy.org、2.linuxtoy.org、3.linuxtoy.org
[a:c].linuxtoy.org # 等价于 a.linuxtoy.org、b.linuxtoy.org、c.linuxtoy.org
可以在每个主机后面指定用户名+密码:ansible_ssh_user='xxx' ansible_ssh_pass='password'
如若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明
如 ?www1.magedu.com:2222 ?可以指定端口
现在,我们执行以下命令来看看 Ansible 是否能正常工作:
ansible -i hosts all -m ping -u www
该命令选项的作用分别为:
?-i:指定 inventory 文件,使用当前目录下的 hosts
?all:针对 hosts 定义的所有主机执行,这里也可以指定组名或模式
?-m:指定所用的模块,我们使用 Ansible 内置的 ping 模块来检查能否正常管理远端机器
?-u:指定远端机器的用户
如果返回如下结果:
linuxtoy.org | success >> {
? ? "changed": false,
? ? "ping": "pong"
}
则说明一切正常。
下面我们再看看远端机器的 uptime:
ansible vps -a 'uptime' ?#这将输出:
linuxtoy.org | success | rc=0 >>
11:23:16 up 177 days, 21:19, ?0 users, ?load average: 0.55, 0.45, 0.39
此处我们省略了?-m,Ansible 默认使用 command 模块;-a?指定模块的参数,即执行?uptime?命令。
ansible通过ssh实现配置管理、应用部署、任务执行等功能, 建议配置ansible端能基于密钥认证的方式联系各被管理节点?
ansible <host-pattern> [-m module_name] [-a args]
ansible +被管理的主机(ALL) +模块 ?+参数
? ? --version ? ? ? ? ? ? ?显示版本
? ? -m module ? ? ? ? ? ? ?指定模块,默认为command
? ? -v ? ? ? ? ? ? ? ? ? ? 详细过程 –vv -vvv更详细
? ? --list-hosts ? ? ? ? ? 显示主机列表,可简写 --list
? ? -k, --ask-pass ? ? ? ? 提示输入ssh连接密码,默认Key验证
? ? -C, --check ? ? ? ? ? ?检查,并不执行
? ? -T, --timeout=TIMEOUT ?执行命令的超时时间,默认10s
? ? -u, --user=REMOTE_USER 执行远程执行的用户
? ? -b, --become ? ? ? ? ? 代替旧版的sudo切换
? ? ? ? --become-user=USERNAME 指定sudo的runas用户,默认为root
? ? -K, --ask-become-pass ?提示输入sudo时的口令
ansible all --list ?列出所有主机
ping模块: 探测网络中被管理主机是否能够正常使用 ?走ssh协议
? ? ? ? ? 如果对方主机网络正常,返回pong
ansible-doc -s ping ? 查看ping模块的语法?
检测所有主机的网络状态
1> ?默认情况下连接被管理的主机是ssh基于key验证,如果没有配置key,权限将会被拒绝
? ? 因此需要指定以谁的身份连接,输入用户密码,必须保证被管理主机用户密码一致
? ? ansible all -m ping -k
2> 或者实现基于key验证 将公钥ssh-copy-id到被管理的主机上 , 实现免密登录
? ?ansible all -m ping
?
1.command模块
Command:在远程主机执行命令,默认模块,可忽略-m选项
? ? > ansible srvs -m command -a 'service vsftpd start'
? ? > ansible srvs -m command -a 'echo adong |passwd --stdin 123456'
此命令不支持 $VARNAME < > | ; & 等特殊符号,需要用shell模块实现
? ? chdir: ? 进入到被管理主机目录
? ? creates: 如果有一个目录是存在的,步骤将不会运行Command命令
? ? ansible websrvs -a 'chdir=/data/ ls'
2.shell模块
Shell:和command相似,用shell执行命令
? ? > ansible all -m shell ?-a 'getenforce' ?查看SELINUX状态
? ? > ?ansible all -m shell ?-a "sed -i 's/SELINUX=.*/SELINUX=disabled' /etc/selinux/config"
? ? > ansible srv -m shell -a 'echo magedu |passwd –stdin wang'
? ? ??
? ? 调用bash执行命令 类似 cat /tmp/stanley.md | awk -F'|' '{print $1,$2}' &> /tmp/example.txt ? ??
? ? 这些复杂命令,即使使用shell也可能会失败,
? ? 解决办法:写到脚本时,copy到远程执行,再把需要的结果拉回执行命令的机器
3.script模块
Script:在远程主机上运行ansible服务器上的脚本
? ? > -a "/PATH/TO/SCRIPT_FILE"
? ? > ansible websrvs -m script -a /data/test.sh
4.copy模块
Copy:从主控端复制文件到远程主机
? ? ? src : 源文件 ?指定拷贝文件的本地路径 ?(如果有/ 则拷贝目录内容,比拷贝目录本身)
? ? ? dest: 指定目标路径
? ? ? mode: 设置权限
? ? ? backup: 备份源文件
? ? ? content: 代替src ?指定本机文件内容,生成目标主机文件
? ? ??
? ? ? > ansible websrvs -m copy -a "src=/root/test1.sh dest=/tmp/test2.showner=wang mode=600 backup=yes"
? ? ? ? 如果目标存在,默认覆盖,此处指定先备份
? ? ? > ansible websrvs -m copy -a "content='test content\nxxx' dest=/tmp/test.txt"
? ? ? ? 指定内容,直接生成目标文件
5、File模块
File:设置文件属性
? ? path: 要管理的文件路径 (强制添加)
? ? recurse: 递归,文件夹要用递归
? ? src: ?创建硬链接,软链接时,指定源目标,配合'state=link' 'state=hard' 设置软链接,硬链接
? ? state: 状态
? ? ? ? ? absent 缺席,删除
? ? ? ? ??
? ? > ansible websrvs -m file -a 'path=/app/test.txt state=touch' ? ? ? 创建文件
? ? > ansible websrvs -m file -a "path=/data/testdir state=directory" ? 创建目录 ? ?
? ? > ansible websrvs -m file -a "path=/root/test.sh owner=wang mode=755" ?设置权限755
? ? > ansible websrvs -m file -a 'src=/data/testfile dest=/data/testfile-link state=link' 创建软链接
6、Cron模块
Cron:计划任务
? ? 支持时间:minute,hour,day,month,weekday
? ? > ansible websrvs -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.16.0.1 &>/dev/null' name=Synctime"?
? ? 创建任务
? ? > ansible websrvs -m cron -a 'state=absent name=Synctime'?
? ? 删除任务
? ? > ansible websrvs -m cron -a 'minute=*/10 job='/usr/sbin/ntpdate 172.30.0.100" name=synctime disabled=yes'
? ? 注释任务,不在生效
对于需反复执行的、较为复杂的任务,我们可以通过定义 Playbook 来搞定。Playbook 是 Ansible 真正强大的地方,它允许使用变量、条件、循环、以及模板,也能通过角色 及包含指令来重用既有内容。我们来看一个简单的例子,该例子在远端机器上创建一个 新的用户:
---
- name: create user
? hosts: vps
? user: root
? gather_facts: false
? vars:
? - user: "toy"
? tasks:
? - name: create {{ user }} on vps
? ? user: name="{{ user }}"
首先,我们给 Playbook 指定了一个名称;接着,通过?hosts?让该 Playbook 仅作用于 vps 组;user?指定以 root 帐号执行,Ansible 也支持普通用户以?sudo?方式执行;gather_facts?的作用是搜集远端机器的相关信息,稍后可通过变量形式在 Playbook 中使用;vars?定义变量,也可单独放在文件中;tasks?指定要执行的任务。
要执行 Playbook,可以敲入:
ansible-playbook user.yml
Ansible自1.2版本之后,引入了Roles的新特性,以便层次性和结构化的组织Playbook。相比于Ansible命令的方式进行控制,Ansible Playbook的控制方式极大的提升了Ansible对于被控端设备的管理能力。但是,如果我们想配置更加复杂的被控端环境,那么单单的将所有的配置命令写成一个Playbook文件就可多达成百上千行。这极不利于Ansible Playbook的管理和维护。
相比于Ansible Playbook,Roles能够层次型结构自动装载变量、任务以及handlers。在本质上,Ansible Roles就是将变量、任务、模板以及处理器分别的放在不同的目录中,并通过include的方式进行调用,并组合成一个整体。
一个项目从开始到结束,不是简单几十个playbook就可以完事了,当文件数很多,有上百个的话,仅通过简单的includes不停的引用,那最终的结果错综复杂。这个时候ansible roles就可以很好的发挥它的作用了。
每个角色的格式,一特定的层级目录结构进行组织,如下:
mysql/
? ? files/
? ? templates/
? ? tasks/
? ? handlers/
? ? vars/
? ? meta/
在playbook中调用角色的方式
- hosts: webservers
? remote_user: root
? roles:
? - mysql
?