Ansible 教程

30 Aug 2015

Ansible 是一套自动化 IT 部署工具,用于批量配置系统,安装或升级软件,以及完成其他更多更高级的 IT 部署需求。目前还有其他几款普遍用于生产的 IT 自动化工具,比如 Fabric,Chef,Puppet,SaltStatck;而 Ansible 能区别于这些工具的最大特性便是一点——简单。这要从两点说起,一是依赖简单,二是使用简单。

先说依赖,Ansible 被设计成只需要极少的依赖便能够执行任务。Ansible 不需要远程服务器上安装任何的 Agent 便能在其上执行部署操作,它使用OpenSSH传输指令,用Python执行指令,而几乎所有服务器开箱即具备 OpenSSH和 Python。因此,不论你有多少服务器,不需要事先在这些服务器上进行任何改动,只需要有一台安装了 Ansible 工具的主机,便能够由此向其它服务器执行自动化部署任务。

Ansible 的使用也很简单,很符合直觉。几乎你要在远程服务器上执行的每一个任务都有对应的模块,比如 yum 模块用于在 CentOS 上安装软件,apt 模块用于在 Ubuntu 上安装软件,你的任务就是安排不同的模块完成不同的工作,以使系统达到预期的状态。当任务比较简单时,你可以简单地用 ansible 命令行发出指令,它能很好地工作;而当任务比较复杂时,你可以将各种模块组织成一个 playbook,Ansible 能从中获取信息并恰当地执行任务。

Ansible 安装

在CentOS 6上,可以通过EPEL安装Ansible。

$ sudo yum install epel-release
$ sudo yum install ansible

受控机器不需要做任何改动,只要保证安装有 Python,并且 OpenSSH 服务是开启的。一个例外是,如果受控机器开启了 SELinux,那么一些文件相关的操作(比如复制文件)需要在受控机器上先安装 libselinux-python(当然这也可以使用 Ansible 的 yum 模块来安装)。

Inventory

Inventory 被称为“设备清单”,在这里定义你的主机信息。Ansible 从 inventory 文件获取每次执行任务的目标机器。

Inventory的默认位置为/etc/ansible/inventory。它的格式很简单:

[webserver]
192.168.1.21
192.168.1.22 ansible_ssh_port=8888 ansible_ssh_user=lijian

[db]
192.168.1.23 ansible_ssh_private_key_file=/home/example/.ssh/aws.pem
192.168.1.24

其中方括号里的名字(比如webserver, db)是分组的名称,组下面是主机名字或者IP地址,每行一个主机。

主机 192.168.1.22 后面的 ansible_ssh_port=8888 称为 inventory 变量,可以在这里定义一些与主机相关的信息,比如主机端口,ssh连接的用户等。在这里可以找到所有可用的 inventory 变量。

Ansible 命令行

对于较复杂的配置和部署任务,合理的方式是使用 Ansible Playbook,后文会有详细介绍。但有时候我们也想执行一些简单、快速的任务,不需要使用 Playbook 的框架,那么此时可以使用 ansible 命令行轻松地完成。

使用/usr/bin/ansible在远程机器上执行任务的格式如下:

$ ansible <pattern> -m <modue> -a <arguments>

这里的 pattern 指定在哪些机器上执行操作。pattern 一般是 inventory 文件里的主机名或者组名,比如上文中定义的 webserver 和 db。特殊地,all 指代 inventory 里定义的所有主机。

module 指定要执行的模块,比如安装软件包的 yum 模块或者 apt 模块。后边的 arguments 指定该模块可以使用的参数。

举一些例子:

  1. 让所有主机返回“hello”

     $ ansible all -m command -a "echo hello"
    

    这里使用的是 command 模块,用来返回一个“hello”。如果不指定模块,就默认使用 command 模块,所以这里的 -m command 可以省略。

  2. 传输文件

     $ ansible webserver -m copy -a "src=/etc/hosts dest=/tmp/hosts"
    

    这里使用 copy 模块,向 webserver 组里的所有主机传输 /etc/hosts 文件至 /tmp/hosts (scp)。

  3. 安装软件

     $ ansible db -m yum -a "name=mongodb state=present"
    

    这里使用 yum 模在 db 组里的所有主机上安装 mongodb。

    不同的模块有着各自不同的参数,具体的可以在使用时参考 Ansible 的模块文档。

  4. 指定登录用户

    Ansible 使用 OpenSSH 和远程机器沟通。默认的认证方式是公钥/密钥对,当然也可以使用密码登录。

    在命令行用 -u 指定登录(和执行任务的)用户名,并要求交互地输入登录密码,如下:

     $ ansible webserver -a 'echo hello' -u lijian --ask-pass
    
  5. 使用 sudo 执行任务

    使用普通用户登录,而后用 sudo 来执行任务:

     $ ansible db -a yum -u lijian --ask-pass --sudo --ask-sudo-pass
    

Ansible Playbook

Playbook的意思是“剧本”,顾名思义,Ansible 据此来“表演”配置和部署工作。结构上,一个 Playbook 包含一个或多个 play,而 play 不过是面向某个(组)服务器的 tasks 的组合。

可以看到,Playbook 的结构是很简单的,这里给出一个简单的示例就会更加明了了:

---
- hosts: webserver
  remote_user: yourname
  tasks:
    - name: ensure apache is at the lastest version
      yum: pkg=httpd state=latest
    - name: write the apache config file
      template: src=/srv/httpd.conf.j2 dest=/etc/httpd.conf
      notify:
        - restart apache
    - name: ensure apache is running( and enable it at boo)
       service: name=httpd state=started enabled=yes
  handlers:
    - name: restart apache
      service: name=httpd state=restarted

首先要说明,Playbook 的书写语法是一种叫做 YAML 的格式,它非常简单,Ansible用到的部分只需两句就能表述清楚:

  • 同一级别缩进的 - 形式表示一个列表的项
  • 同一级别缩进的 key: value 形式表示一个字典的项

另外,再加上一个通用的约定,每个 YAML 文件都以 --- 开始第一行。

上面给出的这个 Playbook 只包含一个 play,这个 play 面向 webserver 组的机器,需要执行三个 tasks,执行的任务身份是 username。我们可以看到,每个task 其实就是一个模块的调用,再给它起个名字而已。具体地来看:

第一个 task 是要保证 httpd 服务是安装了的并且在最新的版本,我们用 yum 模块来完成这个任务。第二个 task 是要生成一份 httpd 的配置文件,这里使用 template 模块来完成,需要注意的是多出来的 notify,它的意思是说完成了这个任务以后要触发名为 restart apache 这个 handler。handlers 是什么呢,handlers 跟 tasks 是一样的格式,其实 handler 本质上就是 task,不过它不会主动执行,而是等待被 task 里的 notify 触发再执行,我们这里定义了一个用 service 模块重启 httpd 的 handler。第三个 task 是要用 service 模块保证 httpd 是启动的状态,并且加入了开机启动。

关于 handlers 的执行时机还需要强调一点,handlers 被触发了以后并不一定立即执行,它需要在一个 Playbook 的所有 tasks 完成了以后再执行,而且即便被触发了多次,也只会执行一次而已。

这就是最基本的 Playbook 的写法了。总结一下,一个 Playbook 由一个或多个 play 组成,而一个 play 包括以下元素:

  • hosts,指定面向的机器
  • remote_user,指定执行任务的用户
  • tasks,一个 task 列表
  • handlers,一个 handler 列表

接下来就可以执行这个 Playbook,方式很简单:

$ ansible-playbook playbook.yml

如果过程中需要使用变成另一个用户(比如 root 或 postgre)来执行任务,那么可以在 play 里指明:

--- 
- hosts: webservers 
  remote_user: yourname   
  become: yes   
  become_user: postgres 
  become_method: sudo

或者在 task 级别指明:

--- 
- hosts: webservers   
  remote_user: yourname   
  tasks:     
	- service: name=nginx state=started       
	  become: yes       
	  become_user: root
	  become_method: su