1.介绍

Ansible自动化运维工具,是用来实现一台主机对多台主机进行操作的开源软件。
主要功能:

  • 批量对多台主机发送文件
  • 批量对多台主机运行命令
    特性:
    • 模块化
    • 基于Python语言实现,有Paramiko,PyYAML和Jinja2三个关键模块
    • 部署简单:agentless,可以不需要在需要操作的服务器上安装任何软件
    • 支持自定义模块
    • 支持Playbook,可以将任何配置写入Playbook,循环使用
    • 幂等性,命令不管执行多少次,结果是一样的
      Ansible配置系统结构图:
      结构图.jpg

      2.安装和配置说明

      Ansible的安装需要使用epel源进行安装,所以在安装之前需要配置epel源
      主要配置文件
      /etc/ansible/hosts :主机清单配置文件
      /etc/ansible/ansible.cnf:主配置文件
      /etc/ansible/roles:角色定义目录

相关命令介绍
1.帮助类相关命令

  • ansible-doc -l 查看当前支持的所有模块
  • ansible-doc -s 模块名 查看当前指定模块使用方法
  • ansible-doc -h 该命令使用方法

2.一次性执行命令相关

  • ansible host|all -m 模块 -a “模块参数” -f 一次连接多少个主机

3.ansible-playbook相关命令
测试相关

  • ansible-playbook --check 只检测可能会发生的改变,但不真正执行操作
  • ansible-playbook --list-hosts 列出运行任务的主机
  • ansible-playbook --list-tasks 列出要运行的任务列表
  • ansible-playbook --syntax-check 语法检查
  • ansible-playbook --list-tags 列出所有可用的标签
  • ansible-playbook --list-tasks 列出所有任务列表
    运行相关
  • ansible-playbook yml_file
  • ansible-playbook -t TAGS , --tags=TAGS 只运行指定标签的任务
  • ansible-playbook --skip-tigs=SKIP_TIGS 跳过指定标签的任务

    3.常用模块及实例

1.ping:测试与指定主机是否通讯正常
[root@ansible ~]# ansible ansible.test.com -m ping 
ansible.test.com | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

2.command:远程在指定主机执行命令,该模块是直接在内核级执行,所以没有bash的一些符号

相关参数:
chdir:指定运行命令目录
creates:创建文件或目录,若文件或目录存在,则不执行
removes:删除文件或目录,若文件或目录不存在时,则不执行
实例:
[root@ansible ~]# ansible ansible.test.com -m command -a "date"
ansible.test.com | SUCCESS | rc=0 >>
Tue Jun 12 03:23:01 EDT 2018

3.shell:远程在指定主机执行命令,该模块时基于bash运行,所以bash相关符号都支持
相关参数:
chdir:指定运行命令目录
creates:创建文件或目录,若文件或目录存在,则不执行
removes:删除文件或目录,若文件或目录不存在时,则不执行
实例:
[root@ansible ~]# ansible ansible.test.com -m shell -a "echo 123456 | passwd --stdin test1"
ansible.test.com | SUCCESS | rc=0 >>
Changing password for user test1.
passwd: all authentication tokens updated successfully.

4.group:远程在指定主机创建或删除组
相关参数:
gid:指定组的GID
name:指定组名
state:指定删除还是创建,present | absent
system:指定对应组是否为系统组
实例:
[root@ansible ~]# ansible ansible.test.com -m group -a "name=ansible state=present gid=2000"
ansible.test.com | SUCCESS => {
    "changed": true, 
    "gid": 2000, 
    "name": "ansible", 
    "state": "present", 
    "system": false
}
[root@ansible ~]# ansible ansible.test.com -m group -a "name=ansible state=absent gid=2000"
ansible.test.com | SUCCESS => {
    "changed": true, 
    "name": "ansible", 
    "state": "absent"
}

5.user:在指定主机创建或删除用户
相关参数:
name:指定用户名
group:指定主组
uid:指定用户的uid
goups:指定附加组
home:指定家目录
password:指定用户密码
state:指定状态,若和状态不想同则作出操作 present | absent
system:设定用户为系统用户
shell:设定登入shell
实例:
[root@ansible ~]# ansible ansible.test.com -m user -a "name=ansible uid=2000 password=123456 shell=/bin/sh"
ansible.test.com | SUCCESS => {
    "changed": true, 
    "comment": "", 
    "createhome": true, 
    "group": 2000, 
    "home": "/home/ansible", 
    "name": "ansible", 
    "password": "NOT_LOGGING_PASSWORD", 
    "shell": "/bin/sh", 
    "state": "present", 
    "system": false, 
    "uid": 2000
}
[root@ansible ~]# ansible ansible.test.com -m user -a "name=ansible state=absent"
ansible.test.com | SUCCESS => {
    "changed": true, 
    "force": false, 
    "name": "ansible", 
    "remove": false, 
    "state": "absent"
}

6.copy:从本地复制文件至指定服务器
相关配置:
src:本地文件路径
dest:远程服务器目录
owner:指定文件所有者
group:指定文件所属组
mode:指定文件权限
content:将指定内容复制至指定服务器
实例:
[root@ansible ~]# ansible ansible.test.com -m copy -a "src=issue dest=/tmp owner=memcached group=root mode=0444"
ansible.test.com | SUCCESS => {
    "changed": true, 
    "checksum": "5c76e3b565c91e21bee303f15c728c71e6b39540", 
    "dest": "/tmp/issue", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "f078fe086dfc22f64b5dca2e1b95de2c", 
    "mode": "0444", 
    "owner": "memcached", 
    "size": 23, 
    "src": "/root/.ansible/tmp/ansible-tmp-1528789534.05-118540157876873/source", 
    "state": "file", 
    "uid": 995
}

7.fetch:从远程服务器复制文件至本地,为了可以存多个服务器相同文件名,是创建一个以主机名为目录将复制文件放入目录中实现
相关配置:
src:远程地址
dest:本地地址
实例:
[root@ansible ~]# ansible ansible.test.com -m fetch -a "src=/etc/passwd dest=/tmp"
ansible.test.com | SUCCESS => {
    "changed": true, 
    "checksum": "49ed3c6ed3359b339b94c0b4b69d596974de5ff2", 
    "dest": "/tmp/ansible.test.com/etc/passwd", 
    "md5sum": "256651c73ef0e89bc7cd5cffe786f27e", 
    "remote_checksum": "49ed3c6ed3359b339b94c0b4b69d596974de5ff2", 
    "remote_md5sum": null
}

8.file:对远程文件或目录进行操作
相关配置:
path:指定远程操作文件
state:指定path文件的类型,可以是dreectory、link、hard、file、touch,也可以是present或absent
src:本地路径,用于在指定连接文件时使用
owner:指定文件属主
group:指定文件属组
mode:指定文件权限
实例:
[root@ansible ~]# ansible ansible.test.com -m file -a "path=/tmp/file state=directory"
ansible.test.com | SUCCESS => {
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0755", 
    "owner": "root", 
    "path": "/tmp/file", 
    "size": 6, 
    "state": "directory", 
    "uid": 0
}

9.get_url:批量下载
相关配置:
url:指定url路径
owner:指定文件属主
group:指定文件属组
mode:指定文件权限
dest:指定目标路径,必须是一个目录
实例:
[root@ansible ~]# ansible ansible.test.com -m get_url -a "url=https://mirrors.aliyun.com/gentoo-portage/app-accessibility/SphinxTrain/SphinxTrain-1.0.8.ebuild dest=/tmp"
ansible.test.com | SUCCESS => {
    "changed": true, 
    "checksum_dest": null, 
    "checksum_src": "b1a87e9c2e46841866387b11805d2cdf3d240577", 
    "dest": "/tmp/SphinxTrain-1.0.8.ebuild", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "a52bed11534400b1901760bc1bcc9dd9", 
    "mode": "0644", 
    "msg": "OK (912 bytes)", 
    "owner": "root", 
    "size": 912, 
    "src": "/tmp/tmpNHTpAE", 
    "state": "file", 
    "uid": 0, 
    "url": "https://mirrors.aliyun.com/gentoo-portage/app-accessibility/SphinxTrain/SphinxTrain-1.0.8.ebuild"
}

10.git:用于下载git代码仓库命令,该命令需要安装git软件包才可以下载
相关配置:
repo:指定仓库地址
dest:指定目标路径
version:指定版本号,默认最新版本号

11.cron:为指定主机定义计划任务
相关配置:
minute:定义分钟
day:定义天
month:定义月
weekday:定义周
hour:定义时
job:定义命令
name:计划任务名
state:present:创建  |  absent:删除
实例:
[root@ansible ~]# ansible ansible.test.com -m cron -a "name=mycron minute=*/5 job=date"
ansible.test.com | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "jobs": [
        "mycron"
    ]
}

12.yum:软件包的安装,默认输出格式不对,这里是整理过的格式
相关配置:
name:程序包名,可以带版本号,若不指定,默认安装最新版
state:设置安装,卸载 installed | removed
enablerepo:启用某仓库
diablerepo:禁用某仓库
实例:
[root@ansible ~]# ansible ansible.test.com -m yum -a "name=tree state=installed"
ansible.test.com | SUCCESS => {
    "changed": true, 
    "msg": "", 
    "rc": 0, 
    "results": [
    ]
}

13.service:服务相关
相关配置:
name:指定服务名称
state:指定服务状态,可以是started、restarted、reloaded、stoped
enabled:是否开机自启 true
runlevel:定义级别CentOS7版本不需要指定
实例:
[root@ansible ~]# ansible ansible.test.com -m service -a "name=memcached state=started"
ansible.lin.com | SUCCESS => {
·······这里显示的都是一些该服务的环境参数
}
    "warnings": []
}

14.hostname:设置远程主机的主机名,一般不适用
15.pip:用于安装python模块
16.npm:用于安装JS模块
17.setup:显示当前系统中所有的变量,可以在配置文件中直接调用
显示:
ansible.test.com | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.1.161", 
            "192.168.1.111", 
            "192.168.1.112"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::880b:c17f:5022:67c3", 
            "fe80::acd6:5a07:96b5:c5d4", 
            "fe80::805f:d6bd:3a96:c3dc"
        ], 
        "ansible_architecture": "x86_64", 
        "ansible_bios_date": "07/02/2015", 
        "ansible_bios_version": "6.00", 
        "ansible_cmdline": {
            "BOOT_IMAGE": "/vmlinuz-3.10.0-693.el7.x86_64", 
            "LANG": "en_US.UTF-8", 
            "crashkernel": "auto", 
            "quiet": true, 
            "rd.lvm.lv": "centos/swap", 
            "rhgb": true, 
            "ro": true, 
            "root": "/dev/mapper/centos-root"
        }, 
        "ansible_date_time": {
            "date": "2018-06-12", 
            "day": "12", 
            "epoch": "1528792866", 
            "hour": "04", 
            "iso8601": "2018-06-12T08:41:06Z", 
            "iso8601_basic": "20180612T044106138105", 
            "iso8601_basic_short": "20180612T044106", 
            "iso8601_micro": "2018-06-12T08:41:06.138178Z", 
18.template:用于复制模板配置文件,模板配置文件必须为 .j2格式
相关配置:
src:源文件
dest:目标路径
owner:属主
group:数组
mode:权限
Jinja2:
  字面量:
        字符串:使用单引号或双引号;
        数字:整数,浮点数;
        列表:[item1, item2, ...]
        组:(item1, item2, ...)
        字典:{key1:value1, key2:value2, ...}
        布尔型:true/false
         算术运算:
            +, -, *, /, //, %, **
         比较操作:
            ==, !=, >, >=, <, <=
         逻辑运算:
            and, or, not 

4.Playbook:将需要在远程服务器上执行的命令写入配置文件中,调用配置文件即可执行

YAML

YAML:YAML(/ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达数据序列的格式。YAML参考了其他多种语言,包括:C语言、Python、Perl,并从XML、电子邮件的数据格式(RFC 2822)中获得灵感。Clark Evans在2001年首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。目前已经有数种编程语言或脚本语言支持(或者说解析)这种语言。
        YAML是"YAML Ain't a Markup Language"(YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言),但为了强调这种语言以数据做为中心,而不是以标记语言为重点,而用反向缩略语重命名。
        YAML的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印除错内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。

Playbook的核心元素

* Hosts:主机
* Tasks:任务列表 
* Varoables:变量
* Templates:包含了模板语法文本文件
* Handlers:特定条件触发的任务
* Roles:角色,将重复需要执行的命令写成一个单独的功能模块,当需要使用时,直接使用即可,类似于函数

Playbook的基本组件

- hosts: 运行指定主机
  remote_user: 远程主机执行任务所用的身份,一般为root
  tasks: 任务列表
       选项: 模块 参数
        模块: 参数
   handlers:特定模式下执行,需要在上述指定notify,在notify后面指定字符串,在下面至指定触发即可
   -name:

实例:

[root@ansible ansible]#  vim httpd.yml
- hosts: ansible.test.com
  remote_user: root
  tasks:
  - name: install httpd package
    yum: name=httpd state=installed
  - name: start httpd servier
    service: name=httpd state=started

[root@ansible ansible]# ansible-playbook httpd.yml 

PLAY [ansible.test.com] *********************************************************

TASK [setup] *******************************************************************
ok: [ansible.test.com]

TASK [install httpd package] ***************************************************
changed: [ansible.test.com]

TASK [start httpd servier] *****************************************************
changed: [ansible.test.com]

PLAY RECAP *********************************************************************
ansible.test.com            : ok=3    changed=2    unreachable=0    failed=0   

variables:传递参数


 1.facts:可以直接调用,使用setup查看
 2.用户自定义变量
       * ansible-playbook -e 变量
       * -var1: value1
3.通过reles传递变量
4.在/etc/ansible/hosts文件中定义主机或是可以直接定义 
   ip var=value1
   [groupname::vars]
    varname=valus

条件测试:
when语句,在task中使用,当满足条件式才会执行

tasks: 
    - name: install conf file to centos7
      template: src=files/nginx.conf.c7.j2
      when: ansible_distribution_major_version == "7"
    - name: install conf file to centos6
      template: src=files/nginx.conf.c6.j2
      when: ansible_distribution_major_version == "6"

循环,迭代,能够将重复任务循环完成
对迭代项引用,固定变量名为"item",而后给定列表

  • 列表的方法有字符串和字典
- name: install some packages
  yum: name={{ item }} state=present
  with_items:
  - nginx
  - memcached
  - php-fpm
- name: install some packages
  yum: name={{ item }} state=present
  with_items:
  - { name: 'nginx', group: 'nginx' }
   - { name: 'nginx', group: 'nginx' }
   - { name: 'nginx', group: 'nginx' }

roles角色的定义:
角色目录结构
nginx/:指定角色名称,当需要调用时,也是根据该名称调用,在一下目录下的每一个目录,若需要使用,至少应该拥有一个main.yml文件,若需要扩展,则可以使用include进行扩展

  • files/:存放有copy或script模块等调用的文件
  • templates/:存放模板查看锁需要的目录,文件后缀为.j2
  • tasks/:任务列表目录,存放要执行的任务
  • handlers/:来用存放满足条件才会执行的任务列表
  • vars/:变量目录
  • meta/:定义当前角色的特殊设定及其依赖关系
  • default/:设定默认变量是使用该目录

    5.实践

    利用roles实现模块化nginx

1.创建目录结构
[root@ansible ansible]# tree /etc/ansible/roles/nginx/
/etc/ansible/roles/nginx/
├── default
├── files
│   ├── proxy.html
│   └── web.html
├── handlers
│   └── main.yml
├── meta
├── tasks
│   └── main.yml
├── templates
│   ├── nginx.conf.j2
│   └── proxy.conf.j2
└── vars
    └── main.yml
2.创建 tasks目录下main.yml
[root@ansible nginx]# cat tasks/main.yml 
- name: install nginx package
  yum: name=nginx state=installed
- name: create conf.d directory
  file: path=/etc/nginx/conf.d state=directory
- name: install web conf file
  template: src=templates/nginx.conf.j2 dest={{ nginx }}/nginx.conf
  when: servertype == 'web'
  notify: 'restart nginx server'
- name: install proxy conf file
  template: src=templates/proxy.conf.j2 dest={{ nginx }}/nginx.conf
  notify: 'restart nginx server'
  when: servertype == 'proxy'
- name: create web index
  file: path={{ webpath }}  state=directory
  when: servertype == 'web'
- name: create proxy index
  file: path={{ proxypath }}  state=directory
  when: servertype == 'proxy'
- name: copy web index file
  copy: src=files/web.html dest={{ webpath }}/index.html
  when: servertype == 'web'
- name: copy proxy index file
  copy: src=files/proxy.html dest={{ proxypath }}/index.html
  when: servertype == 'proxy'
- name: start nginx service
  service: name=nginx state=started enabled=true
3.创建对应的变量vars/main.yml
[root@ansible nginx]# cat vars/main.yml 
nginx: /etc/nginx/conf.d/
servertype: web
webpath: /app/web/
proxypath: /app/proxy/
4.创建handles目录下main.yml
[root@ansible nginx]# cat handlers/main.yml 
- name: restart nginx server
  service: name=nginx state=restarted
5.配置模板文件templates
[root@ansible nginx]# cat templates/proxy.conf.j2 
unstream tomser {
    server tomcat1.lin.com:8080;
    server tomcat2.lin.com:8080;
}
server {
    listen 80;
    server_name {{ ansible_fqdn }};
    index index.html;
    root {{ proxypath }};
    location / {
        proxy_pass http://tomser/;
    }
}
[root@ansible nginx]# cat templates/nginx.conf.j2 
server {
    listen 80;
    server_name {{ ansible_nodename }};
    root {{ webpath }};
    index index.jsp index.html;
    location / {
        proxy_pass http://{{ ansible_fqdn  }}:8080;
    }
}
6.创建对应的测试主页
[root@ansible nginx]# cat files/
proxy.html  web.html    
[root@ansible nginx]# cat files/*
<h1>proxy</h2>
<h1>test</h1>
7.根据参数来选择安装的类型
[root@ansible ansible]# ansible-playbook nginx.yml
或
[root@ansible ansible]# ansible-playbook -e server=proxy nginx.yml