一、概述

Ansible是2013年推出的通用自动化工具,可用于配置管理和流程管理。Ansible使用Python编写,它使用SSH在不同的机器上执行命令,Ansible是无代理的,使用声明式YAML编写Playbook。

(1)其他开源项目

  • Ansible Galaxy:用于查找、共享使用Ansible Role的在线社区
  • Ansible Container:实现了构建、部署、管理容器应用的全过程
  • Ansible Tower:商业项目,可视化仪表盘

(2)对管理主机的要求

  • 支持Python2和Python3

(3)对目标主机的要求

  • 使通常使用SSH通信,使用SFTP作为文件传输,通过修改ansible.cfg可以实现SCP文件传输
  • 支持Python2或者Python3版本

(4)与其他软件对比

Ansible Chef Puppet SaltStack
开发语言 Python Ruby、Erlang C++、Clojure Python2
配置文件 YAML、JSON Ruby Propfiletary YAML
数据库支持 不需要 PostgreSQL PuppetDB 不需要
传输方式 SSH RabbitMQ Mcollective ZeroMQ
发布方式 PUSH PULL PULL PUSH
管理节点 无限制 LINUX LINUX 无限制
是否需要代理
公有云版本 AM AM、AZ、PR
公有云管理支持 AM、AZ、OS、GCP Fog Driver AM、AZ、VM、GCP Salt Cloud
架构 Server C/S C/S C/S
逐步部署支持 支持 支持 不支持 不支持
开源版UI Semaphore Chef Manager Foreman Slatpad、SlatShaker
企业版UI Ansible Tower OpsCode Manager Puppet Enterprise SaltStack Enterprise
企业版本

Ansible适用于中小型环境,SaltStack执行效率高,Puppet适合大型环境。

(5)常见文件和命令

  • /etc/ansible/ansible.cfg配置文件
  • /etc/ansible/hosts主机清单
  • /etc/ansible/roles存放角色的目录
  • /usr/bin/ansible主程序
  • /usr/bin/ansible-doc查看配置文档的程序
  • /usr/bin/ansible-galaxyRole分享平台
  • /usr/bin/ansible-playbook定制自动化任务
  • /usr/bin/ansible-ansible-pull远程执行命令
  • /usr/bin/ansible-vault文件加密
  • /usr/bin/ansible-console基于Console界面与用户交互的工具

二、主机清单

(1)概述

主机清单的本质是个INI文件或者YAML文件,因此可以手动使用Python的INI模块configparser解析。但是YAML文件使用不方便所以忽略。

ini文件由section和键值对或者字符串组成,每个section对应多个键值对,类似于如下形式:

[section]
key=value
string

(2)定义主机

Ansible通过主机清单管理想要管理的主机。将主机组写在sectioon位置,Ansible支持各种形式的主机定义:

[nginx-servers]
hostname
hostname:port  # 指定连接端口
localhost ansible_connection=local  # 指定连接类型
hostname http_port=80 maxReuqestsPerChild=808  # 定义主机变量
hostname ansible_ssh_port=22 ansible_ssh_host=192.168.3.3 # 定义SSH参数
service[0:50].example.com  # 支持范围定义的方式
server[a-f].example.com

(3)执行环境

Ansible支持定义执行Playbook的时候所使用的的执行环境:

[mysql-servers]
database.example.com ansible_python_interpreter=/applications/python/bin/python3.8
192.168.3.5 ruby_module_host ansible_ruby_interpreter=/applications/ruby/bin/ruby

(4)定义变量

Ansible支持在Hosts文件中定义变量:

[nginx-servers:var]  # 使用:var表示定义在nginx-servers组内可以被共享的变量
ntp_server = 192.178.3.7
proxy = 127.0.0.1:1080

由于在Hosts文件中的变量存在覆盖情况,因此变量在覆盖的时候遵循以下优先级:

  1. all 最低
  2. 父组
  3. 子组
  4. 主机 最高

当然可以使用ansible_group_priority调整优先级,默认为1(数值越大优先级越高),相同的优先级后者优先。

(5)组合并

Ansible支持将组合并为一个新的组进行管理:

[web-services]
nginx-servers
mysql-servers

Ansible中有默认的组:

  • all:所有的主机
  • ungrouped:没有组的主机

三、Playbook

Playbook是由多个Play构成的,Play的主要功能在于将预定义的一组主机设置为通过Ansible中的Task描述后的角色。本质上,Task是调用Ansible的一个Module(目前Ansible自带1738个模块),将多个Play组织在一个Playbook中,就可以通过多个Play实现任务的编排。Playbook采用YAML编写,在YAML的基础上,支持Jinjia2模板引擎的解析。

通常情况下,一个YAML文件对应一个Playbook,但是也可以使用---进行分割。

一般会将Playbook文件存放到/etc/ansible/role目录。

(1)核心元素

  • hosts:执行Playbook的远程主机列表,支持逻辑操作符
  • tasks:任务集,由众多action组成,每个name对应一个action,用于描述action的意义
  • varniables:变量,在YAML文件中使用变量:{{var_name}},变量可以在:
    • Hosts文件或者Playbook中定义
    • 使用ansible setup fact获取
    • -e参数可以通过命令行传入参数
  • templates:模板,可以替换模板文件变量并且实现简单逻辑的文件,比如根据硬件信息自动修改配置,使用jinjia2语言
  • handlers:与notify结合使用,特定条件下触发的处理器,本质上handlers还是action,notify与hanlder通过name进行绑定
  • tags:标签,指定某条任务执行,用于选择运行Playbook中的部分代码,Ansible本身具有幂等性,自动跳过没有变化的部分。但是有些Task在测试是否执行过的时候时间很长,因此可以配合tag使用。多个action可以共用一个tag

执行Playbook的指令:

ansible-playbook yamlfile

--check参数可以检查Playbook脚本,-t tagname可以指定Tag执行,-k使用密码方式,默认是秘钥方式

在action中,大部分模块参数都是键值对形式,除了shell和command模块。

由于在执行任务的时候出错,如果希望继续执行那么可以在命令后边添加|| /bin/true或者在action中添加ignore_errors: True

- hosts: all
  remote_user: root

  vars:
  - filename: create-by-ansible

  tasks:
  - name: create new file in root home
    file: name=/root/{{filename}} state=touch
    notify:
    - restart postfix
    - check nginx status

  - name: create new user
    user: name=tmpuser system=yes shell=/sbin/nologin
    tags: create-new-user

  handlers:
  - name: restart postfix
    service: name=postfix state=restart

  - name: check nginx status
    shell: killall -0 nginx

(2)执行流程

(3)Role模块化

/etc/ansible的目录结构:

ansible.cfg       # Ansible的配置文件
hello-world.yml   # Playbook文件,与roles目录同级
hosts             # 配置的主机文件
roles             # 存放角色的目录
└── hello-world        # 一个角色
    ├── default        # 设定默认变量时使用此目录的main.yml文件
    │   └── main.yml
    ├── files          # 存放由copy和script模块等调用的文件
    ├── handlers       # 存放触发器对应的处理Action,通过include引入
    │   └── main.yml
    ├── meta           # 角色的特殊设定及其依赖关系,通过include引入
    │   └── main.yml
    ├── tasks          # 定义Task和Role的基本元素,通过include引入
    │   └── main.yml
    ├── templates      # 存放模板文件的目录
    └── vars           # 定义变量,通过include引入
    └── main.yml

tasks/main.yml中通过include的编写顺序定义各个task的执行顺序:

- include: create-user.yml
- include: copy-nginx-config.yml

在Playbook中使用Role,/etc/ansible/hello-world.yml

- hosts: services
  remote_user: root
  roles:
    - role: hello-world

*模板会自动搜索templates目录下的.j2文件**:

templates: nginx.conf.j2

变量的优先级是:-e指定的变量 > Playbook变量 > 主机清单变量

(4)角色包含

  • 静态包含

    • 使用import_tasks模块来包含task文件
    • 使用import_role模块来包含role
  • 变量包含

    • include_vars 在task中动态加载yaml或json文件类型中的变量
  • 动态包含

    循环引用3次
    - include_tasks: foo.yml param={{item}}
    with_items:
    - 1
    - 2
    - 3
    
    使用动态变量引入task文件
    - include_tasks: "{{inventory_hostname}}.yml"
    

(5)Facts

  • 采集目标系统的信息

    ansible hostname -m setup

    支持正则表达式过滤:

    ansible all -m setup -a 'filter=ansible_*_mb’
  • 自定义目标系统的facts

    在远程主机/etc/ansible/facts.d/目录下创建.fact结尾的文件,也可以是json、ini 或者返回json 格式数据的可执行文件,这些将被作为远程主机本地的facts 执行。

    # /etc/ansible/facts.d/helloworld.fact
    [helloworld]
    name = hello

    通过{{ ansible_local.preferences.helloworld.name }}方式来使用该变量

  • Facts支持缓存,/etc/ansible/ansible.cfg

    • 使用文件作为缓存
    fact_caching = jsonfile
    fact_caching_connection = /tmp/facts_cache
    • 使用Redis作为缓存
    gathering = smart
    fact_caching = redis
    fact_caching_timeout = 86400
    fact_caching_connection = localhost:6379:0:admin
    • 使用Memcached作为缓存
    gathering = smart
    fact_caching = memcached
    fact_caching_timeout = 86400
    fact_caching_connection = localhost:11211