Ansbile基础
Ansible概述
Ansible简介
• Ansible是一个配置管理和配置工具,类似于Chef,Puppet或Salt
• 这是一款很简单也很容易入门的部署工具,它使用 SSH 连接到服务器并运行配置好的任务
• 服务器上不用安装任何多余的软件,只需要开启ssh, 所有工作都交给client端的ansible负责
准备环境
启动三台虚拟机:
localhost | 192.168.138.129/24 |
---|---|
web1 | 192.168.138.130/24 |
web2 | 192.168.138.131/24 |
web3 | 192.168.138.132/24 |
[root@localhost ~]# vim /etc/hosts
192.168.138.130 web1
192.168.138.131 web2
192.168.138.132 web3
192.168.138.129 localhos
[root@localhost ~]# for i in web1 web2 web3
> do
> rsync -av /etc/hosts ${i}:/etc/
> ssh ${i} reboot
> done
[root@localhost ~]# cd /root/.ssh/
[root@localhost .ssh]# ssh-keygen -b 1024 -t rsa -f id_rsa -P ""
收集主机密钥:
[root@localhost ~]# ssh-keyscan web1 web2 web3 >> ~/.ssh/known_hosts
安装ansible
• 在线安装
[root@localhost ~]# pip3 install -i https://pypi.douban.com/simple/ ansible
[root@localhost ~]# yum -y install ansible
• 使用本地安装包
– 参见《大型技术架构》课程ansible安装
配置运行环境
• 创建ansible工作目录
[root@localhost ~]# mkdir /root/ansible
• 创建配置文件
[root@localhost ~]# cd /root/ansible
[root@bogon ansible]# vim ansible.cfg
[defaults]
inventory = hosts
remote_user = root
配置运行环境(续1)
• 声明被管理主机
[root@localhost ansible]# vim hosts
[web]
web1
[webservers]
web2
web3
配置运行环境(续2)
[root@localhost ansible]# ansible all -m ping -k
SSH password:
web1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web3 | SUCCESS => {
"changed": false,
"ping": "pong"
}
web2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
Ansible应用
使用playbook
• Playbooks是Ansible的配置、部署、编排语言。
• 它们可以被描述为一个需要希望远程主机执行命令的方案,或者一组程序运行的命令集合
• Playbook由一到多个Play组成
• 每个play可以指定哪些主机执行哪些任务
• 执行任务一般通过调用模块来实现
Yaml简介
• Playbooks的格式是YAML
• 语法做到最小化,意在避免 playbooks 成为一种编程语言或是脚本
• 使用 YAML 是因为它像 XML 或 JSON 是一种利于人们读写的数据格式
Yaml语法
• 每一个 YAML 文件都是从一个列表开始
• 列表中的每一项都是一个键值对, 通常它们被称为一个 "哈希" 或 "字典"
• 所有的 YAML 文件开始行都应该是 ---。这是 YAML 格式的一部分,表明一个文件的开始
• 列表中的所有成员都开始于相同的缩进级别,并且使用一个 "- " 作为开头(一个横杠和一个空格)
• 一个字典是由一个简单的 键: 值 的形式组成(冒号后面必须是一个空格)
配置VIM
• Yaml的缩进不能使用tab键
• 建议缩进为两个空格
• 为了实现yml文件按tab键缩进两个空格,可以按以下方式 对vim进行定制
[root@localhost myansi]# cat ~/.vimrc
autocmd FileType yaml setlocal sw=2 ts=2 et ai
使用模块
• Ansible的模块实际上就是一个个的python程序文件
• Ansible执行任务就是通过调用这些模块来完成的
• 查看模块列表
[root@localhost myansi]# ansible-doc -l
• 查看模块帮助
[root@localhost myansi]# ansible-doc yum
创建playbook,实现免密登陆
调整vim的配置,使它能够适应yaml的语法
[root@localhost ansible]# vim ~/.vimrc
set ai
set ts=4
set et
set encoding=utf8
autocmd FileType yaml setlocal sw=2 ts=2 et ai
[root@room8pc16 ~]# ansible-doc authorized_key
[root@localhost myansi]# vim install_web.yml
---
- name: 服务器
hosts: all
tasks:
- name: 免密登陆
authorized_key:
user: root
state: present
key: "{{ lookup('file', '/root/.ssh/id_rsa.pub') }}"
执行playbook
• 检查语法
[root@localhost ansible]# ansible-playbook --syntax-check auth.yml
• 执行
[root@localhost ansible]# ansible-playbook auth.yml -k
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vTyQlAx5-1584802721423)(C:\Users\Administrator\Desktop\Ansible\图片\ansible.png)]
通过playbook配置yum
---
- name: 服务器
hosts: all
tasks:
- name: cp repo
copy:
src: files/server.repo
dest: /etc/yum.repos.d/server.repo
playbook:在dbservers上配置mariadb,在webservers上配置apache
# 检查web服务器是否安装了mariadb-server
[root@localhost ansible]# ansible all -m yum -a "list=mariadb-server"
[root@localhost ansible]# vim lamp.yml
---
- name: dui web
hosts: web
tasks:
- name: install mariadb
yum:
name: mariadb-server
state: present
- name: start mariadb
service:
name: mariadb
state: started
enabled: yes
- name: configure webservers
hosts: webservers
tasks:
- name: install apache
yum:
name: [httpd, php, php-mysql]
state: latest
- name: start httpd
service:
name: httpd
state: started
enabled: yes
[root@localhost ansible]# ansible-playbook --syntax-check lamp.yml
[root@localhost ansible]# ansible-playbook lamp.yml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gVg7JA4j-1584802721425)(C:\Users\Administrator\Desktop\Ansible\图片\ansible1.png)]
Ansible编程
Ansible编程基础
命名元组
Ansible官方手册 — > Ansible Documentation — > 搜索python api。把python api example中的代码复制粘贴到adhoc.py
[root@localhost ansible]# python3 adhoc.py
命名元组:为元组的下标起名,仍然具有元组的属性
• 命名元组与普通元组一样,有相同的表现特征,其添加的功能就是可以根据名称引用元组中的项
• collections 模块提供了namedtuple()函数,用于创建自定义的元组数据类型
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y', 'z'])
>>> p1 = Point(10, 20, 25)
>>> len(p1)
3
>>> p1[0]
10
>>> p1[1:]
(20, 25)
>>> p1.x
10
>>> p1.y
20
>>> p1.z
25
Ansible常用属性
• from ansible.parsing.dataloader import DataLoader
– 用来加载解析yaml文件或JSON内容,并且支持vault的解密
• from ansible.vars.manager import VariableManager
– 管理变量的类,包括主机,组,扩展等变量
• from ansible.inventory.manager import InventoryManager
– 用于创建主机清单,主机清单的源采用配置文件或是逗号分开主机名字符串
ad-hoc模式
使用TaskQueueManager
• 创建TaskQueueManager实例,用于管理子进程、通过主机列表和任务建立对象
• TaskQueueManager需要主机清单参数、主机变量参数、连接选项等
导入模块
• 不管是执行ad-hoc还是playbook都需要以下模块
#!/usr/bin/env python
import shutil
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
import ansible.constants as C
设置参数
• 运行命令时有很多参数要指定,这些参往往很长,可以先把它们提前定义出来
Options = namedtuple('Options', ['connection', 'module_path', 'forks',
'become', 'become_method', 'become_user', 'check', 'diff'])
options = Options(connection='local', module_path=[''], forks=10,
become=None, become_method=None, become_user=None, check=False, diff=False)
loader = DataLoader()
passwords = dict(vault_pass='secret')
inventory = InventoryManager(loader=loader, sources='localhost,')
variable_manager = VariableManager(loader=loader,
inventory=inventory)
设置参数( 续1 )
• 运行命令时有很多参数要指定,这些参往往很长,可以先把它们提前定义出来
play_source = dict(
name = "Ansible Play",
hosts = 'localhost',
gather_facts = 'no',
tasks = [
dict(action=dict(module='shell', args='mkdir /tmp/mytestdir'), register='shell_out'),
]
)
play = Play().load(play_source, variable_manager=variable_manager, loader=loader)
执行ad-hoc命令
• 创建实例并执行命令
tqm = None
try:
tqm = TaskQueueManager(
inventory=inventory,
variable_manager=variable_manager,
loader=loader,
options=options,
passwords=passwords,
)
result = tqm.run(play)
finally:
if tqm is not None:
tqm.cleanup()
shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
调用playbook
Playbook编程概述
• Playbooks 是 Ansible的配置、部署、编排语言
• 它们可以被描述为一个需要希望远程主机执行命令的方案或者一组IT程序运行的命令集合
• 可以通过python编程的方式执行playbook
相关模块
• 与执行ad-hoc命令一样,playbook的执行也需要相关模块
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.executor.playbook_executor import PlaybookExecutor
创建元组
• Playbook的参数更多,元组更大
Options = namedtuple('Options',
[‘connection', 'remote_user',
‘ask_sudo_pass', 'verbosity',
‘ack_pass', 'module_path',
‘forks', 'become',
‘become_method', 'become_user',
'check', 'listhosts',
'listtasks',
'listtags',
'syntax',
'sudo_user', 'sudo',
'diff'])
创建元组( 续1 )
• Playbook的参数更多,元组更大
ops = Options(connection='smart',
remote_user=None, ack_pass=None,
sudo_user=None, forks=5,
sudo=None, ask_sudo_pass=False,
verbosity=5, module_path=None,
become=None, become_method=None,
become_user=None, check=False,
diff=False, listhosts=None,
listtasks=None,
listtags=None,
syntax=None)
创建其他相关参数
loader = DataLoader()
passwords = dict()
inventory = InventoryManager(loader=loader, sources=['hosts'])
variable_manager = VariableManager(loader=loader, inventory=inventory)
执行playbook
def playbookrun(playbook_path):
playbook = PlaybookExecutor(playbooks=playbook_path,
inventory=inventory,
variable_manager=variable_manager,
loader=loader, options=ops, passwords=passwords)
result = playbook.run()
return result
if __name__ == '__main__':
playbookrun(playbook_path=['install_web.yml'])
编写ansible模块
模块基础
官方模块
• Ansible官方已经提供了大量模块,在编写模块之前,可以查看是否已有现成模块
• 官方已发布模块
– http://docs.ansible.com/ansible/modules.html
• 官方正在开发的模块
– https://github.com/ansible/ansible/labels/module
模块执行流程
• 将模块文件读入内存,然后添加传递给模块的参数,最后将模块中所需要的类添加到内存,由zipfile压缩后,再由base64进行编码,写入到模板文件内
• 通过默认的连接方式(一般是ssh),ansible连接到远程主机,创建临时目录,并关闭连接
• 打开另外一个ssh连接,将模板文件以sftp方式传送到刚刚创建的临时目录中,写完后关闭连接
模块执行流程( 续1 )
• 打开一个ssh连接将任务对象赋予可执行权限,执行 成功后关闭连接
• 最后,ansible将再打开一个新连接来执行模块,并删除临时目录及其所有内容
• 模块的结果是从标准输出stdout中获取json格式的字符串。ansible将解析和处理此字符串
模块开发
模块库目录
• 可以使用 ANSIBLE_LIBRARY环境变量来指定模块的存放位置
• 也可以在playbook当前目录下创建library目录
[root@localhost myansi]# mkdir library/
编写模块头
• 在文件头部加入下列语句,表示该模块使用python运行
#!/usr/bin/env python
• 导入所需要的模块,如shutil模块
import shutil
from ansible.module_utils.basic import AnsibleModule
创建模块入口
• 使用AnsibleModule类中的argument_spec来接受参数
def main():
module = AnsibleModule(
argument_spec = dict(
source=dict(required=True, type='str'),
dest=dict(required=True, type='str')
)
)
执行动作
• 使用shutil.copy拷贝文件
hutil.copy(module.params['source'], module.params['dest'])
返回结果
• 拷贝完成后,返回json数据
module.exit_json(changed=True)
• 编写主程序代码
if __name__ == '__main__':
main()
编写测试playbook
• 编写playbook,测试编写的模块
[root@localhost myansi]# vim mytest.yml
---
- name: test remote_copy module
hosts: myself
tasks:
- name: remote_copy file
remote_copy:
source: /etc/hosts
dest: /tmp/zj.txt
执行playbook
• 执行playbook
[root@localhost myansi]# ansible-playbook mytest.yml
PLAY [test remote_copy module]
*************************************************
TASK [Gathering Facts]
*********************************************************
ok: [localhost]
TASK [remote_copy file]
********************************************************
changed: [localhost] PLAY RECAP
********************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0
ansible模块开发
# 建立自定义模块目录
[root@localhost ~]# mkdir jsck
[root@localhost ~]# cd jsck/
[root@localhost jsck]# pwd
/root/jsck
[root@localhost jsck]# export ANSIBLE_LIBRARY=/root/jsck
# 编写模块,用于在远程主机上将一个文件拷贝到目标位置
[root@localhost jsck]# vim py_copy.py
import shutil
from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
yuan=dict(required=True, type='str'),
mubiao=dict(required=True, type='str')
)
)
shutil.copy(module.params['yuan'], module.params['mubiao'])
module.exit_json(changed=True)
if __name__ == '__main__':
main()
[root@localhost jsck]# ansible all -m py_copy -a "yuan=/etc/hosts mubiao=/tmp/tt.txt"
ansible-cmdb模块
用于将ansible收集下来的主机信息转换成html页面
[root@localhost ~]# pip3 install -i https://pypi.douban.com/simple/ ansible-cmdb
[root@localhost ~]# find / -name ansible-cmdb
/usr/local/python3/bin/ansible-cmdb
[root@localhost ~]# vim /usr/local/python3/bin/ansible-cmdb
PY_BIN=$(which python3) # 第8行改为python3,默认是python2
# 通过setup模块收集远程主机信息并保存到/tmp/out/目录
[root@localhost ansible]# ansible all -m setup --tree /tmp/out/
[root@localhost ansible]# ll /tmp/out/
总用量 48
-rw-r--r--. 1 root root 15885 3月 21 22:47 web1
-rw-r--r--. 1 root root 15886 3月 21 22:47 web2
-rw-r--r--. 1 root root 15886 3月 21 22:47 web3
# 利用ansible-cmdb分析/tmp/out/下的文件,生成html
[root@localhost ansible]# /usr/local/python3/bin/ansible-cmdb /tmp/out/ > /tmp/hosts.html