ansible简介及基本操作

ansible 自动化运维工具

ansible的软件可以去登录ansible官网去下载;也可以去epel源去下载。

命令 ansible saltstack
文件 ansible puppet func

运维工具的分类: 是否具有客户端代理

agent: puppet, func 带有客户端代理
agentless: ansible, fabric, saltstack 无客户端代理
ssh

运维工作:系统安装(物理机、虚拟机)--> 程序包安装、配置、服务启动 --> 批量操作 --> 程序发布(svn,git) --> 监控

ansible:
模块化,调用特定的模块,完成特定的任务;
基于Python语言实现,由Paramiko、PyYAML和Jinja2三个关键模块;
部署简单,agentless;只需要布置服务器端;客户端必须预装ssh和python
主从模式
支持自定义模块
支持Playbook: 以文件形式自动化管理
幂等性:多次执行同一个操作,结果都是一致的

特点: 高度模块化、无客户端代理、支持playbook、幂等性

工作原理: 管理端靠paramiko模块连接,发送功能模块,在被管理端运行功能模块;运行后模块会自动删除

playbook的核心元素:
tasks: 任务,即调用模块完成的某操作
variables: 变量 -------yaml语言中变量需要事先定义
templates: 模板
handlers: 触发器,由某时间触发执行的操作
roles: 角色

一、ansible如何以命令形式管理:

1)、准备工作

时间同步、实验环境->双机互信(真实只需将管理端公钥拷贝给被管理端)----->>可以靠expect编写脚本--->实现秘钥自动分发
----->>pxe装机可以实现安装后脚本-->wget 下载公钥

客户端还需:Python环境

2)、使用格式:

#man ansible
ansible <host-pattern> [options]

-m: 指定调用哪些模块
-a: 向模块传递的参数

3)、配置文件解读:

#vim /etc/ansible/ansible.cfg
[defaults]
inventory = /etc/ansible/hosts 指定主机清单文件
roles_path = /etc/ansible/roles 指定角色的根目录
timeout = 10 连接超时
remote_user = root 默认连接远程的用户

[inventory] 设定动态清单文件

[privilege_escalation] 定义切换用户身份(执行模块的身份)
#become=True
#become_method=sudo
#become_user=root
#become_ask_pass=False

[paramiko_connection] 定义远程连接

[colors] 定义显示的颜色

4)、定义主机清单文件:

#vim /etc/ansible/hosts
192.168.0.248 单独定义一个主机

[node1] 定义第一个主机组,名称为node1,成员为247
192.168.0.247

[node2]
192.168.0.248

[allnodes]
192.168.0.247
192.168.0.248

查看主机组:

#ansible 主机组名(host-pattern) --list-hosts

查看ansible都安装哪些模块:

#ansible-doc -l

获取模块参数帮助文档:

#ansible-doc 模块名

ansible命令管理:

#ansible 主机组名 -m 模块名 -a '向模块传递的参数'

常用模块:

ping(验证连通性) cron (时间同步) command shell(执行命令) user、group(用户与组管理)

copy (拷贝) lineinfile(主文件内容管理) file(文件权限管理) archive unarchive (归档与展开归档)

yum(rpm包管理) yum_repository(配置yum源文件) mount(挂载)

service(服务管理) iptables firewalld (防火墙管理)


二、ansible中Playbook编写和使用: 了解列表和字典

playbook: YAML语言(借助了python两种数据结构:列表、字典)

YAML语言的格式:

python中:

列表: 多个有序元素的集合

(1).定义列表
列表名(变量名)=['元素1', '元素2','元素3', ...]

name=['tom', 'jerry','lisi']

(2).引用列表元素:有序的 *****
靠列表索引去引用元素: 索引类似数组的下标
print name[0]
print name[1]
...
注释:索引从0开始

(3). 列表的嵌套: *****
list1=['tom','jerry','lisi']

list2=['a1','b2',list1,'c3','d4','e5']

list2第3个元素,其值又是一个列表

print list2[2]
['tom','jerry','lisi']

print list2[2][1]
jerry


字典: 多个键值对的集合
python中:
(1).定义字典:
dict1={'name':'loring', 'age': 40 , 'uid': 99}

(2).引用字典元素: 是无序的集合 *****
print dict1['name']
loring

(3).字典嵌套:

dict2={'class': 1 , 'alltype': dict1 , 'score': 80}

print dict2['alltype']
{'age': 40, 'name': 'loring', 'uid': 99}

print dict2['alltype']['uid']
99

列表中嵌套字典:
dict1={'name':'loring', 'age': 40 , 'uid': 99}

list3=['hello','welcome',dict1,'haha']

字典嵌套列表:
dict3={'passwd': 'redhat', 'username': 'root', 'test1': list1 , 'shell': 'bash'}


YAML语言中:
列表:
[tom , jerry , lisi]

yaml:
- tom
- jerry
- lisi

[a1, b2, [tom, jerry ,lisi] , c3, d4]

- a1
- b2
- tom
- jerry
- lisi
- c3
- d4

字典:
{name: loring , age:40 , uid:99}


name: loring
age: 40
uid: 99

{'class': 1 , 'alltype': dict1 , 'score': 80}

class: 1
alltype:
name: loring
age: 40
uid: 99
score: 80

列表嵌套字典:
dict1={name: loring , age:40 , uid:99}
list3=['hello','welcome',dict1,'haha']


- hello
- welcome
- name: loring
age: 40
uid: 99
- haha

字典嵌套列表:
list1=['tom', 'jerry', 'lisi']
dict3={'passwd': 'redhat', 'username': 'root', 'test1': list1 , 'shell': 'bash'}

passwd: redhat
username: root
test1:
- tom
- jerry
- lisi
shell: bash

格式:
playbook编写:

#vim a.yml (或者使用a.yaml)
---
- hosts: 主机组名 #指定管理的主机组
remote_user: 用户名 #连接远程主机的用户
tasks: #任务、指定调用的模块
- 模块1: 参数名1=值1 参数名2=值2 ...
- 模块2:
参数名1:值1
参数名2:值2
...
...

注释:在playbook文件中,最外层列表,每一个元素值,代表了一个play(主机、用户和任务)

检测:
运行playbook: ansible-playbook命令

格式:
ansible-playbook [options] playbook.yml

--syntax-check: 语法检测
-C, --check: dry-run 测试运行,但不会真正执行

编写多play剧本:对不同主机组操作

#vim multipaly.yml
---
- hosts: node2
remote_user: root
tasks:
- user:
name: jerry66
state: present

- hosts: allnodes
remote_user: root
tasks:
- user:
name: jerry77
state: present
三、ansible中变量使用:playbook中

1、变量命名规则:naming variables:the same to the variables in shell
只能包含字母、数值、下划线、;不能以字母开头;不能使用关键字

2、定义变量:
全局:Global scope: Variables set from the command line or Ansible configuration

在play中:Play scope: Variables set in the play and related structures

主机:Host scope: Variables set on host groups and individual hosts by the inventory, fact gathering,or registered tasks

变量优先级判断:1·引用变量先后顺序,后大于前;2·作用范围大小,小的优先级高

变量优先级:
主机组变量 < 主机变量 < fact变量 < in-play变量 < register变量 < globle变量

变量类别:

1、主机组变量:

定义: 在主机清单中定义
#vim /etc/ansible/hosts
[主机组:vars]
变量名=变量值

引用主机组变量: 引用变量用 {{ 变量名 }} ;括号和名之间必须有空格

---
- hosts: allnodes
remote_user: root
tasks:
- debug: #可以打印信息
msg: "{{ testvar }}"

注意1:变量引用前面,如果没有其它字符串,变量要加引号

注意2:如果多个主机组中都去定义变量,变量名尽量不要一样

2、主机变量: host 在清单文件中定义

定义:
#vim /etc/ansible/hosts
[allnodes]
192.168.0.247 testvar="from 247"
192.168.0.248 testvar="from 248"

3、fact变量: 靠setup模块实现 *****

setup 模块获取:在连接之后;默认是执行的第一个模块

只对本次剧本运行有效
---
- hosts: allnodes
remote_user: root
gather_facts: false #关闭模拟的fact变量获取
tasks:
- debug:
msg: "{{ ansible_fqdn }}"

利用setup模块,打印所有fact变量(关于node2主机组的常用变量)
#ansible node2 -m setup | more

{ "ansible_facts": {键值对(变量)} }

靠嵌套字典中的键,去引用变量值


迭代引用变量
---
- hosts: allnodes
remote_user: root
gather_facts: false
tasks:
- setup:
- debug:
msg: "{{ ansible_date_time['date'] }}"

注意: ansible_date_time['date'] 等同于 ansible_date_time.date
其中最后的date都代表前ansible_date_time值中的一个叫data的键


4、 register变量: 变量名自定义;其值来自上某个模块运行的结果

位置与对应模块对齐

对register变量运行之后的模块有效
---
- hosts: node2
remote_user: root
tasks:
- yum:
name: vsftpd
state: installed
register: haha

- debug:
msg: "{{ haha }}"
5、in play 变量:

在playbook的play中用

vars: vars_files:
变量: “值” - 文件名
例1:
---
- hosts: node2
remote_user: root
vars:
testvar1: "hello loring"
testvar2: "welcmoe tom"
tasks:
- debug:
msg: "{{ testvar1 }} and {{ testvar2 }}"
例2:
---
- hosts: node2
remote_user: root
vars_files:
- /etc/ansible/playbooks/varfiles.yml
tasks:
- debug:
msg: "{{ testvar1 }} and {{ testvar2 }}"

6、全局变量: 命令行传递

playbook中引用变量

#ansible-playbook var10.yml -e "变量名='变量值'"

#ansible-playbook var10.yml -e "@/etc/ansible/playbooks/varfiles.yml"
#ansible-playbook var10.yml -e "@变量所在文件"

vim /etc/ansible/playbooks/varfiles.yml
testvar1: "test from file1"
testvar2: "haha to file2"

7、交互式输入变量: vars_prompt

---
- hosts: node2
remote_user: root
vars_prompt:
- name: "testvar1"
prompt: "input a num"
- name: "testvar2"
prompt: "input your name"
tasks:
- debug:
msg: "{{ testvar1 }} and {{ testvar2 }}"

四、ansible中实现控制:

一)、循环
1·with_items: 类似for循环
值为列表循环
---
- hosts: node2
remote_user: root
tasks:
- yum:
name: "{{ item }}"
state: installed
with_items:
- vsftpd
- dhcp
- httpd
------------------------
值为列表嵌套字典循环
- debug:
msg: "{{ item.name }} and {{ item['pass'] }}"
with_items:
- {name: 'tom' , pass: 'redhat'}
- {name: 'jerry' , pass: 'fedora'}

2·with_nested: 类似双重for循环

---
- hosts: node2
remote_user: root
tasks:
- debug:
msg: "{{ item[0] }} and {{ item[1] }}"
with_nested:
- ['tom','jerry']
- ['redhat','fedora','suse']

二)、判断: when

例1:
#vim when1.yml
---
- hosts: node2
remote_user: root
tasks:
- debug:
msg: "{{ loringvar }}"
when: loringvar is defined

注释:当when给定的条件为真,则会运行所在的模块;如果为假,则不运行; loringvar is difined代表判断loringvar变量是否被定义

when: 变量1 in 变量2

注释:当变量1的值被包含在变量2的值中时为真;否则为假

with_items: "{{ ansible_mounts }}"
when: item.mount == "/" and item.size_available > 20199577600

注释:在when中,支持比较运算和逻辑运算

三)、忽略错误: ignore_errors: (建议忽略与之后程序无关的error)

可忽略错误继续运行playbook
---
- hosts: node2
remote_user: root
tasks:
- yum:
name: httpdfs
state: installed
ignore_errors: yes
- debug:
msg: "the test for ignore_errors"
四)、标签:tags:

可将打标签的模块动作 一个或几个标签 单独运行;但不能改变模块在playbook中的运行顺序

注意: 多个模块,可以共用一个名称的标签;将整个任务分组(过滤)

#vim tag1.yml
---
- hosts: node2
remote_user: root
tasks:
- name: 安装dhcp服务
yum:
name: dhcp
state: installed
tags: dhcptag

- name: 安装httpd服务
yum:
name: httpd
state: installed
tags: httpdtag

- name: 安装vsftpd服务
yum:
name: vsftpd
state: installed
tags: vsftpdtag

tags应用:
#ansible-playbook tag1.yml --tags='dhcptag,vsftpdtag'

五)、handlers: 触发器

触发器:当满足某个特定条件时自动触发执行哪些操作

触发器属于某个play;在play中定义触发器(每个play中只能有一个handlers)

注意:触发器要在所有tasks任务运行结束之后,去运行

handlers定义:

一般在playbook中末尾定义handlers ;且handlers与hosts平级

handlers:
- name: loringhand #触发器名
service:
name: httpd
state: restarted

handlers应用 : notify--> 通知

- name: 下载页面文件
get_url:
url: http://192.168.0.247/loringdir/test.html
dest: /var/www/virtual/index.html
mode: 0777
force: yes
notify: loringhand #通知loringhand触发器
注释:当该模块运行状态为changed时,回调用触发器

六)、block: 类似if多分支语句

- block:
rescue:
always:

一般都tasks的最后编写

运行顺序:张氏定义([block || rescue] 为真 ;运行-->之后的模块 else 不运行---> 之后的模块 {always常运行} )

注释:
先运行block下的模块,一旦运行成功,则不会运行rescue下的模块,但是always下模块会运行,而且整个状态为真

如果block下模块运行失败,则运行rescue下的模块,always下会运行,整个状态为真

如果block下模块运行失败,去运行rescue下的模块也失败,也会运行always下模块,但是整个状态为假;在下面所有模块不再运行

#vim block1.yml
---
- hosts: node2
remote_user: root
tasks:
- block:
- name: 安装httpd
yum:
name: httpd
state: installed
rescue:
- name: 安装dhcp服务
yum:
name: dhcp
state: installed
always:
- debug:
msg: "message from always"
- debug:
msg: "the end for testing..."

七)、ansible中使用jinja2模板: ---->(一般为拷贝大文件“配置文件”修改某个变量值实现不同功能)

在拷贝文件中,文件中支持变量引用
jinja2模版文件,必须与.j2结尾

注释:调用template模块,去拷贝j2文件;在拷贝时支持变量引用

例1:基本使用

#vim /tmp/haha.j2
hello from ansible
welcome to {{ ansible_fqdn }}

#vim jinja.yml
---
- hosts: node2
remote_user: root
tasks:
- template:
src: /tmp/haha.j2
dest: /var/www/virtual/c.txt

例2:jianji2中使用控制语句:

格式;for语句:

{% for 变量名 in 列表 %}
内容(可引用变量)
{% endif %}
{# 注释信息 #} ---->> (对模版的注释;不输出显示)

格式: if语句:

{% if 条件判断 %}
内容(可引用变量)
{% elseif %}
内容
{% else %}
内容
{% endif %}

#vim if.j2

{% if ansible_fqdn=="c1.loring.com" %}
TYPE master
proity 100
{% else %}
TYPE backup
proity 90
{% endif %}
device eth0
address 192.168.0.100

注释: 以上jianja2模版文件定义好后,需在playbook中被调用才有意义


vim jinja4.yml
---
- hosts: allnodes
remote_user: root
tasks:
- file:
path: /loringdir
state: directory
- template:
src: /etc/ansible/playbooks/if.j2
dest: /loringdir/if.conf

八)、ansible中使用角色(role): *****

#vim /etc/ansible/ansible.cfg
roles_path = /etc/ansible/roles 指定角色根目录

在根目录中,建立的所有子目录,都是角色目录(角色名)

角色目录中的关键文件:角色目录是自定义

defaults(目录): 在该目录中建立的main.yml中,包含了角色的默认值(变量默认值)

files(目录): 该目录中,包含了角色需要使用的静态文件,可以被copy模块所调用,调用只需使用相对路径;不包括jinja2模板

handlers(目录): 该目录中,main.yml文件,是角色需要用到的触发器

meta(目录): 该目录中的main.yml包含了源数据,无需自己给定源数据

tasks(目录***): 该目录中的main.yml文件,就是角色的任务;必须要有

templates(目录): 该目录中,保存jinja2模板

tests(目录): 测试剧本的目录,一般不用给定

vars(目录): 该目录中main.yml是定义角色的变量,可以覆盖defaults中设定的变量


九)、ansible中使用vault(文件加密):

ansible-vault


创建:
#ansible-vault create a.yml

查看:
#ansible-vault view a.yml

修改:
#ansible-vault edit a.yml

加密文件: 前提b.yml文件必须存在
#ansible-vault encrypt b.yml

解密:
#ansible-vault decrypt b.yml

修改秘钥(密码):
#ansible-vault rekey a.yml

使用文件保存密码:
#vim pass.txt 存放vault密码的文件
redhat

#ansible-vault view a.yml --vault-password-file=pass.txt


#ansible-vault encrypt vault.yml 将整个剧本加密

#ansible-playbook vault.yml --ask-vault-pass 加密剧本运行


#ansible-vault encrypt varfile.yml 对变量文件加密

#ansible-playbook vault.yml --ask-vault-pass

注释:只有剧本使用到的文件被加密,那么在运行剧本时,必须加--ask-vault-pass选项

或者:
#vim pass.txt
redhat 存放vault密码的文件

#ansible-playbook vault.yml --vault-password-file=pass.txt

为了保证数据的安全(来剧本所需的文件;如账号密码等);也可以防止其它人随意修改


十)、配置文件、普通用户管理:

一、设定主机清单文件

1)、默认清单文件修改主配置文件
#vim /etc/ansible/ansible.cfg
[defaults]
inventory = /etc/ansible/hosts ----默认清单文件(可为目录;目录下所有文件皆为清单文件)指定(文件名随意)
#vim /etc/ansible/hosts ------- 清单文件内容编辑
[node1]
192.168.0.247
[node2]
192.168.0.248
[allnodes]
192.168.0.247
192.168.0.248

手动指定主机清单文件
-i: 指定主机清单文件
#vim a.txt
[node1]
192.168.2.10

[node2]
192.168.2.20

#ansible node2 --list-hosts -i a.txt

2)、设定配置文件:

默认主配置文件: /etc/ansible/ansible.cfg

自定义:

在家目录中定义: ~/.ansible.cfg 或: $HOME/.ansible.cfg
在运行剧本的当前目录: ./ansible.cfg


优先级: 当前位置配置文件 > 家目录中配置文件 > 默认配置文件


二、普通用户

普通用户管理需sudo提权

所有主机节点: 设定sudo条目
#vim /etc/sudoers
loring ALL=(root) NOPASSWD: ALL ----- (不一定为ALL)

1)、命令方式管理:

$ ansible node2 -m user -a 'name=tom666 state=present' --become --become-method "sudo" --become-user "root"

--become: 在执行模块时,要切换身份
--become-user: 切换到哪个用户身份,一般是root
--become-method: 以哪种方式切换,一般为sudo
--ask-sudo-pass: 是否需要sudo密码

2)、剧本方式管理:

执行剧本模块运行sudo: 在剧本中
$vim user2.yml
---
- hosts: node2
remote_user: loring
become: yes #切换用户
become_method: sudo
become_user: root
tasks:
- name: 创建tom999
user:
name: tom999
state: present

3)、全局sudo:

$vim ~/.ansible.cfg
[defaults]
inventory = /etc/ansible/hosts

[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False

原文地址:https://www.cnblogs.com/zhangshan-log/p/13745312.html