一、简介
在进行多个服务器配置管理时,为了提高效率,通过ansible达到同时管理所有节点,ansible基于python编写,由Paramiko和PyYAML俩个关键模块构建
特点如下:
- 没有客户端,通过ssh链接节点
- 不仅仅支持python,还支持多种动态语言开发模块
- 非root账户也可使用
- 轻量级
- 简单易读
- … …
二、运行环境
配置文件
查找配置文件的顺序
- 环境变量
- ./ansible.cfg
- ~/.ansible.cfg
- /etc/ansible/ansible.cfg
ansible.cfg参数列表如下
- inventory 主机列表 /etc/ansible/hosts
- library 存放模块的目录 /usr/share/my_modules/
- forks 最多多少个进程同时工作 5
- sudo_user 默认执行命令的用户 root
- remote_port 远程端口 22
- host_key_checking 是否检查主机秘钥,一般下发控制主机的ssh公钥到节点,从而使用无密码访问 false
- timeout 超时间隔 10
- log_path 日志路径,默认不记录,只有指定路径才记录 /var/log/ansible.log
- … …
三、帮助工具
# 显示所有模块
ansible-doc -l
# 显示该模块用法
ansible-doc ping
四、组件介绍
inventory
静态主机配置列表
/etc/ansible/hosts
172.29.88.100
172.29.88.103 ansible_ssh_pass='123456'
[buildnodes]
172.29.88.100
172.29.88.133
[buildnodes:vars]
ansible_ssh_pass='123456'
[allnodes:children]
buildnodes
172.29.88.156
当然,可以在ansible.cfg中指定inventory为目录,这样该目录下的文件都是可以做主机配置列表
动态主机配置列表
在执行ansible命令时,使用-i参数指定该脚本即可,该脚本必须支持–list(-l)和–host(-H) + 主机ip,前者是返回所有主机及主机组信息,后者返回该主机的变量信息,返回格式都是json格式
一个参考的脚本
#!/usr/bin/env python3
#coding:utf8
import json
import sys
def all():
info_dict = {
"all":[
"10.10.0.109",
"10.10.0.112"]
}
print(json.dumps(info_dict,indent=4))
def group():
host1 = ['10.10.0.112']
host2 = ['10.10.0.112','10.10.0.109']
group1 = 'test1'
group2 = 'test2'
hostdata = {
group1:{"hosts":host1},
group2:{"hosts":host2}
}
print(json.dumps(hostdata,indent=4))
def host(ip):
info_dict = {
"10.10.0.112": {
"ansible_ssh_host":"10.10.0.112",
"ansible_ssh_port":22,
"ansible_ssh_user":"root",
"ansible_ssh_pass":"123457"
},
"10.10.0.109": {
"ansible_ssh_host":"10.10.0.109",
"ansible_ssh_port":22,
"ansible_ssh_user":"root",
"ansible_ssh_pass":"xxxx"
}
}
print(json.dumps(info_dict,indent=4))
if len(sys.argv) == 2 and (sys.argv[1] == '--list'):
group()
elif len(sys.argv) == 3 and (sys.argv[1] == '--host'):
host(sys.argv[2])
else:
print("Usage: %s --list or --host <hostname>" % sys.argv[0])
sys.exit(1)
内置参数
ansible_ssh_user
ansible_ssh_pass
ansible_python_interpreter
ansible_shell_type
Ah-Hoc命令
1.后台运行
# 后台执行最大时间是120秒,每1秒检查一下状态
ansible buildnodes -m shell -a 'sleep 5;cat /etc/issue' -P 1 -B 120 -f 2 -o
2.复制文件
ansible buildnodes -m copy 'src=hosts.py dest=/root/hosts.py owner=root group=root mode=644 backup=yes' -o
3.包管理
ansible buildnodes -m apt -a 'name=sysstat state=latest' -f 2 -o
4.用户管理
ansible buildnodes -m user -a 'name=tester password="$1$s3aRAhUo$B8S/ei.VeKLJSC3h37aMP1"'
Playbook
facts组件
ansible buildnodes -m setup
ansible buildnodes -m setup -a 'filter="ansible_python_version"'
五、Playbook
基本语法
---
- hosts: all
tasks:
- name: Install Nginx Package
apt: name=nginx state=present
- name: Copy Nginx.conf
template: src=./nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root mode=0644 validate='nginx -t -c %s'
notify:
- ReStart Nginx Service
handlers:
- name: ReStart Nginx Service
service: name=nginx state=restarted
# 进行语法检查
ansible-playbook nginx.yaml --syntax-check
# 列出所有task
ansible-playbook nginx.yaml --list-task
# 部署
ansible-playbook -i hosts nginx.yaml -f 3
变量与引用
---
- hosts: all
gather_facts: False
vars_prompt: #执行playbook时交互输入
- name: "one"
prompt: "first"
default: "ok"
private: no
vars: #定义变量
xixi: gege
vars_files: #从文件中获取变量
- var.json
tasks:
- name: display host info
debug: msg="the {{ inventory_hostname }} user is {{ ansible_ssh_user }},{{ hehe }},{{ xixi}},{{one}} "
- name: register variable
shell: hostname
register: info
- name: display variable
debug: msg="The variable is {{ info }} " #info是python字典,info['stdout']是执行的结果
# 在执行playbook时指定变量
ansible-playbook playbook.yaml -e "hehe=bilibili"
ansible-playbook playbook.yaml -e "@var.json"
循环
1.标准loops
---
- hosts: all
gather_facts: False
tasks:
- name: debug loops
debug: msg="name -> {{ item.key }},value -> {{ item.value }} "
with_items:
- {key: "one",value: "hehe"}
- {key: "second",value: "haha"}
2.嵌套loops
---
- hosts: all
gather_facts: False
tasks:
- name: debug loops
debug: msg="name -> {{ item[0] }},value -> {{ item[1] }}"
with_nested:
- ['A']
- ['a','b','c']
3.散列loops
---
- hosts: buildnodes
gather_facts: False
vars:
users:
jenkins:
name: jenkins
shell: bash
root:
name: root
shell: sh
tasks:
- name: debug loops
debug: msg="name -> {{ item.key }},value -> {{ item.value.name }} shell -> {{ item.value.shell }}"
with_dict: users
4.文件匹配loops
---
- hosts: buildnodes
gather_facts: False
tasks:
- name: debug loops
debug: msg="files -> {{ item }}"
with_fileglob:
- /roor/ansible/*.yaml
5.随机选择loops
---
- hosts: buildnodes
gather_facts: False
tasks:
- name: debug loops
debug: msg="name -> {{ item }}"
with_random_choice:
- "1"
- "2"
- "3"
6.条件判断loops
---
- hosts: buildnodes
gather_facts: False
tasks:
- name: debug loops
shell: cat /etc/issue
register: issue
until: issue.stdout.startswith("Ubuntu")
retries: 5
delay: 5
7.文件优先匹配loops
---
- hosts: buildnodes
gather_facts: False
tasks:
- name: debug loops
debug: msg="files -> {{ item }}"
with_first_found:
- "{{ ansible_distribution }}.yaml"
- "default.yaml"
8.register loops
---
- hosts: buildnodes
gather_facts: False
tasks:
- name: debug loops
shell: "{{ item }}"
with_items:
- hostname
- uname
register: ret
- name: display loops
debug: msg="{% for i in ret.results %} {{ i.stdout }} {% endfor %}"
lookups
ansible支持从外部获取数据,lookups就是这样那个一种插件
1.file
---
- hosts: buildnodes
gather_facts: False
vars:
contents: "{{ lookup('file','/etc/networks') }}"
tasks:
- name: debug lookup
debug: msg="the contents is {% for i in contents.split('\n') %}{{ i }}{% endfor %}"
2.password
---
- hosts: buildnodes
gather_facts: False
vars:
contents: "{{ lookup('password','hehe') }}"
tasks:
- name: debug lookup
debug: msg="the contents is {{ contents }}"
3.pipe
实际上就是利用python的subprocess.Popen执行shell命令
---
- hosts: buildnodes
gather_facts: False
vars:
contents: "{{ lookup('pipe','date +%F-%H-%M-%S') }}"
tasks:
- name: debug lookup
debug: msg="the contents is {{ contents }}"
4.redisi_kv
---
- hosts: buildnodes
gather_facts: False
vars:
contents: "{{ lookup('redis_kv','redis://localhost:6379,ansible') }}"
tasks:
- name: debug lookup
debug: msg="the contents is {% for i in contents.split('\n') %}{{ i }}{% endfor %}"
5.template
---
- hosts: buildnodes
gather_facts: True
vars:
contents: "{{ lookup('template','./lookups.j2') }}" #lookups.j2是一个jinja模板文件
tasks:
- name: debug lookup
debug: msg="the contents is {% for i in contents.split('\n') %}{{ i }}{% endfor %}"
conditionals
---
- hosts: buildnodes
gather_facts: True
vars:
contents: "{{ lookup('pipe','date +%F-%H-%M-%S') }}"
tasks:
- name: debug lookup
debug: msg="the contents is {{ contents }}"
when: ansible_default_ipv4.address == "172.29.88.100"
Jinja2 filter
内置变量
1.groups是inventory中所有主机的信息,是一个json字符串
{'ungrouped': [], 'all': [u'172.29.88.100', u'172.29.88.133', u'172.29.88.156'], u'buildnodes': [u'172.29.88.100', u'172.29.88.133', u'172.29.88.156']}