Ansible 工作机制
Ansible主要由6部分组成
Ansible 组件调用关系
下文以CentOS7为例,Ansible支持的系统有: Red Hat, Debian, CentOS, macOS (windows不支持作为管理节点)
前提条件
===================================
1. 无论是管理节点(安装Ansible的机器),还是被管理节点其上均需要安装好Python并且版本满足:
Python 2.7+ OR Python 3.5+
2. 启用EPEL源
开始安装
===================================
yum install ansible
安装过程中,可能会自动安装的依赖参考如下:
PyYAML
libyaml
python-babel
python-backports
python-backports-ssl_match_hostname
python-cffi
python-enum34
python-httplib2
python-idna
python-ipaddress
python-jinja2
python-markupsafe
python-paramiko
python-ply
python-pycparser
python-setuptools
python2-cryptography
python2-jmespath
python2-pyasn1
sshpass
如果系统里的python是2.7版本,依赖却显示安装了很多python3的依赖,一般是因为yum源不够新,建议更换
https://docs.ansible.com/ansible/latest/user_guide/intro_getting_started.html
################################################### 机器准备 ##################################
192.168.1.113 x1
192.168.1.114 x2
192.168.1.118 x3
x1机器安装了Ansible,3台机器已经互相做好免密,并且
ssh x1 echo hello
ssh x2 echo hello
ssh x3 echo hello
如上的yes应当已经搞好
##################################### 添加主机清单 ###################################################
cat << 'EOF' >> /etc/ansible/hosts
x1
x2
x3
EOF
##################################### 测试连通性 ###################################################
[root@x1 ~]# ansible all -m ping
x2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
x3 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
x1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
##################################################### 其它测试 ##################################
ansible all -a "/bin/echo hello"
##################################################### 查看版本号 ##################################
ansible --version
直接在命令批量远程操作机器(ad-hoc),另外还有一种是书写playbook的方式
ansible [pattern] -m [module] -a "[module options]"
ansible atlanta -m copy -a "src=/etc/hosts dest=/tmp/hosts"
ansible webservers -m file -a "dest=/srv/foo/b.txt mode=600 owner=mdehaan group=mdehaan"
ansible all -m shell -a 'cat /etc/os-release'
ansible all -m copy -a "src=/root/node_exporter-1.0.0.linux-amd64.tar.gz dest=/tmp"
ansible all -m copy -a "src=/root/node_exporter-1.0.0.linux-amd64.tar.gz dest=/tmp"
上面的命令连续执行两次,可以发现第1次输出为黄色,表明系统已经做了修改,第2次输出为绿色表明无任何修改,具有一定的幂等性
ansible foo.example.com -m yum -a "name=httpd state=installed"
ansible all -m setup
在Ansible里把需要管理的机器提前放到配置文件里,默认是/etc/ansible/hosts
################################################ 简单主机分组 ##################################
[webservers]
10.0.0.31
10.0.0.41
10.0.0.61
[web01]
10.0.0.8
################################################# IP地址合并 ##################################
添加三台主机至webserver
[webservers]
web1.as4k.com
web2.as4k.com
web3.as4k.com
添加三台主机至webserver
[webservers]
web[1:3].as4k.com
####################################### 直接加上密码验证 ##################################
web1.as4k.com ansible_ssh_pass='123456'
web2.as4k.com ansible_ssh_pass='123456'
web3.as4k.com ansible_ssh_pass='123456'
概述
==============================
Ansible启用动态Inventory的机制是通过调用外部脚本(任何脚本都可以,二进制文件也可以,只要运行结果返回的是JSON串就行)生成指定格式的JSON串。Ansible可以对JSON格式的字符串进行解析,并最终将其转化为Ansible可用的Inventory文件格式。所以,所谓的动态Inventory文件脚本开发,其实就是编写脚本根据具体环境将主机信息及关系(这些数据可以通过抓取数据库,调用外部API或者直接读取文件获得)以JSON格式来表示出来,并将其做为脚本输出结果传给Ansible。
需要注意的是,用于生成JSON代码的脚本必须支持两个选项:--list和--host。
--list:返回所有的主机组信息,每个组都应该包含字典形式的主机列表、子组列表,如果需要的话还应该有组变量,最简单的信息是只包含主机列表。返回的数据格式是JSON格式。
--host:返回该主机的变量列表,或者是返回一个空的字典,使用JSON格式
参考python脚本
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#!/usr/bin/python3
import os
import sys
import json
import argparse
class ExampleInventory(object):
def __init__(self):
self.inventory = {}
self.read_cli_args()
# 定义 --list 选项
if self.args.list:
self.inventory = self.example_inventory()
elif self.args.host:
self.inventory = self.empty_inventory()
else:
self.inventory = self.empty_inventory()
print(json.dumps(self.inventory))
def example_inventory(self):
return {
'group': {
'hosts': ['10.222.32.121', '10.222.32.122']
}
}
def empty_inventory(self):
return {'_meta': {
'hostvars': {}
}}
def read_cli_args(self):
parser = argparse.ArgumentParser()
parser.add_argument('--list', action='store_true')
parser.add_argument('--host', action='store')
self.args = parser.parse_args()
ExampleInventory()
使用
chmod +x inventory.py
[root@node3 /etc/ansible]# ./inventory.py --list
{"group": {"hosts": ["10.222.32.121", "10.222.32.122"]}}
[root@node3 /etc/ansible]# ansible all -i inventory.py -m ping
inventories/
inventory-prod
inventory-dev
ansible-playbook playbook.yml -i inventories/inventory-dev
剧本是用人类易读语言YAML,来描述对被管理机器需要进行的一些列操作。模块是商店,被管理机器是原材料,剧本就是做菜手册。上面按顺序记录了,如何把被管理机器一步步打造成指定的样子。
########################################### 快速入门 ###################################################
cat test.yaml
---
- hosts: nfs
tasks:
- name: copy files form m01 to nfs
copy: src=/root/httpd.conf dest=/root/ mode=777
ansible-playbook test.yaml
上面的命令也可以换行书写
- hosts: nfs
tasks:
- name: copy files form m01 to nfs
copy: src=/root/httpd.conf
dest=/root/
mode=777
########################################### 在剧本中使用shell模块 ##################################
shell和command模块比较特殊,其后直接接命令,不再是key=value的形式。
tasks:
- name: show ip address
command: hostname -I
########################################### Handlers - 事件处理器 ##################################
Running Operations On Change,在很多时候我们需要配置一些服务启动,但这些服务的启动
往往都是有条件的,那就是**当配置文件发生变化时**自动重启,这时就需要使用notify,
只要检测到配置文件变化,即调用对应的handlers处理,示例如下:
- name: template configuration file
template:
src: template.j2
dest: /etc/foo.conf
notify:
- restart memcached
- restart apache
handlers:
- name: restart memcached
service:
name: memcached
state: restarted
- name: restart apache
service:
name: apache
state: restarted
使用handlers要注意,此时name名称就是一一对应的,不仅仅是注释。
########################################### 语法检查和预执行 ###################################################
YAML对空格的要求非常严格,可使用:
ansible-playbook --syntax-check test.yaml
模拟执行(不对目标机器实际进行操作):
ansible-playbook -C test.yaml
大C参数表示预执行,不会真正修改被管理机器的东西,会提前告知我们可能发生的变化,错误。
看一下哪些机器被该剧本管理:
ansible-playbook playbook.yaml --list-hosts
执行时输出详细信息:
ansible-playbook test.yaml -C --verbose
Ansible 语法特性总结
=======================================
总的来说,Playbook语法具有如下一些特性。
1)需要以“---”(3个减号)开始,且需顶行首写。
2)次行开始正常写Playbook的内容,但笔者建议写明该Playbook的功能。
3)使用#号注释代码。
4)缩进必须是统一的,不能将空格和Tab混用。
5)缩进的级别必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的。
6)YAML文件内容和Linux系统大小写判断方式保持一致,是区别大小写的,k/v的值均需大小写敏感。
7)k/v的值可同行写也可换行写。同行使用“:”分隔,换行写需要以“-”分隔。
8)一个完整的代码块功能需最少元素,需包括name:task。
9)一个name只能包括一个task
标签、限制具体机器、指定操作系统
=================================================
---
- name: copy node-ps single binary to remote machine /etc/dAppCluster
copy: src=node-ps dest=/etc/dAppCluster/node-ps mode=0744
tags:
- INSTALL_OR_UPDATE
when:
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "6" or ansible_distribution_major_version == "7"
- name: copy node-ps manager scripts CENTOS7
copy: src=node-ps.service dest=/usr/lib/systemd/system/node-ps.service
tags:
- INSTALL_OR_UPDATE
when:
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "7"
ansible-playbook playbooks/dpool_zsh.yml --limit 10.13.32.39 (换成分组名即限制某一组机器)
ansible-playbook playbooks/node_ps.yml --tags INSTALL --limit ${new-nodeps-ip}
https://git.staff.sina.com.cn/dpool/ansible/blob/master/roles/node_ps/tasks/main.yml
使用非root用户执行
=================================================
[root@node3 /etc/ansible/playbooks]# cat none-root-user.yml
- hosts: test
tasks:
- name: debug info 4
become: yes
become_user: www
shell: whoami > /tmp/tmp2.txt
--check
参数,在之际执行前,进行模拟执行,不会对目标机器实际作出改变[root@astest ~]# cat /etc/ansible/hosts
astest
[root@astest ~]# cat /etc/hosts | grep astest
10.0.0.230 astest astest
[root@astest ~]# ansible all -m ping
[root@astest ~]# tree .
.
|-- testrole
| `-- tasks
| `-- main.yml
`-- test.yml
[root@astest ~]# cat test.yml
- hosts: astest
roles:
- testrole
[root@astest ~]# cat testrole/tasks/main.yml
- debug:
msg: "hello world!"
ansible-playbook test.yml
tasks目录:角色需要执行的主任务文件放置在此目录中,默认的主任务文件名为main.yml,当调用角色时,默认会执行main.yml文件中的任务,你也可以将其他需要执行的任务文件通过include的方式包含在tasks/main.yml文件中。
handlers目录:当角色需要调用handlers时,默认会在此目录中的main.yml文件中查找对应的handler
defaults目录:角色会使用到的变量可以写入到此目录中的main.yml文件中,通常,defaults/main.yml文件中的变量都用于设置默认值,以便在你没有设置对应变量值时,变量有默认的值可以使用,定义在defaults/main.yml文件中的变量的优先级是最低的。
vars目录:角色会使用到的变量可以写入到此目录中的main.yml文件中,看到这里你肯定会有疑问,vars/main.yml文件和defaults/main.yml文件的区别在哪里呢?区别就是,defaults/main.yml文件中的变量的优先级是最低的,而vars/main.yml文件中的变量的优先级非常高,如果你只是想提供一个默认的配置,那么你可以把对应的变量定义在defaults/main.yml中,如果你想要确保别人在调用角色时,使用的值就是你指定的值,则可以将变量定义在vars/main.yml中,因为定义在vars/main.yml文件中的变量的优先级非常高,所以其值比较难以覆盖。
meta目录:如果你想要赋予这个角色一些元数据,则可以将元数据写入到meta/main.yml文件中,这些元数据用于描述角色的相关属性,比如 作者信息、角色主要作用等等,你也可以在meta/main.yml文件中定义这个角色依赖于哪些其他角色,或者改变角色的默认调用设定,在之后会有一些实际的示例,此处不用纠结。
templates目录: 角色相关的模板文件可以放置在此目录中,当使用角色相关的模板时,如果没有指定路径,会默认从此目录中查找对应名称的模板文件。
files目录:角色可能会用到的一些其他文件可以放置在此目录中,比如,当你定义nginx角色时,需要配置https,那么相关的证书文件即可放置在此目录中。
Changes can be made and used in a configuration file which will be searched for in the following order:
1 ANSIBLE_CONFIG (environment variable if set)
2 ansible.cfg (in the current directory)
3 ~/.ansible.cfg (in the home directory)
4 /etc/ansible/ansible.cfg
Ansible will process the above list and use the first file found, all others are ignored.
################################ 配置文件注释 ########################################################
The configuration file is one variant of an INI format. Both the hash sign (#) and semicolon (;) are allowed as comment markers when the comment starts the line. However, if the comment is inline with regular values, only the semicolon is allowed to introduce the comment. For instance:
# some basic default values...
inventory = /etc/ansible/hosts ; This points to the file that lists your hosts
在线配置帮助 https://docs.ansible.com/ansible/latest/reference_appendices/config.html
默认配置文件 https://github.com/ansible/ansible/blob/devel/examples/ansible.cfg
一份常用配置文件参考
==============================
[root@node3 /etc/ansible]# cat ansible.cfg
[defaults]
inventory = /etc/ansible/hosts
roles_path = /etc/ansible/roles
interpreter_python = /usr/bin/python
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
ps: 如果要管理机器非常多,inventory 可以配置成一个目录,目录里放多个文件,文件的格式保持不变,中括号里面的内容是实际用的清单名称
系统内置变量 ansible node -m setup
========================================
ansible node -m setup
获取IP地址
========================================
cat playbooks/debug-info.yml
- hosts: test
tasks:
- name: debug info1
debug:
msg: "{{ ansible_default_ipv4.address }}"
- name: debug info2
debug:
msg: "{{ ansible_host }}"
ansible-playbook playbooks/debug-info.yml
使用group_vars里的变量
========================================
# ls
ansible.cfg group_vars hosts playbooks roles template
# group_vars 与 hosts 处在同级目录
# cat hosts
[test]
node1
node2
node3
# cat group_vars/test
foo:
name: onesdkfjsdlkfj
field2: two
role: web5
region: bx
# cat playbooks/group-vars-test.yml
- hosts: test
tasks:
- name: test1
shell: echo {{ foo.role }} > /tmp/tmp.txt
- name: test2
shell: echo {{ foo.region }} >> /tmp/tmp.txt
# ansible-playbook playbooks/group-vars-test.yml
# ssh node3 cat /tmp/tmp.txt
web5
bx
# group_vars 是固定用法,目录名不能更换,目录必须和inventory在同级目录,文件名要和主机清单中括号里面的名称对应上
[root@node3 /etc/ansible]# ifconfig | grep -A1 eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.222.32.122 netmask 255.255.254.0 broadcast 10.222.33.255
[root@node3 /etc/ansible]# cat playbooks/template-test.yml
- hosts: test
tasks:
- name: test template
vars:
testnum: 5
template:
src: /etc/ansible/templates/test.j2
dest: /tmp/test.j2
[root@node3 /etc/ansible]# cat /etc/ansible/templates/test.j2
{% if testnum > 3 %}
大与3的模板
{% endif %}
bind {{ ansible_default_ipv4.address }}
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
supervised no
[root@node3 /etc/ansible]# ansible-playbook playbooks/template-test.yml > /tmp/tmp2.txt
[root@node3 /etc/ansible]# cat /tmp/test.j2
大与3的模板
bind 10.222.32.122
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
supervised no
Ansible 默认工作模式是Push,即主机通过SSH远程推送相关资源到目标机器,目标机器执行
具体示例参考如下:
*/20 * * * * root /usr/local/bin/ansible-pull -o -C 2.1.0 -d /srv/www/king-gw/ -i /etc/ansible/hosts -U git:// git.kingifa.com/king-gw-ansiblepull >> /var/log/ansible-pull.log 2>&1
ansible-pull通常在配置大批量机器的场景下会使用,灵活性稍有欠缺,但效率几乎可以无限提升,对运维人员的技术水平和前瞻性规划有较高要求
ansible puppet saltstack三款自动化运维工具的对比
https://blog.csdn.net/qq_26848099/article/details/79400801
https://docs.ansible.com/
https://www.zsythink.net/archives/tag/ansible/
https://docs.ansible.com/ansible/2.4/shell_module.html