Ansible基础

一、Ansible简介
Ansible是一个开源的配置管理引擎,使用Python编写,是一个无代理的解决方案,通过默认的OpenSSH连接到一个受控节点。由Cobbler的作者和Func框架的合作者Michael DeHaan开发。Ansible于2015年10月被开源巨头RedHat收购,希望未来Ansible能结合RedHat系统发挥巨大作用。


二、安装Ansible
1.环境
角色 主机名 IP 组名 系统
Master test.elisun.com 192.168.1.209 ———— CentOS 6.5
Node1 test1.elisun.com 192.168.1.210 webservers CentOS 6.5
Node2 test2.elisun.com 192.168.1.211 dbservers CentOS 6.5

2.安装Ansible
由于目前ansible还没有被集成到红帽的默认yum仓库中,所以需要安装epel。
# rpm -Uvh http://mirrors.ustc.edu.cn/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
# yum install ansible
三、Ansible基本配置
1.ansible主机和主机组定义
默认定义主机的文件为/etc/ansible/hosts
192.168.1.210
test2.elisun.com
test[1:2].elisun.com
[webservers]
192.168.1.210
[dbservers]
192.168.1.211
[WebsAndDbs:children]
webservers
dbservers
定义规则:
主机可以用域名、IP、别名进行标识,[webservers]、[dbservers]为组名,组名的下方为组的成员,所以对于单个主机来说,一定要靠上写。
可以使用通配符、范围等表示主机群(例如test[1:2].elisun.com,表示两个主机)。
支持组嵌套,父组名+":children",如[WebsAndDbs:children],其下跟上要包含的组名,可以用"ansible WebsAndDbs --list-hosts"命令列出其下包含的主机。
2./etc/ansible/ansible.cfg
ansible的主配置文件,可以修改许多默认配置,无需重启,例如可以打开日志记录,去掉'log_path = /var/log/ansible.log'前面的'#'即可。
3.配置SSH无密码验证
由于ansible是基于ssh进行操作的,所以每次操作都需要输入密码或者将密码写入到配置文件,所以为了方便和安全采用ssh无密码原则,配置请自行搜索。
四、 Ansible常用模块(命令行操作格式为:ansible 主机 -m 模块名 -a '模块参数')
1. Ping模块
Ping模块验证与目标主机的连通性。
# ansible webservers -m ping
2. 远程命令模块
模块包括command、script、shell,都可以实现远程shell命令运行。command作为Ansible的默认模块,可以运行远程权限范围内所有shell命令;script功能是在远程主机执行主控端存储的shell脚本;shell功能是执行远程主机的shell脚本文件。
# ansible webservers -m command -a "df -h"
# ansible webservers -m script -a "/tmp/test.sh"
# ansible webservers -m shell -a "/tmp/test.sh"
3. copy模块
实现主控端向目标拷贝文件,类似于scp的功能。
# ansible webservers -m copy -a "src=/etc/httpd/conf/httpd.conf dest=/tmp/ owner=www group=www mode=0644"
4. stat模块
获取远程文件状态信息,包括atime、ctime、mtime、md5、uid、gid等信息。
# ansible webservers -m stat -a "path=/etc/passwd"
5. get_url模块
实现在远程主机下载指定URL到本地,支持sha256sum文件校验。
# ansible webservers -m get_url -a "url=https://www.baidu.com dest=/tmp/index.html mode=0440 force=yes"
6. yum模块
在远程机器上安装软件。
# ansible webservers -m yum -a "name=httpd state=latest"
7. cron模块
远程主机定时任务。
# ansible webservers -m cron -a "name='a job for time sync' minute=*/30 job='/usr/sbin/ntpdate 1.asia.pool.ntp.org && /sbin/hwclock -w'"
效果如下:
#Ansible: a job for time sync
*/30 * * * * /usr/sbin/ntpdate 1.asia.pool.ntp.org && /sbin/hwclock -w
8. user模块
远程主机用户管理。
# ansible webservers -m user -a "name=eli comment=elisun" (创建)
# ansible webservers -m user -a "name=eli state=absent remove=yes" (删除)
9. Setup模块
这个模块帮助我们收集系统的相关信息。
# ansible webservers -m setup
10. 模块帮助
# ansible-doc -l //查看支持的模块
# ansible-doc 模块名 //查看该模块的帮助信息
五、 Ansible playbook
剧本(playbook)是部署指令的集合,这些指令也称为演出(plays)。使用剧本的好处是可以组合多个Ansible模块。playbook是通过YAML格式进行描述定义的,文件名一般以yml为后缀。
1. 剧本举例 web服务器剧本:apache.yml

---
- hosts: webservers
  tasks:
  - name: deploy apache
    yum: pkg=httpd state=latest
  - name: apache config file
    copy: src='files/httpd.conf' dest='/etc/httpd/conf/httpd.conf'
    notify:
    - restart httpd
  - name: apache service runs
    service: name=httpd state=started
  handlers:
    - name: restart httpd
    service: name=httpd state=restarted

hosts关键字指定运行这些指令的主机(/etc/ansible/hosts文件中的webservers组)
tasks关键字表示webservers组中主机上将要执行的模块的开始。每个task至少包括两个部分,name:是一个标识,让阅读代码的人知道这个任务的作用;第二个部分是要执行的Ansible模块(我们上述第一个任务是执行yum模块)。
notify表示响应配置文件更改时执行某些功能的Ansible处理程序名称。
handlers和tasks部分很类似,但是handlers起着特殊的作用——响应notify通知操作,即notify表示要干啥,而handlers负责怎么干。注意notify下指定的操作要和handler下的某个name关键字相匹配。
总结一下,一般的剧本文件包含四个主要部分:主机定义(hosts)、变量定义(vars)、任务定义(tasks)、处理程序定义(handles)。
2. 条件表达式和变量
上面的例子我们的apache剧本已经准备好,针对的系统是RedHat。但是,如果我们的生产环境有基于Debian的系统(例如,Ubuntu)怎么办?我们需要优雅的处理多种操作系统。
when:条件语句允许根据偏好调整主机上执行的Ansible任务。
我们对上面的例子进行修改,以便能根据系统做相应的操作,如下代码。

---
- hosts: webservers
tasks:
# Deploy the Web Server
- name: Deploy Apache for Red Hat Systems
yum: pkg=httpd state=latest
when: ansible_os_family == 'RedHat'
- name: Deploy Apache for Debian Systems
apt: pkg=apache2 state=latest
when: ansible_os_family == 'Debian'

# Copy Config File
- name: Apache Config File for Red Hat Systems
copy: src='files/httpd.conf' dest='/etc/httpd/conf/httpd.conf'
notify:
- restart httpd redhat
when: ansible_os_family == 'RedHat'
- name: pache Config File for Debian Systems
copy: src='files/apache2.conf' dest=/etc/apache2/apache2.conf
notify:
- restart httpd debian
when: ansible_os_family == 'Debian'

# Verify Web Service is running
- name: Apache Service Runs for Red Hat Systems
service: name=httpd state=started
when: ansible_os_family == 'RedHat'
- name: Apache Service Runs for Debian Systems
service: name=apache2 state=started
when: ansible_os_family == 'Debian'

# Restart Web Service in response to config file change
handlers:
- name: restart httpd redhat
service: name=httpd state=restarted
- name: restart httpd debian
service: name=apache2 state=restarted

'#'注释为便于理解。WEB服务器部署中的每个重要步骤都有两组指令,一组为RedHat系统,另一组为Debian系统。Ansible将求取when:语句的值,决定在目标节点上执行的任务,该语句使用ansible_os_family系统fact变量(ansible webservers -m setup | grep family)提供模块执行指导。
有木有发现一个问题,上述代码写的太冗余了,我们可以使用Ansible的group_by函数来简化代码,该函数能够自动根据某些条件(例如,ansible_os_family)创建更多的主机组。从来自/etc/ansible/hosts文件中webservers组开始,告诉ansible从该组中创建附加组,以ansible_os_family系统事实作为选择条件。对于我们的系统意味着运行时将创建两个组(RedHat and Debian),这些主机组将用于剧本的其余部分,代码如下。

---
- hosts: webservers
tasks:
- name: Group Servers By Operating System Family
action: group_by key={{ ansible_os_family }}
- hosts: RedHat
- name: Deploy Apache
yum: pkg=httpd state=latest
- name: Apache Config File
copy: src='files/httpd.conf' dest='/etc/httpd/conf/httpd.conf'
notify:
- restart httpd
- name: apache service runs
service: name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted

- hosts: Debian
- name: Deploy Apache
apt: pkg=apache2 state=latest
- name: Apache Config File
copy: src='files/apache2.conf' dest='/etc/apache2/apache2.conf'
notify:
- restart httpd
- name: apache service runs
service: name=httpd state=started
handlers:
- name: restart httpd
service: name=apache2 state=restarted

when条件语句和group_by函数都可以解决根据操作系统类型来引导剧本执行的问题。
但是,关键的问题是尼玛代码还是那么多,我们接下来通过Ansible的其它能力来优化下代码,代码如下。
#apache.yml

---
- hosts: webservers
vars_files: 
- "vars/{{ ansible_os_family }}.yml"
tasks:
- name: Deploy Apache for Red Hat Systems
yum: pkg=httpd state=latest
when: ansible_os_family == 'RedHat'
- name: Deploy Apache for Debian Systems
apt: pkg=apache2 state=latest
when: ansible_os_family == 'Debian'
- name: Apache Config File
copy: src=files/{{ conffile }} dest={{ confpath }}
notify:
- restart httpd
- name: Apache Service Runs
service: name={{ webserver }} state=started
handlers:
- name: restart httpd
service: name={{ webserver }} state=restarted

 

#RedHat.yml

---
webserver: 'httpd'
conffile: 'httpd.conf'
confpath: '/etc/httpd/conf/httpd.conf'
contentpath: '/var/www/html/index.html'

 

#Debian.yml

webserver: 'apache2'
conffile: 'apache2.conf'
confpath: '/etc/apache2/apache2.conf'
contentpath: '/var/www/index.html'

 

目录结构
├── apache.yml
├── files
│ ├── apache2.conf
│ └── httpd.conf
├── host
└── vars
├── Debian.yml
└── RedHat.yml
该代码示例中,我们加入了一个新元素:vars_files。这个关键字告诉Ansible我们在哪里保存剧本中使用的变量。变量必须包含在{{ }}中。直观来看,我们发现经过优化的代码好像还是不尽人意,但是不可否认的是我们的逻辑更加清晰了,重复的动作越来越少。因为这个案例的代码比较少,所以再怎么优化它也很难减少,但是在更大的剧本中,使用变量可能会带来更为显著的优化效果。
六、Ansible角色
目前,组织文件是个简单的任务,因为我们只处理Apache的部署,但是,如果我们想部署其它类型的服务呢?我们要不断地在当前YAML文件中添加用于数据库、应用服务等的附加演出吗?即使应用模块化设计,将演出分隔到单独的YAML文件中,那么组织文件(配置文件、变量文件等)的最佳方法又是什么?是将它们放在公共的目录中,还是根据功能创建不同的子目录?Ansible的作者考虑了这些问题,实现角色功能来实现它们。
Apache Web服务器角色示例:
├── apache.yml
└── roles
└── web
├── defaults
│ └── main.yml
├── files
│ ├── apache2.conf
│ └── httpd.conf
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
└── vars
├── Debian.yml
├── main.yml
└── RedHat.yml
roles目录和apache.yml文件在同级目录下,其余目录和文件在roles目录下。
defaults: 如果角色在调用时接受参数,可以将包含未在主剧本角色中指定的默认值的YAML文件放在这个目录下。
files: 打算复制到目标主机的任何文件。
handlers: 执行响应剧本任务通知的指令(例如,配置文件更改后重启服务)
meta: 当前角色所以来的其它Ansible角色引用。
tasks: 剧本任务位置。
templates: 可用于根据系统事实或者其它变量动态生成内容的Jinja2文件。
vars: 剧本使用的变量。
apache.yml
---
- hosts: webservers
roles:
- web
角色名字web必须与roles文件夹中的子目录名相符合(方能匹配)。剧本中的tasks和handlers分隔到了单独的文件,这些文件名都为main.yml,分别在tasks和handlers子目录下(roles/web/{tasks,handlers}/main.yml)
roles/web/tasks/main.yml

---
- name: Ansible OS Family
include_vars: '{{ ansible_os_family }}.yml'
- name: Deploy Apache for Red Hat Systems
yum: pkg=httpd state=latest
when: ansible_os_family == 'RedHat'
- name: Deploy Apache for Debian Systems
apt: pkg=apache2 state=latest
when: ansible_os_family == 'Debian'
- name: Apache Config File
copy: src={{ conffile }} dest={{ confpath }}
notify:
- restart httpd
- name: Apache Service Runs
service: name={{ webserver }} state=started

 

roles/web/handlers/main.yml

---
- name: Ansible OS Family
include_vars: "{{ ansible_os_family }}.yml"
- name: restart httpd
service: name={{ webserver }} state=restarted

 

执行命令:# ansible-playbook apache.yml


参考书籍:
《DevOps实战》
《Python自动化运维》

posted @ 2017-05-20 01:56  elisun  阅读(533)  评论(0编辑  收藏  举报