1、Ansible的简介

   Ansible is a radically simple IT automation system. It handles configuration management, application deployment,
cloud provisioning,ad-hoc task execution, network automation, and multi-node orchestration. Ansible makes complex changes like zero-downtime rolling updates with load balancers easy.


  如同官网介绍所说,ansible是一个IT自动化系统,类似的产品还有Puppet、Chef、Saltstack等等。
详细的对比介绍可以参照这篇博文运维管理工具的对比 ,简单对比如下表:

2、Ansible的架构

Ansible是开源工具,整个开发过程或二次开发均遵循GPL协议,所以所有源码均可见:Github项目

架构图如下图所示,核心组件包括Inventory、Modules、Plugins、Playbook。其中Inventory存放主机清单,可以分组分级管理。Modules包括自带的和第三方模块。Plugins是对模块功能的补充。Playbook是任务配置的剧本,系统按照剧本中配置的任务执行。

ansible的工作执行过程如下图所示:

系统里安装了ansible的称为管理端、中心端、控制节点,可以有多个,但是不能使用windows作为管理端。

未安装的主机或设备称为被管理端、客户端、受控节点。在客户端上需要安装 Python 2.4 或以上的版本,如果版本低于 Python 2.5 ,需要额外安装一个模块:python-simplejson。 管理端支持local 、ssh、zeromq 三种方式连接被管理端,默认使用基于ssh的连接。

Ansible任务执行模式分为两种:

ad-hoc模式: 使用单个模块,支持批量执行单条命令,相当与在bash中执行一句shell命令

playbook模式: 通过多个task的集合完成一类功能,可以理解为多个ad-hoc的配置文件

可以通过命令可以查看到Ansible提供了一些基础命令,这些命令提供了对应的功能来支持运维工作。官方文档

1
2
3
4
5
6
7
8
9
10
11
12
[root@Ansible ~]# ls /usr/bin/ | grep ansible | grep -v [0-9]
ansible
ansible-config
ansible-connection
ansible-console
ansible-doc
ansible-galaxy
ansible-inventory
ansible-playbook
ansible-pull
ansible-test
ansible-vault

ansible

ansible主要用于临时性操作,执行ad-hoc命令,即单条命令。默认后面需要跟主机和选项部分,默认不指定模块时,使用的是command模块。

1
$ ansible [pattern] -m [module] -a "[module options]"

ansible-doc:

该指令功能和Linux的man命令类似,不加参数运行时显示模块详细信息,常用参数有两个-l 和 -s。

1
2
3
4
#列出所有已安装的模块
$ ansible-doc -l
#简介的显示模块的帮助信息
$ ansible-doc -s command

ansible-galaxy:

ansible-galaxy 指令用于方便的从https://galaxy.ansible.com/ 站点(类似于dockerhub)下载第三方扩展模块,可以自己搭建内部的Galaxy服务器。

1
$ ansible-galaxy collection install my_namespace.my_collection

ansible-config:

用于查看、编辑管理ansible的配置文件

1
$ ansible-config [-h] [--version] [-v] {list,dump,view} ...

ansible-playbook:

该指令是日常用的最多的命令,其通过读取playbook 文件后,执行相应的动作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
usage: ansible-playbook [-h] [--version] [-v] [-k]
[--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]
[-c CONNECTION] [-T TIMEOUT]
[--ssh-common-args SSH_COMMON_ARGS]
[--sftp-extra-args SFTP_EXTRA_ARGS]
[--scp-extra-args SCP_EXTRA_ARGS]
[--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers]
[--flush-cache] [-b] [--become-method BECOME_METHOD]
[--become-user BECOME_USER] [-K] [-t TAGS]
[--skip-tags SKIP_TAGS] [-C] [--syntax-check] [-D]
[-i INVENTORY] [--list-hosts] [-l SUBSET]
[-e EXTRA_VARS] [--vault-id VAULT_IDS]
[--ask-vault-password | --vault-password-file VAULT_PASSWORD_FILES]
[-f FORKS] [-M MODULE_PATH] [--list-tasks]
[--list-tags] [--step] [--start-at-task START_AT_TASK]
playbook [playbook ...]

ansible-pull

ansible默认使用的是push模式,这个和通常使用的push模式的工作机制正好相反。适用于,有数量巨大的机器需要配置;要在刚启动的,没有联网的主机上执行ansible。

ansible-console

基于dominis’ ansible-shell,属于ansible自己的终端,在可以对主机执行临时任务,用的不多。

ansible-inventory

查看被控制端主机清单的详细信息默认情况下它使用库存脚本,返回JSON格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@Ansible ~]# ansible-inventory --list
{
"_meta": {
"hostvars": {}
},
"all": {
"children": [
"testserver",
"ungrouped"
]
},
"testserver": {
"hosts": [
"10.10.0.149",
"10.10.0.109"
]
}
}

ansible-vault

主要用于配置文件的加密,如编写的playbook配置文件中包含敏感的信息,ansible-vault可加密/解密这个配置文件。这种playbook文件在执行时,需要加上 –ask-vault-pass参数,同样需要输入密码后才能正常执行。

3、Ansible的安装

在控制节点安装ansible的办法有三种:源码安装、yum/apt方式安装、通过pip安装,可以根据自己的需求选择。

本文介绍在CentOS 7.4 环境下,python版本2.7.5,使用YUM方式安装ansible 2.9.7版本。

RHEL或CentOS用户,需要 配置 EPEL

首先替换服务器yum源为163源:

1
2
3
4
5
6
cd /etc/yum.repos.d/
wget http://mirrors.163.com/.help/CentOS7-Base-163.repo
sed -i "s;\$releasever;7;g" CentOS7-Base-163.repo
mv CentOS-Base.repo CentOS-Base.repo.bk
yum clean all
yum makecache

然后安装epel源

1
yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

最后安装ansible

1
$ sudo yum install ansible

安装目录如下:
 配置文件目录:/etc/ansible/
 执行文件目录:/usr/bin/
 Lib库依赖目录:/usr/lib/pythonX.X/site-packages/ansible/
 Help文档目录:/usr/share/doc/ansible-X.X.X/
 Man文档目录:/usr/share/man/man1/
 
ansible 的配置文件为/etc/ansible/ansible.cfg,大部分配置节都是默认配置,需要关注的如下:

1
2
3
4
5
6
7
8
inventory = /etc/ansible/hosts		#资源清单inventory文件的位置
library = /usr/share/ansible #指向存放Ansible模块的目录,支持多个目录方式冒号隔开
forks = 5 #并发连接数,默认为5
sudo_user = root #设置默认执行命令的用户
remote_port = 22 #指定连接被管节点的管理端口,默认为22端口
host_key_checking = False #设置是否检查SSH主机的密钥
timeout = 60 #设置SSH连接的超时时间,单位为秒
log_path = /var/log/ansible.log #指定一个存储ansible日志的文件(默认不记录日志)

4、Ansible的使用

4.1 配置主机清单

配置主机清单,把受控节点添加到 inventory 文件里, 默认的文件路径为 /etc/ansible/hosts

主机可以按主机和组管理,且可以添加变量,官方例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Ex 1: Ungrouped hosts, specify before any group headers.

## green.example.com
## blue.example.com
## 192.168.100.1
## 192.168.100.10

# Ex 2: A collection of hosts belonging to the 'webservers' group

## [webservers]
## alpha.example.org
## beta.example.org
## 192.168.1.100
## 192.168.1.110

# If you have multiple hosts following a pattern you can specify
# them like this:

## www[001:006].example.com

# Ex 3: A collection of database servers in the 'dbservers' group

## [dbservers]
##
## db01.intranet.mydomain.net
## db02.intranet.mydomain.net
## 10.25.1.56
## 10.25.1.57

# Here's another example of host ranges, this time there are no
# leading 0s:

## db-[99:101]-node.example.com

组支持创建子成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[atlanta]
host1
host2

[raleigh]
host2
host3

[southeast:children]
atlanta
raleigh

[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2

[usa:children]
southeast
northeast
southwest
northwest

# 主机配置参数
some_host ansible_ssh_port=2222 ansible_ssh_user=manager

4.2 配置访问主机

Ansible默认是通过SSH key和被控主机进行通信,也支持SSH password进行通信。 需要将控制主机上的公钥放到被控主机的/root/.ssh/authorized_keys文件中。

配置免密登陆登陆被控主机,需要用到ssh-keygen和ssh-copy-id两个命令,可以通过yum安装。

在控制端生成SSH公钥:

1
2
3
4
5
6
[root@Ansible ~]# ssh-keygen

-t: 密钥类型,可以选择 dsa|ecdsa|ed25519|rsa; 默认是rsa
-f: 密钥目录位置,默认为当前用户home路径下的.ssh隐藏目录,~/.ssh/, root用户在/root/.ssh/id_rsa, 其他用户在/home/username/.ssh/id_rsa;
-C: 指定此密钥的备注信息, 需要配置多个免密登录时, 建议携带;
-N: 指定此密钥对的密码, 如果指定此参数, 则命令执行过程中就不会出现交互确认密码的信息

将公钥拷贝到被控端:

1
2
3
4
# 指定要拷贝的本地公钥、被控端主机的IP+用户名+端口号:
[root@Ansible ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub -p 22 root@被控端IP

# 公钥会被添加到被控机的authorized_keys文件中,因此也可以通过scp等方式拷贝公钥到被控主机后,将内容手动添加到该文件中。

之后就可以直接通过SSH免密登陆被控主机了。

4.3 playbook

  Playbooks 是 Ansible的配置、部署、编排语言,可以理解为一组执行计划或者命令合集,使用YAML语言编写。playbooks里的命令按从上到下的顺序依次执行,不同于单命令模式,它可以做到传递参数。比如从某一台主机读取内容赋给变量,再传递给下一台主机使用。
  在 play 之中,一组主机被映射为定义好的角色。在 ansible 中,play 的内容被称为 tasks,即任务。一个任务是一个对 ansible 模块的调用。一个任务执行完毕之后,下一个 task 才会执行。如果有一组主机中有一个执行任务失败,则会被剔除出该组。
  modules 具有”幂等”性:意思是如果再一次地执行 moudle,moudle 只会执行必要的改动,只会改变需要改变的地方,所以重复多次执行 playbook 也很安全。

playbook主要有以下四部分构成:

  • Target section: 用于定义将要执行playbook的远程主机组及远程主机组上的用户、连接方式
  • Variable section: 定义playbook运行时需要使用的变量
  • Task section: 定义将要在远程主机上执行的任务列表
  • Handler section: 定义task执行完成以后需要调用的任务

一个示例test.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
---
# Target section:
- hosts: webservers # 主机、一个或多个组的patterns
remote_user: root # 执行的用户
# Variable section:
vars:
http_port: 80
max_clients: 200
# Task section:
tasks:
- name: ensure apache is at the latest version # 任务名称备注
yum:
name: httpd
state: latest
- name: write the apache config file
template: # 使用template模块传递含参数的配置文件到被控主机
src: /srv/httpd.j2
dest: /etc/httpd.conf
notify: # 监视任务
- restart apache
- name: ensure apache is running
service:
name: httpd
state: started
# Handler section:
handlers:
- name: restart apache #必须和notify内容一致
service:
name: httpd
state: restarted

执行playbooks的命令是

1
[root@Ansible ~]# ansible-playbook test.yml

4.4 核心模块

模块(也被称为 “task plugins” 或 “library plugins”),是执行命令或任务时实际运行的功能。
可以使用ansible-doc命令来查询模块和模块信息,大部分模块都可以附带参数。

ansible 团队负责维护核心模块,源码托管在 Github 的 ansible-modules-core repo中。

command模块

命令模块,常用于ad-hoc模式,但是无法支持”<”,”>”,”|”,”;”,”&”等符号,只能运行于shell中的命令都不支持

常用参数 释义
chdir 在执行命令前,先进入到指定目录中
creates 判断指定文件是否存在,如果存在,不执行后面的操作
removes 判断指定文件是否存在,如果存在,执行后面的操作
free_form 必须要输入一个合理的命令

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- name: return motd to registered var
command: cat /etc/motd
register: mymotd

- name: Run command if /path/to/database does not exist (without 'args' keyword).
command: /usr/bin/make_database.sh db_user db_name creates=/path/to/database

# 'args' is a task keyword, passed at the same level as the module
- name: Run command if /path/to/database does not exist (with 'args' keyword).
command: /usr/bin/make_database.sh db_user db_name
args:
creates: /path/to/database

# 'cmd' is module parameter
- name: Run command if /path/to/database does not exist (with 'cmd' parameter).
command:
cmd: /usr/bin/make_database.sh db_user db_name
creates: /path/to/database