自动化运维工具---ansible

Ansible简介

Ansible 是什么?

Ansible 简单的说是一个配置管理系统(configuration management system)。你只需要可以使用 ssh 访问你的服务器或设备就行。它也不同于其他工具,因为它使用推送的方式,而不是像 puppet 等 那样使用拉取安装agent的方式。你可以将代码部署到任意数量的服务器上!

Ansible能做什么?

ansible可以帮助我们完成一些批量任务,或者完成一些需要经常重复的工作,这些场景中我们都可以使用到ansible。

  • 同时在100台服务器上安装nginx服务,并在安装后启动它们
  • 将某个文件一次性拷贝到100台服务器上。
  • 每当有新服务器加入工作环境时,你都要为新服务器部署某个服务,也就是说你需要经常重复的完成相同的工作。

Ansible特性

  • 模块化:调用特定的模块,完成特定的任务。
  • 有Paramiko, PyYAMl, Jinja2(模板语言) 三个关键模块
  • 支持自定义模块
  • 基于Python语言实现
  • 部署简单,基于python和SSH(默认已安装), agentless
  • 安全,基于OpenSSH
  • 支持playbook任务编排
  • 幂等性:一次任务执行一遍和执行n遍效果一样,不会重复执行带来意外情况
  • 无需代理不依赖PKI(无需ssl)
  • 可使用任何编程语言写模块
  • YAML格式,编排任务,丰富的数据结构
  • 较强大的多层解决方案

Ansible架构

ansible

Ansible主要组成部分功能说明

  • PLAYBOOKS:任务剧本(任务集),编排定义Ansible任务集的配置文件,由Ansible顺序依次执行,通常是JSON格式的YAML文件。
  • INVENTORY: Ansible管理主机的清单/etc/anaible/hosts。
  • MODULES: Ansible执行命令的功能模块,多数为内置的核心模块,也可自定义,ansible-doc –l 可查看模块。
  • PLUGINS: 模块功能的补充,如连接类型插件、循环插件、变量插件、过滤插件等,该功能不常用。
  • API:供第三方程序调用的应用程序编程接口。
  • ANSIBLE:组合INVENTORY、 API、 MODULES、PLUGINS的绿框,可以理解为是ansible命令工具,其为核心执行工具。

注意事项 :

1
2
3
4
5
-  执行ansible的主机一般称为主控端,中控,master或堡垒机
- 主控端Python版本需要2.6或以上
- 被控端Python版本小于2.4需要安装python-simplejson
- 被控端如开启SELinux需要安装libselinux-python
-  windows不能做为主控端

安装与配置Ansible

安装Ansible

安装方法有很多 , 这里仅仅以Centos yum安装为例 , Ansible默认不在标准仓库中,需要用到EPEL源。

1
2
3
4
5
6
7
8
9
[root@test-master01 ~]# yum install -y epel-release
[root@test-master01 ~]# yum -y install ansible
[root@test-master01 ~]# ansible --version
ansible 2.5.3
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr 11 2018, 07:36:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]

免秘钥登录

1
2
3
[root@test-master01 ~]# ssh-keygen
[root@test-master01 ~]# ssh-copy-id test-node01
[root@test-master01 ~]# ssh-copy-id test-node02

Ansible 配置文件

Ansible 配置文件/etc/ansible/ansible.cfg (一般保持默认)

1
2
3
4
5
6
7
8
9
10
11
12
 [defaults]
 #inventory = /etc/ansible/hosts # 主机列表配置文件
 #library = /usr/share/my_modules/ # 库文件存放目录
 #remote_tmp = $HOME/.ansible/tmp #临时py命令文件存放在远程主机目录
 #local_tmp = $HOME/.ansible/tmp # 本机的临时命令执行目录
 #forks = 5 # 默认并发数
 #sudo_user = root # 默认sudo 用户
 #ask_sudo_pass = True #每次执行ansible命令是否询问ssh密码
 #ask_pass = True      #连接时提示输入ssh密码
 #remote_port = 22     #远程主机的默认端口,生产中这个端口应该会不同
 #log_path = /var/log/ansible.log #日志
 #host_key_checking = False # 检查对应服务器的host_key,建议取消注释。也就是不会弹出

ansible配置文件

Inventory 主机清单

Ansible必须通过Inventory 来管理主机。Ansible 可同时操作属于一个组的多台主机,组和主机之间的关系通过 inventory 文件配置。

语法格式:

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
# 1.单台主机
test-master01 或者 192.168.72.2


# 2. 定义组
[node]
test-node01
test-node02

[db]
test-node02      # 一台主机可以是不同的组


# 3. 组内嵌套
[group1:children]     #  组嵌套组,group1为自定义的组名,children是关键字,固定语法,必须填写。
node                  #  group组内包含的其他组名
db                    #  group组内包含的其他组名


# 4. 分组主机可以简写
[databases]
db-[a:e].example.com
这里表示相当于:
db-a.example.com
db-b.example.com
db-c.example.com
db-d.example.com
db-e.example.com


# 5. 隐藏所有主机分组all
最后还有一个隐藏的分组,那就是all,代表全部主机,这个是隐式的,不需要写出来的。

Ansible使用

Ansible常用命令语法

通用语法: ansible <host-pattern> [-m module_name] [options]

​ 指令 匹配规则的主机清单 -m 模块名 选项

1
2
3
4
5
6
7
8
9
10
11
12
--version 显示版本
-a 模块参数(如果有)
-m module 指定模块,默认为command
-v 详细过程 –vv -vvv更详细
--list-hosts 显示主机列表,可简写--list
-k, --ask-pass 提示连接密码,默认Key验证
-K,--ask-become-pass 提示使用sudo密码
-C, --check 检查,并不执行
-T, --timeout=TIMEOUT 执行命令的超时时间,默认10s
-u, --user=REMOTE_USER 执行远程执行的用户
-U, SUDO_USER, --sudo-user 指定sudu用户
-b, --become 代替旧版的sudo 切换

查看模块帮助: ansible-doc [options][module...]

1
2
3
4
5
6
ansible-doc: 显示模块帮助
ansible-doc [options] [module...]

-a 显示所有模块的文档
-l, --list 列出可用模块
-s, --snippet 显示指定模块的简要说明

Ansible 主机 匹配列表

使用通配符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
*  匹配任意字符
# ansible '*' --list   等同于 # ansible all --list

? 匹配单个字符
# ansible 'test-node0?' --list

: 或者  --> 在组node或master
# ansible 'node:master' --list

:& 并且  (逻辑与)  ---> 在组node和master中
# ansible 'node:&master' --list

:! 逻辑非 ---> 在组master内,却不在node内
# ansible 'master:!node' --list

使用正则表达式

~表示后面是正则匹配,注意~后面不能有空格

1
# ansible '~^[[:digit:]]' --list

Ansible 的命令执行过程

以 ansible test-node01 -m command -a 'ls -l /' -vvv 这条命令为例,根据显示的信息时行解读

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1>. 加载自己的配置文件,默认/etc/ansible/ansible.cfg
Using /etc/ansible/ansible.cfg as config file

2>. 匹配主机清单
Parsed /etc/ansible/hosts inventory source with ini plugin

3>. 加载指令对应的模块文件
Using module file /usr/lib/python2.7/site-packages/ansible/modules/commands/command.py

4>. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件,这个目录就是在/etc/ansible/ansible.cfg定义的
  ( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1517301292.6-155771303493861 `" ....)
    sftp> put /tmp/tmp4JvsLH /root/.ansible/tmp/ansible-tmp-1517301292.6-155771303493861/command.py\n'

5>. 给文件 +x 权限
 'chmod u+x /root/.ansible/tmp/ansible-tmp-1517301292.6-155771303493861/ /root/.ansible/tmp/ansible-tmp-1517301292.6-155771303493861/command.py && sleep 0'

6>. 执行并返回结果
 '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1517301292.6-155771303493861/command.py;

7>. 删除临时py文件,sleep 0退出
rm -rf "/root/.ansible/tmp/ansible-tmp-1517301292.6-155771303493861/" > /dev/null 2>&1 && sleep 0

8>. 断开远程主机连接
'Shared connection to 7-db-3.hunk.tech closed.\r\n')

执行结果状态

  • 绿色:执行成功并且不需要做改变的操作
  • ×××:执行成功并且对目标主机做变更
  • 红色:执行失败
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
可以在配置文件中定义
[colors]
#highlight = white
#verbose = blue
#warn = bright purple
#error = red
#debug = dark gray
#deprecate = purple
#skip = cyan
#unreachable = red
#ok = green
#changed = yellow
#diff_add = green
#diff_remove = red
#diff_lines = cyan

Ansible常用模块的使用

Ansible的模板非常的重要,这里要非常详细的学习

ping

功能:尝试连接到主机,验证并返回pong成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 查看模块的简要说明
[root@test-master01 ~]# ansible-doc -s ping
- name: Try to connect to host, verify a usable python and return `pong' on success
  ping:
      data:                  # Data to return for the `ping' return value. If this parameter is set to `crash', the module will cause an exception.

[root@test-master01 ~]# ansible all -m ping
test-node02 | SUCCESS => {
    "changed": false,
    "ping": "pong"  # 返回pong表明成功通讯
}
test-master01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
test-node01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

command

功能:在远程节点上执行命令 。

  • 变量 和操作符号 “<”, “>”, “|”, “;” and “&” 不能正常工作。如果需要使用,请使用shell模块。
  • Ansible默认不指定模块时,将使用此模块。
1
2
3
4
5
- chdir  命令运行前先切换到此目录。   ansible test-node01 -a 'chdir=/tmp ls'
- creates  条件判断,如果文件存在,将不执行后面的命令。 ansible test-node01 -a 'creates=/tmp rm -f test.py'
- removes  条件判断,如果文件不存在,将不执行后面的命令。ansible test-node01 -a 'removes=/tmp rm -f test.py'
- stdin 将命令的stdin直接设置为指定的值
- warn  如果 ansible.cfg 设置了开启警报, 将不会对这一行进行警报

shell

功能:在远程节点上执行命令。与command模快使用一致,但是,变量 和操作符号 “<”, “>”, “|”, “;” and “&” 能正常工作。

1
2
3
4
5
6
7
8
9
10
11
# 下面2个例子对比能清晰的表示出不同的地方
[root@test-master01 ~]# ansible test-node01 -m command  -a 'echo $RANDOM'
test-node01 | SUCCESS | rc=0 >>
$RANDOM

[root@test-master01 ~]# ansible test-node01 -m shell  -a 'echo $RANDOM'
test-node01 | SUCCESS | rc=0 >>
19077

# 这些复杂命令,即使使用shell也可能会失败,解决办法:写到脚本时,copy到远程,执行,再把需要的结果拉回执行命令的机器。
[root@test-master01 ~]# ansible test-node01 -m shell -a df | awk '{print $5}'

script

功能:把脚本复制到远程节点后,在远程节点本地运行脚本 ,给定的脚本将通过远程节点上的shell环境进行处理。这个模块在远程系统上不需要python,就像原始脚本一样。

1
2
3
4
5
6
7
8
9
10
[root@test-master01 ~]# ansible test-node02 -m script -a 'hello.sh'
test-node02 | SUCCESS => {
    "changed": true,
    "rc": 0,
    "stderr": "Shared connection to test-node02 closed.\r\n",
    "stdout": "hello welcome to chenfanlinux.org\r\n",
    "stdout_lines": [
        "hello welcome to chenfanlinux.org"
    ]
}

copy

功能:复制文件或目录到远程节点。默认会覆盖目标文件 。

参数详解:

1
2
3
4
5
6
7
- src:要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync。
- dest:必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录。
- backup:在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no
- content:用于替代"src",可以直接设定指定文件的内容,相当于echo 重定向内容到文件
- directory_mode:递归的设定目录的权限,默认为系统默认权限
- force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes
- others:所有的file模块里的选项都可以在这里使用

实例说明:

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 复制文件
[root@test-master01 ~]# ansible test-node01 -m copy -a 'src=hello.sh dest=/root backup=yes'
test-node01 | SUCCESS => {
    "changed": true,
    "checksum": "449c7df7cfc5a34a19f3e6dc64bb739fa066c650",
    "dest": "/root/hello.sh",
    "gid": 0,
    "group": "root",
    "md5sum": "a1c5800f3a303d01101a2861dd37b165",
    "mode": "0644",
    "owner": "root",
    "size": 53,
    "src": "~None/.ansible/tmp/ansible-tmp-1528359468.11-74900633617667/source",
    "state": "file",
    "uid": 0
}

# 复制目录时,斜线不要写,这样可以将thid_dir 目录复制到远程的root下
[root@test-master01 ~]# mkdir this_dir # 文件底下需要有内容
[root@test-master01 ~]# touch this_dir/test.text
[root@test-master01 ~]# ansible test-node01 -m copy -a 'src=/root/this_dir  dest=/root backup=yes'
test-node01 | SUCCESS => {
    "changed": true,
    "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "dest": "/root/this_dir/test.text",
    "gid": 0,
    "group": "root",
    "md5sum": "d41d8cd98f00b204e9800998ecf8427e",
    "mode": "0644",
    "owner": "root",
    "size": 0,
    "src": "~None/.ansible/tmp/ansible-tmp-1528359562.1-256280234210712/source",
    "state": "file",
    "uid": 0
}

file

功能:文件操作及属性设置

参数详解:

1
2
3
4
5
6
7
8
9
10
11
12
13
1
force:需要在两种情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
group:定义文件/目录的属组
mode:定义文件/目录的权限
owner:定义文件/目录的属主
path:必选项,定义文件/目录的路径
recurse:递归的设置文件的属性,只对目录有效
src:要被链接的源文件的路径,只应用于state=link的情况
dest:被链接到的路径,只应用于state=link的情况
state:  操作方法
    directory:如果目录不存在,创建目录
    file:即使文件不存在,也不会被创建
    link:创建软链接
    hard:创建硬链接
    touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
    absent:删除目录、文件或者取消链接文件。相当于rm -rf

实例说明:


17
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 创建空文件,类似于touch
[root@test-master01 ~]# ansible test-node01 -m file -a 'path=/root/null.txt state=touch mode=0666 owner=root'
test-node01 | SUCCESS => {
    "changed": true,
    "dest": "/root/null.txt",
    "gid": 0,
    "group": "root",
    "mode": "0666",
    "owner": "root",
    "size": 0,
    "state": "file",
    "uid": 0
}

# 创建空目录, 类似于mkdir -p
[root@test-master01 ~]# ansible test-node01 -m file -a 'path=/root/dir1/dir2/dir3  state=directory  mode=0666 owner=root'
test-node01 | SUCCESS => {
    "changed": true,
    "gid": 0,
    "group": "root",
    "mode": "0666",
    "owner": "root",
    "path": "/root/dir1/dir2/dir3",
    "size": 4096,
    "state": "directory",
    "uid": 0
}


# 创建软链接
[root@test-master01 ~]# ansible test-node01 -m file -a 'path=/root/hello   state=link src=/root/hello.py  mode=0666 owner=root'
test-node01 | SUCCESS => {
    "changed": true,
    "dest": "/root/hello",
    "gid": 0,
    "group": "root",
    "mode": "0777",
    "owner": "root",
    "size": 14,
    "src": "/root/hello.py",
    "state": "link",
    "uid": 0
}

[root@test-node01 ~]# ls hello -l
lrwxrwxrwx 1 root root 14 Jun  7 16:30 hello -> /root/hello.py

cron

功能:管理计划任务

参数详解:

1
2
3
4
5
6
7
8
9
10
11
12
backup:对远程主机上的原任务计划内容修改之前做备份
cron_file:如果指定该选项,则用该文件替换远程主机上的cron.d目录下的用户的任务计划
day:日(1-31,*,*/2,……)
hour:小时(0-23,*,*/2,……)
minute:分钟(0-59,*,*/2,……)
month:月(1-12,*,*/2,……)
weekday:周(0-7,*,……)
job:要执行的任务,依赖于state=present
name:该任务的描述
special_time:指定什么时候执行,参数:reboot,yearly,annually,monthly,weekly,daily,hourly
state:确认该任务计划是创建还是删除
user:以哪个用户的身份执行

实例说明:

1
2
3

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 设置一个定时任务
[root@test-master01 ~]# ansible  test-node01 -m cron -a 'name="test cron job" minute=*/2 job="/usr/bin/wall hello world"'
test-node01 | SUCCESS => {
    "changed": true,
    "envs": [],
    "jobs": [
        "test cron job"
    ]
}

[root@test-node01 ~]# crontab -l
#Ansible: test cron job
*/2 * * * * /usr/bin/wall hello world


# 禁用某个计划任务
[root@test-master01 ~]# ansible  test-node01 -m cron -a 'disabled=yes name="test cron job" minute=*/2 job="/usr/bin/wall hello world"'
test-node01 | SUCCESS => {
    "changed": true,
    "envs": [],
    "jobs": [
        "test cron job"
    ]
}

[root@test-node01 ~]# crontab -l
#Ansible: test cron job
#*/2 * * * * /usr/bin/wall hello world

# 删除某个定时任务
[root@test-master01 ~]# ansible  test-node01 -m cron -a 'state=absent name="test cron job"'
test-node01 | SUCCESS => {
    "changed": true,
    "envs": [],
    "jobs": []
}

[root@test-node01 ~]# crontab -l
# 这时定时任务空了

猜你喜欢

转载自blog.csdn.net/qq_32485197/article/details/81237634