第10章:深入浅出Ansible

1.Ansible介绍

1).Ansible的优点

    Ansible是一个简单的自动化引擎,可完成配置管理、引用部署、服务编排以及其他各种IT需求

    Ansible是Python开发并实现的开源软件,其依赖Jinja2,paramiko和PyYAML这几个Python库

    安装部署简单

    基于SSH进行配置管理

    Ansible不需要守护进程

    日志集中存储

    Ansible简单易用

    Ansible功能强大

    Ansible设计优秀

    Ansible对云计算和大数据平台都有很好的支持

2).Ansible与Fabric之间比较

    Fabric像是一个工具箱,提供了很多好用的工具用于在远程服务器执行命令

    Ansible提供了一套简单的流程,只需要按照它的流程来做就能轻松完成任务

    Fabric是库,Ansible是框架

    Fabric简单,Ansible复杂

    Fabric通过SSH执行简单的命令,Ansible将模块拷贝到远程服务器后执行,执行完以后删除模块

    Fabric需要Python编程背景,Ansible不需要

    Fabric需要写代码,Ansible只需要编写YAML格式的配置文件来描述要做的事情

    Fabric提供了基本的接口,业务逻辑需要用户自己实现,Ansible提供了大量模块,用户只需要学习模块的用法即可

3).Ansible与SaltStack之间比较

    Ansible安装部署简单,SaltStack需要安装客户端接收服务端发过来的命令

    SaltStack相应速度更快,Ansible使用标准SSH连接,而SaltStack使用ZeroMQ进行通信和传输

    Ansible更安全,Ansible使用标准SSH连接传输数据,不需要在远程主机上启动守护进程

    SaltStack对Windows支持比较友好

    Ansible自身运维比较简单,SaltStack需要在Master和Minion主机启动一个守护进程

2.Ansible使用入门

1).安装Ansible

    pip install ansible

2).Ansible的架构

    Ansible的编排引擎由Inventory、API、Modules(模块)和Plugins组成

    工程师将需要在远程服务器执行的操作写在Ansible Playbook中,然后使用Ansible执行Playbook中的操作

3).Ansible的运行环境

Ansible会默认读取/etc/ansible/hosts文件中配置的远程服务器列表
# mkdir /etc/ansible
# cat /etc/ansible/hosts 
[test]
192.168.1.101
192.168.1.102
192.168.1.103

# ansible test -m ping
192.168.1.101 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
192.168.1.102 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
192.168.1.103 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

4).Ansible的ad-hoc模式

Ansible的ad-hoc模式,通过ansible命令执行操作的方式,称为ad-hoc
# ansible test -m command -a "hostname"

# ansible test -m command -a "whoami"

将本地文件拷贝到服务器中:
# ansible test -m copy -a "src=/etc/ansible/hosts dest=/tmp/hosts"

修改文件的所有者和权限:
# ansible all -m file -a "dest=/tmp/hosts mode=500 owner=mysql group=mysql" -become
-become参数类似于Linux命令下的sudo

在远程服务器中安装软件:
# ansible test -m yum -a "name=git state=present" -become

5).使用playbook控制服务器

在实际的生产环境中,我们一般将远程服务器需要做的事情写在一个YAML配置文件中
YAML文件称为Ansible Playbook

# cat test_playbook.yaml
---
- hosts : test
  become : yes
  become_method : sudo
  tasks : 
  - name : copy file
    copy : src=/etc/ansible/hosts dest=/tmp/data.txt

  - name : change mode
    file : dest=/tmp/data.txt mode=500 owner=mysql group=mysql

  - name : ensure packages installed
    yum : pkg="{{ item }}" state=present
    with_items : 
    - git

# ansible-playbook test_playbook.yaml

3.Inventory管理

1).hosts文件位置

在Ansible中,将可管理的服务器集合称为Inventory
Inventory管理便是服务器管理
默认读取/etc/ansible/hosts文件
通过命令行参数的-i指定hosts文件
通过ansible.cfg文件中的inventory选项指定hosts文件

2).动态Inventory获取

# cat hosts.py 
import argparse
import json
from collections import defaultdict
from contextlib import contextmanager
import pymysql

def to_json(in_dict):
    return json.dumps(in_dict, sort_keys=True, indent=2)

@contextmanager
def get_conn(**kwargs):
    conn = pymysql.connect(**kwargs)
    try:
        yield conn
    finally:
        conn.close()

def parse_args():
    parser = argparse.ArgumentParser(description='OpenStack Inventory Module')
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('--list', action='store_true', help='List active servers')
    group.add_argument('--host', help='List details about the specific host')
    return parser.parse_args()

def list_all_hosts(conn):
    hosts = defaultdict(list)
    with conn as cur:
        cur.execute('select * from hosts')
        rows = cur.fetchall()
        for row in rows:
            no, host, group, user, port = row
            hosts[group].append(host)
    return hosts

def get_host_detail(conn, host):
    details = {}
    with conn as cur:
        cur.execute("select * from hosts where host='{0}'".format(host))
        rows = cur.fetchall()
        if rows:
            no, host, group, user, port = rows[0]
            details.update(ansible_user=user, ansible_port=port)
    return details

def main():
    parser = parse_args()
    with get_conn(host='127.0.0.1', user='root', passwd='msds007', db='test') as conn:
        if parser.list:
            hosts = list_all_hosts(conn)
            print(to_json(hosts))
        else:
            details = get_host_detail(conn, parser.host)
            print(to_json(details))

if __name__ == '__main__':
    main()

4.YAML语法

1).语法规则

YAML文件的第一行为"---",表示是一个YAML文件
YAML中的字段大小写敏感
YAML与Python一样,使用缩进表示层级关系
YAML的缩进不允许使用Tab键,只允许使用空格,且空格的数目不重要,只要相同层次的元素左对齐即可
:冒号前后要有空格
#表示注释,从这个字符一直到行尾都会被解析器忽略

2).支持的数据格式

对象:键值对的集合,又称为映射,类似于Python中的字典
数组:一组按次序排列的值,又称为序列(sequence),类似于Python中的列表
纯量:单个的、不可再分的值,如字符串、布尔值于数字

3).解析

pip install PyYAML

使用PyYAML库解析YAML文件非常简单
import yaml
with open('data.yaml') as f:
    print(yaml.load(f))

# cat data.yaml 
---
name : Example Developer
job : Developer
skill : Elite
employed : True
foods:
    - Apple
    - Orange
    - Strawberry
    - Mango
languages:
    ruby : Elite
    python : Elite
    dotnet : Lame

5.Ansible模块

1).Ansible的模块工作原理

1)将模块拷贝到远程服务器
2)执行模块定义的操作,完成对服务器的修改
3)在远程服务器中删除模块

2).常用的Ansible模块

1.ping
2.远程命令模块command
3.file
4.copy
5.user/group
6.yum
7.get_url
8.unarchive
9.git

3).模块的返回值

changed
failed

6.Playbook

1).Playbook的定义

    在Ansible中,将各个模块组合起来的文件是一个YAML格式的配置文件,这个配置文件,在Ansible中称为Playbook

    Ansible中的Playbook类似于Linux下的Shell脚本文件

2).使用ansible-playbook

# cat test_playbook.yaml
---
- hosts : test
  become : yes
  become_method : sudo
  tasks : 
  - name : copy file
    copy : src=/py/data.txt dest=/tmp/data.txt

  - name : change mode
    file : dest=/tmp/data.txt mode=500 owner=mysql group=mysql

  - name : ensure packages installed
    yum : pkg="{{ item }}" state=present
    with_items : 
    - git

# ansible-playbook test_playbook.yaml

3).Playbook的详细语法

1.权限
在Ansible中,默认使用当前用户连接远程服务器执行操作,我们可以在ansible.cfg文件中配置连接远程服务器的默认用户
2.通知
3.变量
4.Facts变量
Facts变量是Ansible执行远程部署之前从远程服务器中获取的系统信息,包括服务器的名称、IP地址、操作系统、分区信息、硬件信息等
Facts变量可以配合Playbook实现更加个性化的功能需求
访问复杂变量的Playbook:
---
- hosts : test
  gather_facts : yes
  tasks : 
  - shell : echo {{ ansible_eth0 ["ipv4"] ["address"] }}
    register : myecho

  - debug : var=myecho.stdout_lines

  - shell : echo {{ ansible_eth0.ipv4.address }}
    register : myecho

  - debug : var=myecho.stdout_lines
5.循环
# cat test_playbook.yaml 
---
- hosts : test
  become : yes
  become_method : sudo
  tasks : 
  - name : Installed MySQL Package
    yum : pkg="{{ item }}" state=installed
    with_items : 
    - mysql-server
    - MySQL-python
    - libselinux-python
    - libsemanage-python
# ansible-playbook test_playbook.yaml
6.条件
在Playbook中可以通过when选项执行条件语句,when类似于if语句
7.任务执行策略

4).使用Playbook部署ngix

# cat deploy_nginx.yaml 
---
- hosts: test
  become: yes
  become_method: sudo
  vars:
    worker_processes: 4
    worker_connections: 768
    max_open_files: 65506
  tasks:
    - name: install nginx
      yum: name=nginx update_cache=yes state=present

    - name: copy nginx config file
      template: src=/py/nginx.conf.j2 dest=/etc/nginx/nginx.conf

    - name: copy index.html
      template:
        src: /py/index.html.j2
        dest: /usr/share/nginx/html/index.html
        mode: 0644
      notify: restart nginx

  handlers:
    - name: restart nginx
      service: name=nginx state=restarted

# ansible-playbook depoly_nginx.yml

5).使用Playbook部署MongoDB

# cat mongo.yml 
---
- hosts: test
  become: yes
  become_method: sudo
  vars:
    mongodb_datadir_prefix: /data
    mongod_port: 27018

  tasks:
    - name: Create the mongodb user
      user: name=mongodb comment="MongoDB"

    - name: Create the data directory for the namenode metadata
      file: path={{ mongodb_datadir_prefix }} owner=mongodb group=mongodb state=directory

    - name: Install the mongodb package
      yum: name={{ item }} state=installed
      with_items:
        - mongodb-server
        - mongodb

    - name: create data directory for mongodb
      file:
        path: "{{ mongodb_datadir_prefix }}/mongo-{{ ansible_hostname }}"
        state: directory
        owner: mongodb
        group: mongodb

    - name: create log directory for mongodb
      file: path=/var/log/mongo state=directory owner=mongodb group=mongodb

    - name: Create the mongodb startup file
      template: src=mongod.j2 dest=/etc/init.d/mongod-{{ ansible_hostname }} mode=0655

    - name: Create the mongodb configuration file
      template: src=mongod.conf.j2 dest=/etc/mongod-{{ ansible_hostname }}.conf

    - name: Copy the keyfile for authentication
      copy: src=secret dest={{ mongodb_datadir_prefix }}/secret owner=mongodb group=mongodb mode=0400

    - name: Start the mongodb service
      command: creates=/var/lock/subsys/mongod-{{ ansible_hostname }} /etc/init.d/mongod-{{ ansible_hostname }} start

# ansible-playbook mongo.yml

7.role的定义与使用

    role并不是某一个具体的东西,而是一个规范与抽象,是一种将复杂的Playbook分割成多个文件的机制

    Ansible从复杂的Playbook中抽象出了role的概念,并在Playbook提供了roles选项来使用role,在命令行提供了ansible-galaxy命令来创建、删除和查看role

    所谓role,只是一种规范的文件组织方式。每个Ansible的role都会有一个名字,比如mongodb,与mongodb role相关的文件都存放在/etc/ansible/roles/mongodb目录下

8.Ansible的配置文件

1).配置文件的查找路径

配置文件的查找路径
Ansible命令行工具使用的配置文件是/etc/ansible/ansible.cfg文件
一般将所有的role、Playbook、Inventory文件、ansible.cfg文件保存在一个版本控制的库中

在Ansible中,可以有多种方式使用ansible.cfg文件。Ansible查找ansible.cfg文件的顺序如下:
1)ANSIBLE_CONFIG环境变量指定的配置文件
2)当前目录下的ansible.cfg文件
3)当前用户home目录下的.ansible.cfg文件
4)Ansible默认的/etc/ansible/ansible.cfg文件

2).Ansible中的常用配置

1.默认配置
inventory
remote_user
remote_port
private_key_file
roles_path
log_path
host_key_checking
forks
gathering
2.ssh连接配置
ssh_args
pipelining
control_path
3.权限提升配置
become
become_method
become_user
become_ask_pass
原文地址:https://www.cnblogs.com/allenhu320/p/11354121.html