自动化运维工具ansible安装部署
一.ansible介绍
1.简介
ansible是新出现的基于Python开发的自动化运维工具,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的特点,实现了批量系统配置、批量程序部署、批量运行命令等功能。ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括:
(1)、连接插件connection plugins:负责和被监控端实现通信;
(2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
(3)、各种模块核心模块、command模块、自定义模块;
(4)、借助于插件完成记录日志邮件等功能;
(5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
2.ansible架构
3.特点
1.不需要代理,不需要客户端
2.没有服务器端,使用时直接运行命令
3.不基于pki工作
4.基于模块工作
5.支持YAML定义剧本
6.默认基于ssh工作
7.可以实现多级指挥
4.任务执行流程
二.ansible安装(这里使用yum方式安装)
1.源码安装
下载地址:
1.1先解决依赖关系
[root@localhost ~]# yum install python-jinja2 PyYAML python-paramiko
python-babel python-crypto python-setuptools
1.2编译安装
[root@localhost ~]# tar xf ansible-1.9.4.tar.gz
[root@localhost ~]# cd ansible-1.9.4
[root@localhost ansible-1.9.4]# python setup.py build
[root@localhost ansible-1.9.4]# python setup.py install
遇到错误:error: Setup script exited with error: command 'gcc' failed with exit status 1
解决办法:
yum install -y python-devel
再次python setup.py install后安装成功;
1.3然后创建ansible目录并将配置文件复制到该目录中:
[root@localhost ansible-1.9.4]# mkdir /etc/ansible
[root@localhost ansible-1.9.4]# cp -r examples/* /etc/ansible/
[root@localhost ansible-1.9.4]# ls /etc/ansible/
ansible.cfg hosts
2.yum安装
EPEL源中有ansible的安装包,配置好EPEL源后直接yum install ansible即可;
也可以先下载在安装:
ansible包下载地址:
三.配置ansible
1.修改/etc/ansible/hosts文件为
[root@localhost ansible]# cat hosts
[webservers]
node1.a.com
node2.a.com
hosts文件定义了所能识别的所有主机,其内容:
1.1可以将所有主机写入此文件,那么此后所做的操作就会影响所有写入的主机;
1.2可以以[主机组名]的方式定义属于同一组的所有主机,如定义[webservers]段,将所有的web主机的IP或者主机名写入段中,此后就可以用ansible实施诸如servicehttpdstatus等仅对web主机所做的操作了,而其他主机则不会受影响,当然一个组中的主机也可以在其他组中出现,不一定每个组中的主机都不相同;
1.3可以用通配符的方式定义,如node[1:3].a.com,表示定义了node1.a.com node2..a.com和node3.a.com三台主机;
1.4可以直接写入主机IP,也可以写入主机名,但是必须保证能解析这些主机名;
2.配置主机互信
控制台主机是通过SSH区联系被控制主机的,那么就需要实现主机互信使控制台主机的命令送到被控端去执行,避免每一次都要输入密码;
[root@localhost ~]# ssh-keygen -t rsa -f /root/.ssh/id_rsa -P ''
[root@localhost ~]# ssh-copy-id -i .ssh/id_rsa.pub node1
[root@localhost ~]# ssh-copy-id -i .ssh/id_rsa.pub node2
这里因为/etc/hosts文件所以能解析:
[root@localhost ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.85.144 node1.a.com node1
192.168.85.145 node2.a.com node2
3.测试ansible能否执行
如查看所有主机时间是否一致:
[root@localhost ~]# ansible all -a 'date'
node2.a.com | success | rc=0 >>
Sat Nov 28 20:28:21 CST 2015
node1.a.com | success | rc=0 >>
Sat Nov 28 20:28:21 CST 2015
四.ansible用法
1.基本语法
语法格式:ansible [-f forks] [-m module_name] [-a args]
其中:
host-pattern:对哪些主机操作,可以是所有主机all或者定义的组;
-f forks:并行级别,即每次对几个主机操作,默认为5个,主机量多时可以调整该值;
-m module_name:指定模块名称;
默认模块为command,为-m command时可以省略不写,指的是让被控主机执行指定的命令,如
[root@localhost ~]# ansible webservers -a 'service httpd status'
node1.a.com | FAILED | rc=3 >>
httpd is stopped
node2.a.com | FAILED | rc=3 >>
httpd is stopped
-a args:指定模块的参数;
2.ansible的模块和模块参数
2.1列出ansible的所有模块
[root@localhost ~]# ansible-doc -l
2.2列出某模块的参数
[root@localhost ~]# ansible-doc -s 模块名
如:
模块copy可以将本地(控制端)文件复制到其他主机(被控端)上,其参数有:
[root@localhost ~]# ansible-doc -s copy
- name: C o p i e s f i l e s t o r e m o t e l o c a t i o n s .
action: copy
backup # Create a backup file including the timestamp information so you can get the ori
content # When used instead of 'src', sets the contents of a file directly to the specifi
dest= # Remote absolute path where the file should be copied to. If src is a directory,
directory_mode # When doing a recursive copy set the mode for the directories. If this is not se
follow # This flag indicates that filesystem links, if they exist, should be followed.
force # the default is `yes', which will replace the remote file when contents are diff
group # name of the group that should own the file/directory, as would be fed to `chown
mode # mode the file or directory should be, such as 0644 as would be fed to `chmod'.
owner # name of the user that should own the file/directory, as would be fed to `chown'
selevel # level part of the SELinux file context. This is the MLS/MCS attribute, sometime
serole # role part of SELinux file context, `_default' feature works as for `seuser'.
setype # type part of SELinux file context, `_default' feature works as for `seuser'.
seuser # user part of SELinux file context. Will default to system policy, if applicable
src # Local path to a file to copy to the remote server; can be absolute or relative.
validate # The validation command to run before copying into place. The path to the file
示例:将本地的a.txt文件复制到node1和node2的/tmp目录下
[root@localhost ~]# ansible webservers -m copy -a "src=/root/a.txt dest=/tmp/"
验证:
[root@localhost ~]# ansible webservers -a "ls /tmp"
node2.a.com | success | rc=0 >>
a.txt
node1.a.com | success | rc=0 >>
a.txt
五.ansible-playbook
当我们按照期望去部署多台服务器工作的时候,可能任务会不止一个,如去安装服务,启动服务,设置服务开机启动等,我们希望这些任务能同时执行,虽然ansible可以批量执行任务,但是每次都执行一次ansible会大大浪费时间,所以,此时就需要playbooks,而ansible playbooks依赖YAML语言工作;
1.YAML介绍:
YAML是一种直观的能够被电脑识别的数据序列化格式,是一个可读性高并且容易被人阅读,容易和脚本语言交互,用来表达资料序列的编程语言。
YAML Ain't Markup Language即YAML不是XML。不过,在开发的这种语言时YAML的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)。其特性:
可读性好
脚本语言的交互性好
使用实现语言的数据类型
有一个一致的信息模型
易于实现
可以基于流来处理
表达能力强,扩展性好
更多的内容及规范参见
2.YAML语法
YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-"来代表,Map里的键值对用":"分隔。
示例:表示一个人的信息
name: John Smith
age: 41
spouse:
name: Jane Smith
age: 37
children:
- name: Jimmy Smith
age: 17
- name: Jenny Smith
age 13
YAML文件扩展名通常为.yaml
3.ansible playbook
playbook是由一个或多个play组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联同起来按事先编排的机制同时工作。
如:
[root@localhost ~]# cat test.yaml
- hosts: webservers
remote_user: root
tasks:
- name: add a user
user: uid=1234 name=testuser system=no
- name: excute a command
command: /bin/date
hosts表示要操作的主机,因为可以有多个hosts,所以在前面加了个-号;
remote_user表示以哪个用户的身份区执行;
task表示要对该hosts执行的任务;
name表示某一任务的描述;
user: uid=1234 name=testuser system=no表示添加用户的uid为1234,用户名为testuser,且不是系统用户
执行测试:
[root@localhost ~]# ansible-playbook test.yaml
PLAY [webservers] *************************************************************
GATHERING FACTS ***************************************************************
ok: [node2.a.com]
ok: [node1.a.com]
TASK: [add a user] ************************************************************
changed: [node2.a.com]
changed: [node1.a.com]
TASK: [excute a command] ******************************************************
changed: [node1.a.com]
changed: [node2.a.com]
PLAY RECAP ********************************************************************
node1.a.com : ok=3 changed=2 unreachable=0 failed=0
node2.a.com : ok=3 changed=2 unreachable=0 failed=0
4.playbook基础组件
4.1 Hosts和Users
playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,其可以是一个或多个由冒号分隔主机组;remote_user则用于指定远程主机上的执行任务的用户。如上面示例中的
- hosts: webservers
remote_user: root
不过,remote_user也可用于各task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户。
- hosts: webnodes
remote_user: lw
tasks:
- name: test connection
ping:
remote_user: lw
sudo: yes
4.2 任务列表和action
play的主体部分是task list。task list中的各任务在所有主机上完成第一个任务后再开始第二个。在运行自下而下的某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此,在更正playbook后重新执行一次即可。
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。
每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出。
定义task的可以使用action:module options或module:options的格式,推荐使用后者以实现向后兼容。如果action一行的内容过多,也可在行首使用几个空白字符进行换行。
tasks:
- name: make sure apache is running
service: name=httpd state=running
在众多模块中,只有command和shell模块仅需要给定一个列表而无需使用key=value格式,例如:
tasks:
- name: disable selinux
command: /sbin/setenforce 0
如果命令或脚本的退出码不为零,可以使用如下方式替代:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/command || /bin/true
或者使用ignore_errors来忽略错误信息:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/command
ignore_errors: true
4.3 handlers
用于当关注的资源发生变化时采取一定的操作。
notify这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,即notify中调用handler中定义的操作
- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify:
- restart memcached
- restart apache
handler是task列表,这些task与前述的task并没有本质上的不同。
handlers:
- name: restart memcached
service: name=memcached state=restarted
- name: restart apache
service: name=apache state=restarted
如:
先将控制端主机httpd配置文件中监听端口改为8080
[root@localhost ~]# cat http.yaml
- hosts: webservers
remote_user: root
tasks:
- name: ensure httpd is the latest
yum: state=latest name=httpd
- name: ensure httpd configuration file changed
copy: src=/etc/httpd/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf force=yes
notify:
- restart httpd
handlers:
- name: restart httpd service
service: name=httpd state=restarted
这里先yum保证httpd版本是最新的,然后将本地已修改的httpd.conf文件复制(覆盖原文件)到被控端的指定位置,再确保配置文件已经修改后,notify才调用handlers执行httpd服务重启操作,如果配置文件没变,那么就不会重启服务;
注意:notify后的restart httpd要和handlers中的- name保持一致;
执行测试:
[root@localhost ~]# ansible-playbook http.yaml
PLAY [webservers] *************************************************************
GATHERING FACTS ***************************************************************
ok: [node1.a.com]
ok: [node2.a.com]
TASK: [ensure httpd is the latest] ********************************************
ok: [node2.a.com]
ok: [node1.a.com]
TASK: [ensure httpd configuration file changed] *******************************
ok: [node2.a.com]
ok: [node1.a.com]
PLAY RECAP ********************************************************************
node1.a.com : ok=3 changed=0 unreachable=0 failed=0
node2.a.com : ok=3 changed=0 unreachable=0 failed=0
验证:
[root@localhost ~]# ansible webservers -m raw -a 'netstat -ntlp | grep :8080'
node2.a.com | success | rc=0 >>
tcp 0 0 :::8080 :::* LISTEN 26461/httpd
node1.a.com | success | rc=0 >>
tcp 0 0 :::8080 :::* LISTEN 26943/httpd