ansible 初探

January 6, 2017

Overview

主机配置管理三大翘楚 puppet,salt,ansible,名头都很大,”Puppet Enterprise - IT automation for cloud, security, and DevOps.”,”SaltStack automation for CloudOps, ITOps & DevOps at scale”,”Ansible is Simple IT Automation”,这类型的系统,最基本的功能是使配置物理机/虚拟机(例如装某些基础包,配置软件源等)自动化,在这之外,可以作为部署系统的基础(部署系统需要把 build 好的软件分发到目标机器里),不过目前部署的趋势是往容器方向走,主机只需要提供最基本的东西,例如安装 docker 等基础组件,其他配置都在容器内通过 Dockerfile 完成,服务的编排也由 docker swarm/kubernetes/mesos 等接管,这些配置管理工具的价值就降低了,这次看 ansible,是因为想看下宜信的开源 pass lain ,而 lain 用了它。

基本概念

配置管理需要指定需要应用某个配置的主机,主机的指定在 ansible 里是通过 inventory 文件,例如:

[webservers]
web3

[dbservers]
web2

实际的环境里,有很多 host 是需要应用相同的配置的(或大部分相同),例如数据库机器都需要装数据库,因此引入 host group 把 host 进行归类,例如上面代码片段的 webserversdbservers

有了主机,那么需要指定该主机需要的配置,于是有了 role,role 是和主机组对应的概念,表面一类主机的配置,例如 webservers 有个对应的 role 叫 web,包含 webservers 的配置。可以看到,role 只是把配置进行分组的方式,那么最基础的配置如何指定呢?最基础的配置通过 task 指定,例如:

---
# This playbook will install mysql and create db user and give permissions.

- name: Create Mysql configuration file
  template: src=my.cnf.j2 dest=/etc/my.cnf
  notify:
  - restart mysql

- name: Start Mysql Service
  service: name=mysqld state=started enabled=yes

- name: insert iptables rule
  lineinfile: dest=/etc/sysconfig/iptables state=present regexp=""
              insertafter="^:OUTPUT " line="-A INPUT -p tcp  --dport  -j  ACCEPT"
  notify: restart iptables

列表中的 task 按顺序执行,每个 task 通过指定模块来指定运行什么,例如第一个 task,指定了 template 模块,这个模块的作用是把模板 my.cnf.j2 的内容渲染好,然后拷贝到 /etc/my.cnf模块是构成 task 的最基础的东西。在配置管理中还有一个常见的需求,就是配置变更了,需要重启服务,这是通过 handlers 实现的,如上面列表中,notify 底下的就是 handlers,handler 由自己编写,一般也是运行某个模块,例如 restart mysql

- name: restart mysql
  service: name=mysqld state=restarted

说了这么多,那么要对一个数据中心的所有机器的配置进行管理,整个代码怎么组织呢,我们看下官方 examples 仓库里 lamp_simple 的例子:

➜  lamp_simple git:(master) tree .
.
├── LICENSE.md
├── README.md
├── group_vars
│   ├── all
│   └── dbservers
├── hosts
├── roles
│   ├── common
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   │       └── ntp.conf.j2
│   ├── db
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   │       └── my.cnf.j2
│   └── web
│       ├── handlers
│       │   └── main.yml
│       ├── tasks
│       │   ├── copy_code.yml
│       │   ├── install_httpd.yml
│       │   └── main.yml
│       └── templates
│           └── index.php.j2
└── site.yml

可以这样运行:

ansible-playbook -i hosts site.yml

这里,playbook 指的就是整个仓库,实现了 lamp 的配置。其中,hosts 配置了 host group,这些 host group 会在 site.yml 引用:

➜  lamp_simple git:(master) cat hosts
[webservers]
web3

[dbservers]
web2

site.yml 关联了 hosts 和 role,表明各主机的具体配置:

...
- name: apply common configuration to all nodes
  hosts: all
  remote_user: root

  roles:
    - common
...

role 即具体的配置,里面包含 tasks,handlers,templates。tasks 是配置主机所需要运行的 task,其中会引用 handlers 等其他目录的内容;handlers 即某个 task 完成后需要做的事情,例如重启服务;templates 里的文件一般是配置文件模板,例如 mysql 配置文件等。

group_vars 是主机特定的变量,可以在 roles 各文件里引用,用来针对不同的主机设定不同的变量。

那么 ansible-playbook 的整体运行过程就是先看 site.yml,决定哪些主机组运行哪些 role,对于每个主机组,查找 hosts 文件以得到主机列表,然后对于每一主机,运行 role。运行 role 时,找到 tasks/main.yml 文件,逐个运行其中的 task,在运行 task 过程中,会碰到一些变量,需要查找变量的值(例如在 group_vars 中查找),会碰到一些文件,需要查找这些文件(如在 templates 文件夹找),运行 task 时主要是运行 task 指定的模块,每个模块都有每个模块的功能,例如 command 模块是运行一个命令,yum 模块是安装一个包,运行完之后会把 task 运行的结果(例如 task 的标准输出)显示出来。这里 ansible 是通过 ssh 在远程主机运行 task 的。