声明:这是我在大学毕业后进入第一家互联网工作学习的内容
我从自动化运维入门开始,第一个学习的自动化工具就是ansible。
百度解释
ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括:
- 连接插件connection plugins:负责和被监控端实现通信;
- host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
- 各种模块核心模块、command模块、自定义模块;
- 借助于插件完成记录日志邮件等功能;
- playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
个人理解
用通俗的话来解释,ansbile可以分组,每个组里添加目标机器ip,通过密钥或者密码连接成功组里的机器后,你就可以用ansbile命令操作每个组的机器了。对于大规模的机器群来说,ansbile是必不可少的运维工具。
ansbile的特点:
- 部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作;
- 默认使用SSH协议对设备进行管理;
- 有大量常规运维操作模块,可实现日常绝大部分操作;
- 配置简单、功能强大、扩展性强;
- 支持API及自定义模块,可通过Python轻松扩展;
- 通过Playbooks来定制强大的配置、状态管理;
- 轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;
- 提供一个功能强大、操作性强的Web管理界面和REST API接口——AWX平台。
当然你可能不需要用到ansbile所有功能,以下是我认为实战中ansbile用的最爽的几个点:
- 配置管理:将配置文件批量放到你指定组的机器某一目录下,或者指定路径后一次性修改指定组的机器该路径下的配置文件
- 应用部署:如java应用编译好成jar包,ansbile直接将jar包分发到指定组的机器某一目录下,执行启动命令
- 滚动发布:有人可能会问了,ansible也能滚动发布?其实只要了解滚动发布的原理,用ansbile一样可以做到。例如在生产环境利用负载均衡分发流量到底层存在多个运行java应用的实例中,那么滚动更新就是先控制一台组里的机器,杀进程,启动新的jar包,监控jar包启动成功等,如果这台组里的机器成功,则让后续组里的机器继续更新,否则终止。
开始ansible之旅
安装ansible
两种安装方式都行
- pip安装
yum install python-pip
pip install ansible
- yum安装
yum install epel-release -y
yum install ansible –y
安装完成后执行ansible --version
[root@localhost ~]# ansible --version
ansible 2.9.7
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Oct 30 2018, 23:45:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
配置ansible
默认配置文件
配置文件路径在/etc/ansible
[root@localhost ansible]# pwd
/etc/ansible
[root@localhost ansible]# ll
total 24
-rw-r--r--. 1 root root 19985 Apr 19 05:24 ansible.cfg
-rw-r--r--. 1 root root 1016 Apr 19 05:24 hosts
drwxr-xr-x. 2 root root 6 Apr 19 05:24 roles
修改ansible.cfg
将以下几个参数的注释去掉并修改
host_key_checking= False
timeout = 30 增加ssh的超时时间
log_path = /var/log/ansible.log 存日志
主机清单
ansible有2种连接主机清单的方式
基于密码连接
[root@localhost ansible]# vim /etc/ansible/hosts
#添加两个组dev、test
[dev]
172.31.22.31 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
172.31.22.33 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
172.31.22.35 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
[test]
172.31.24.31 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
172.31.24.33 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
172.31.24.35 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass="123456"
修改完后ping下该组主机是否都能连上
[root@localhost ansible]# ansible dev -m ping
172.31.22.33 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
172.31.22.31 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
172.31.22.35 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
基于秘钥连接
[root@localhost ansible]# ssh-keygen
[root@localhost ansible]# for i in {1,3,5}; do ssh-copy-id -i 172.31.22.3$i ; done
[root@localhost ansible]# for i in {1,3,5}; do ssh-copy-id -i 172.31.24.3$i ; done
[root@localhost ansible]# vim /etc/ansible/hosts
#添加两个组dev、test
[dev]
172.31.22.31
172.31.22.33
172.31.22.35
[test]
172.31.24.31
172.31.24.33
172.31.24.35
修改完后ping下该组主机是否都能连上
[root@localhost ansible]# ansible test -m ping
172.31.24.33 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
172.31.24.31 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
172.31.24.35 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
ansbile常用模块
下面举几个日常用的比较多的模块,没有列举完所有的,下列模块掌握之后日常对付批量操作虚拟机的任务是没问题的。
ping模块
测试主机连通性
ansible $1 -m ping
$1:组名 eg:dev
command模块
这个模块可以直接在远程主机上执行命令,并将结果返回本主机。
注意,该命令不支持| 管道命令
ansible $1 -m command -a $2
$1:组名 eg:dev
$2:命令 eg:'ip add'
shell模块
shell模块可以在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等。
ansible $1 -m shell -a $2
$1:组名 eg:dev
$2:命令 eg:'ps -aux|grep java'
shell模块 vs command模块
这两个模块在很多情况下都能完成同样的工作,以下是两个模块之前的区别:
-
command 模块命令将不会使用 shell 执行。
-
因此, 像 $HOME 这样的变量是不可用的。还有像<, >, |, ;, &都将不可用。
-
shell 模块通过shell程序执行, 默认是/bin/sh, <, >, |, ;, & 可用,但这样有潜在的 shell 注入风险。
-
command 模块更安全,因为他不受用户环境的影响。 也很大的避免了潜在的 shell 注入风险。
copy模块
这个模块用于将文件复制到远程主机,同时支持给定内容生成文件和修改权限等。
ansible $1 -m copy -a $2
$1:组名 eg:dev
$2:命令 eg:'src=/data/test.sh dest=/data mode=777 '
参数详解
src #被复制到远程主机的本地文件。可以是绝对路径,也可以是相对路径。如果路径是一个目录,则会递归复制,用法类似于"rsync"
content #用于替换"src",可以直接指定文件的值
dest #必选项,将源文件复制到的远程主机的绝对路径
backup #当文件内容发生改变后,在覆盖之前把源文件备份,备份文件包含时间信息
mode #递归设定目录的权限,默认为系统默认权限
force #当目标主机包含该文件,但内容不同时,设为"yes",表示强制覆盖;设为"no",表示目标主机的目标位置不存在该文件才复制。默认为"yes"
others #所有的 file 模块中的选项可以在这里使用
fetch模块
该模块用于从远程某主机获取(复制)文件到本地。
ansible $1 -m fetch -a $2
$1:组名 eg:dev
$2:命令 eg:'src=/data/test.sh dest=/data '
dest:用来存放文件的目录
src:在远程拉取的文件,并且必须是一个file,不能是目录
文件保存的路径是我们设置的接收目录下的被管制主机ip目录下
[root@localhost data]# ansible dev -m fetch -a 'src=/data/test.sh dest=/data'
172.31.22.33 | CHANGED => {
"changed": true,
"checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00",
"dest": "/data/172.31.22.33/data/test.sh",
"md5sum": "2da6c61e985bf3cece7ece373c3976b0",
"remote_checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00",
"remote_md5sum": null
}
172.31.22.31 | CHANGED => {
"changed": true,
"checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00",
"dest": "/data/172.31.22.31/data/test.sh",
"md5sum": "2da6c61e985bf3cece7ece373c3976b0",
"remote_checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00",
"remote_md5sum": null
}
172.31.22.35 | CHANGED => {
"changed": true,
"checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00",
"dest": "/data/172.31.22.35/data/test.sh",
"md5sum": "2da6c61e985bf3cece7ece373c3976b0",
"remote_checksum": "d53a75b15c0c9eaf4633e26442f4cca32c600c00",
"remote_md5sum": null
}
[root@localhost data]# ll
total 28
drwxr-xr-x. 3 root root 4096 May 15 10:08 172.31.22.31
drwxr-xr-x. 3 root root 4096 May 15 10:08 172.31.22.33
drwxr-xr-x. 3 root root 4096 May 15 10:08 172.31.22.35
[root@localhost data]# cd 172.31.22.31/data
[root@localhost data]# ll
total 4
-rwxr-xr-x. 1 root root 352 May 15 10:08 test.sh
yum模块
该模块主要用于软件的安装
ansible $1 -m yum -a $2
$1:组名 eg:dev
$2:命令 eg:'name=tree state=present'
name= #所安装的包的名称
state= #present 安装, latest 安装最新的, absent 卸载软件。
[root@localhost ~]# ansible dev -m yum -a 'name=tree state=present'
172.31.22.31 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"msg": "",
"rc": 0,
"results": [
"tree-1.6.0-10.el7.x86_64 providing tree is already installed"
]
}
172.31.22.35 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"installed": [
"tree"
]
},
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * elrepo: mirrors.tuna.tsinghua.edu.cn\n * epel: mirrors.tuna.tsinghua.edu.cn\n * extras: mirrors.aliyun.com\n * updates: mirrors.aliyun.com\nResolving Dependencies\n--> Running transaction check\n---> Package tree.x86_64 0:1.6.0-10.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n tree x86_64 1.6.0-10.el7 base 46 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 46 k\nInstalled size: 87 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : tree-1.6.0-10.el7.x86_64 1/1 \n Verifying : tree-1.6.0-10.el7.x86_64 1/1 \n\nInstalled:\n tree.x86_64 0:1.6.0-10.el7 \n\nComplete!\n"
]
}
172.31.22.33 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"installed": [
"tree"
]
},
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * elrepo: mirrors.tuna.tsinghua.edu.cn\n * epel: mirrors.tuna.tsinghua.edu.cn\n * extras: mirrors.aliyun.com\n * updates: mirrors.aliyun.com\nResolving Dependencies\n--> Running transaction check\n---> Package tree.x86_64 0:1.6.0-10.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n tree x86_64 1.6.0-10.el7 base 46 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 46 k\nInstalled size: 87 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : tree-1.6.0-10.el7.x86_64 1/1 \n Verifying : tree-1.6.0-10.el7.x86_64 1/1 \n\nInstalled:\n tree.x86_64 0:1.6.0-10.el7 \n\nComplete!\n"
]
}
注意:已安装目标软件的机器不会再执行安装
ansible playbook
playbook 是 ansible 用于配置,部署,和管理被控节点的剧本。即写好一个剧本后,根据组的不同可以使用一个剧本来批量操作服务器,比如这个剧本制作好了后,可以给dev组安装java环境,安装完成后,还可以给test组安装,有点模板的意思。
格式
创建一个带.yml结尾的文本,文本内容应该遵循下面几点
- 文件的第一行应该以 “—” (三个连字符)开始,表明文件的开始。
- 在同一行中,#之后的内容表示注释。
- YML中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。
- 同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。
- play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以":“分隔表示,”:"后面还要增加一个空格。
Playbook的核心元素:
- Hosts:主机组
- Tasks:任务列表
- Variables:变量,设置方式有四种
- Templates:包含了模板语法的文本文件——Jinja是一种现代且设计友好的Python模板语言,以Django的模板为模型。借助可选的沙盒模板执行环境,它可以快速,广泛地使用并且安全
- Handlers:由特定条件触发的任务
Playbooks配置文件的基础组件:
- Hosts:运行指定任务的目标主机
- remoute_user:在远程主机上执行任务的用户
- tasks:任务列表
格式:
tasks:
– name: TASK_NAME
module: arguments
notify: HANDLER_NAME
handlers:
– name: HANDLER_NAME
module: arguments
handlers:任务,在特定条件下触发;接收到其它任务的通知时被触发;
(1) 某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers;
(2) 任务可以通过“tags“打标签,而后可在ansible-playbook命令上使用-t指定进行调用;
ansible-playbook命令的命令行中的-e vars=VARS,这样就可以直接把自定义的变量传入。
例如下面的playbook
你需要改http_port 端口可以这样执行
ansible-playbook ansible_httpd.yml -e http_port=81
你需要定向执行tag:startapache的方法
ansible-playbook ansible_httpd.yml -t startapache
官网的第一个的playbook
[root@localhost ~]# vim ansible_httpd.yml
---
- hosts: dev #ansbile定义的组名
vars: #变量,可以传到template里的httpd.j2里,也可以直接在yml文件里利用
http_port: 80
max_clients: 200
#远程执行的用户
remote_user: root
tasks:
- name: ensure apache is at the latest version #方法名
#基础模块:参数
yum: pkg=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
#执行name为restart apache的方法
notify:
- restart apache
- name: ensure apache is running
service: name=httpd state=started
tag:startapache
#这里的restart apache和上面的触发是配对的。这就是handlers的作用。相当于tag
handlers:
- name: restart apache
service: name=httpd state=restarted #重启服务器
总结
ansible最基本的知识就梳理到这了,其实对于大部分场景已经够用了。如果需要定制化长期使用ansible编排,推荐用ansbile-playbook的模式,这样对于大型集群维护更方便,例如改脚本、配置更新、重启等。如果是偶尔用ansbile可以直接使用普通命令。本文展示的ansible只是一个入门教程,实际使用中对于更多丰富模块的利用、以及优化ansible的性能的方法可以看下面参考资料的官方文档。
下期通过ansible配合jenkins展现实战中ansbile的可用性。
参考资料
版权声明:
原创不易,洗文可耻。除非注明,本博文章均为原创,转载请以链接形式标明本文地址。