文章目录
-
- playbook
-
- sudo提权
-
- 配置文件
- ansible配置用户提权
-
- 分析
- 测试
- 修改ansible配置(配合sudo使用)
-
- 测试
- inventory补充
- ansible-playbook使用
-
- YAML
- YAML格式要求
- YAML格式理解
- YAML简单总结
- playbook语法格式要求
- 实际测试
-
- ansible-playbook ping模块
- ansible-playbook 单play多任务执行
- ansible-playbook 多play执行多任务
- 剧本格式总结
-
- 格式
- setup 和 debug模块
-
- 说明
- 测试
-
- setup测试 filter过滤
- debug测试 显示信息
- 自定义变量的方法
-
- 总结
playbook
sudo提权
- 管理员需要先授权(修改/etc/sudoers)
- 普通用户用sudo命令来提权执行相应的命令
配置文件
- 位置
- /etc/sudoers
- 格式
-
vim /etc/sudoers ==================================== # 用户名(%组名) 主机名=(提权用户名) 提权命令 root ALL=(ALL) NOPASSWD:ALL #NOPASSWD 不需要输入密码 ====================================
-
ansible配置用户提权
分析
- 创建用户使用user模块
- 提权修改文件使用lineInfile模块
测试
#控制端
cd ansible #cd到ansible目录下 目的使用ansible目录下的主机清单文件
ansible all -m user -a "name=alice password={{'123456' | password_hash('sha512')}}"
#创建alice用户密码设置为123456
#全部CHANGED 成功
#提权操作
ansible all -m lineinfile -a "path=/etc/sudoers line='alice ALL=(ALL) NOPASSWD:ALL'"
#全部CHANGED 成功
#测试验证
ssh [email protected]
#输入123456
sudo systemctl restart sshd #执行成功 说明alice提权成功
exit #退出ssh
修改ansible配置(配合sudo使用)
测试
#控制端
vim ~/ansible/ansible.cfg
=================================
[defaults]
inventory = ~/ansible/inventory
remote_user = alice #远程管理时候使用的用户名(是被控制端的用户)
[privilege_escalation]
become = True #为真 需要提权
become_method = sudo #切换用户的方式 有sudo su
become_user = root #切换成什么用户 sudo -u 用户名/uid 来指定变成谁
become_ask_pass = no #执行sudo命令提权时是否需要输入密码(设置了NOPASSWD就不需要了)
=================================
#配置好了 赶紧测试下
ansible all -m command -a "who"
#失败了
node1 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: [email protected]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
#看完msg 发现ssh alice不被允许 思考下.......好像是没给ssh密钥!
#赶紧给
for i in node1 node2 node3 node4 node5
>do
ssh-copy-id alice@$i
>done
#输入alice密码 完成发送
#再来测试下
ansible all -m command -a "who"
node2 | CHANGED | rc=0 >>
alice pts/0 2020-12-21 04:42 (192.168.4.253)
#成功了 并且返回了alice从控制端4.253进入的情况
inventory补充
#清单文件补充
vim ~/ansible/inventory
=============================
[test]
node1 ansible_ssh_port=端口号 ansible_ssh_user=用户名 ansible_ssh_pass=密码
#主机名 ssh端口号 具体看被控制端ssh在哪个端口 指定登录用户 优先级比主配置文件高 远程连接密码(不是用户密码!) 之前测试用的ssh密码都是为空的
#怪不得一行只能定义一个主机名 后面要加参数 所以一行只能写一个或者切片方式同时赋予参数
=============================
ansible-playbook使用
YAML
- YAML是一个可读性高、用来表达数据序列的格式语言
- YAML:YAML Ain’t a Markup Language
- YAML以数据为中心,重点描述数据的关系和结构
YAML格式要求
- ‘#’代表注释,一般第一行为三个横杠(—)
- 键值(key/value)对使用’:‘表示,数组使用’-‘表示,’-'后面有空格
- key和value之间使用’:'分隔
- 一般缩进由两个或以上空格组成
- 相同层级的缩进必须对齐,缩进代表层级关系
- 全文不可以使用tab键~~(??? tab不香吗)~~
- 区分大小写
- 扩展名为yml或者yaml
- 跨行数据需要使用**>或者|**,其中|会保留换行符
YAML格式理解
- 普通键值对
---
"师仙": "李白" #:后面有空格
---
"师仙":
"李白" #两个以上空格 不能tab
#最简单键值对形式
- 数组 [苹果,香蕉]
---
- "苹果"
- "香蕉"
- 键值对 值为数组
---
"水果": ["苹果","梨","香蕉"]
---
"水果":
- "苹果"
- "梨"
- "香蕉"
- 键值对套键值对 值为数组 水果 :[热带水果:[香蕉], 亚热带水果:[我不知道]]
---
- "水果":
- 热带水果:
- "香蕉"
- 亚热带水果:
- "我不知道"
- 键值对数组 [{产品名:维达 卫生标准: GB15979 主要原料: 100%原生木浆}]
---
- 产品名: 维达
卫生标准: GB15979
主要原料: 100%原生木浆
- 跨行文本
---
开场宣言: > #理解为一行 >不会记录换行符 所以就是一行
白洞白色的明天 #白洞白色的明天在等着我们就是这样 喵
在等着我们
就是这样 喵
---
开场宣言: | #理解为多行 |会记录换行符 所以就是看到的这样
武藏 #武藏
小次郎 #小次郎
喵喵 #喵喵
YAML简单总结
- YAML数据格式是键值对和数组相互嵌套
- 用两个以上空格 相同空格数来区分层级
playbook语法格式要求
- playbook采用YAML格式编写
- playbook文件中由一个或多个play组成
- 每个play中可以包含:
- name (描述信息)
- hosts(主机)
- tasks(任务)
- vars(变量)
- 等等
- 使用ansible-playbook命令运行playbook剧本
- -f 选项自定义并发量
- 顺序执行.yml里面的play
- 默认会执行Gathering Facts的任务 是setup模块的功能 收集被管理的系统信息并保存在变量中 可以通过setup模块查看
实际测试
ansible-playbook ping模块
vim ~/ansible/test.yml
==========================
--- #默认开头三个横
- hosts: all #数组 键值对 hosts的值为主机 all全部具体看inventory :后面要有空格
tasks: #开头两个空格
- name: 描述信息 #再缩进两个空格 不能tab 描述信息
ping: #调用ping模块
==========================
#调用ansible-playbook执行.yml
ansible-playbook test.yml
PLAY [all] *************** #一个剧本 控制的主机是all hosts的值
TASK [Gathering Facts] ************** #默认会执行Gathering Facts这个任务 获取每个控制主机的Facts值
ok: [node5] #可以在.yml(执行的剧本中取消执行)
ok: [node3] # - hosts: all
ok: [node2] # gather_facts: flase #设定为flase取消执行 加快任务执行
ok: [node1]
ok: [node4]
TASK [描述信息] ********** #name的值 任务执行结果 全是ok
ok: [node5]
ok: [node4]
ok: [node1]
ok: [node3]
ok: [node2]
PLAY RECAP ************** #返回具体参数
node1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node4 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node5 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-playbook 单play多任务执行
vim ~/ansible/test2.yml #写个剧本
=============================
---
- hosts: test,webserver
tasks:
- name: 任务一 测试是否能够执行
ping: #ping模块不需要参数
- name: 任务二 创建shell.txt文件
shell: #执行shell模块来创建文件
touch ~/shell.txt
=============================
ansible-playbook test2.yml #执行
PLAY [test,webserver] ***************#剧本执行主机为test,webserver
TASK [Gathering Facts] *******************
ok: [node3]
ok: [node4]
ok: [node1]
TASK [任务一 测试是否能够执行] **************#执行ping模块
ok: [node3]
ok: [node4]
ok: [node1]
TASK [任务二 创建shell.txt] ************#执行shell模块 创建文件 有警告的
[WARNING]: Consider using the file module with state=touch rather than running 'touch'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set
'command_warnings=False' in ansible.cfg to get rid of this message.
changed: [node3]
changed: [node4]
changed: [node1]
PLAY RECAP ************#本次剧本状态汇总
node1 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node3 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node4 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-playbook 多play执行多任务
vim ~/ansible/test3.yml #用户创建 修改 删除
==============================
---
#第一个Play剧本 创建用户
- hosts: webserver
tasks:
- name: 创建用户
user: #调用user模块
name: johnd #user模块参数
uid: 1040
password: "{{'123456' | password_hash('sha512')}}"
#第二个play剧本 修改用户的解释器
- hosts: webserver
tasks:
- name: 修改用户的解释器
user: #调用user模块
name: johnd
shell: /sbin/nologin
#第三个play剧本 删除用户
- hosts: webserver
tasks:
- name: 删除用户
user:
state: absent
name: johnd
===============================
ansible-playbook ~/ansible/test3.yml #启动
#成功了 4个PLAY 6个TASK
#最后一个PLAY RECAP输出结果状态
#多的三个TASK是默认的 Gathering Facts
剧本格式总结
格式
==================================== #主要看对齐
---
- hosts: 主机名 # p
... #有很多参数任意选择 # l
tasks: #任务 # a
- name: #任务描述信息 # y #任
模块名: # 块 #务
模块变量: 模块变量值 # 一 #一
- name: #任务描述信息 第二个任务的描述 # #任
模块名: # #务
模块变量: 模块变量值 # #二
- hosts: 主机名 #play
... #块二
=======================================
#主要看- 确定块的范围
setup 和 debug模块
说明
- setup
- Gathering Facts 在每个剧本执行的时候都会默认执行 获取被控制端的一些信息保存到变量中
- 变量保存格式是JSON格式
- filter 参数 模糊匹配信息 过滤出需要的信息 实际是检索JSON格式的键而且只支持通配符* 不能正则好像
- debug
- 每个任务都可以执行 输出相应变量来达到调试的作用
- 变量用{{}}来表示
- msg参数输出
测试
setup测试 filter过滤
ansible test -m setup -a "filter=*ipv4*" #获取test主机信息 过滤出ipv4相关信息
node1 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [ #过滤出来一个ipv4
"192.168.4.11"
],
"ansible_default_ipv4": { #过滤出来另一个ipv4 过滤的键
"address": "192.168.4.11",
"alias": "ens33",
"broadcast": "192.168.4.255",
"gateway": "192.168.4.254",
"interface": "ens33",
"macaddress": "00:0c:29:72:29:ba",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "192.168.4.0",
"type": "ether"
},
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false
}
debug测试 显示信息
vim ~/ansible/debug.yml
=========================
---
- hosts: test
tasks:
- debug:
msg: "主机名是:{{ansible_hostname}}"
- debug:
msg: "总内存大小:{{ansible_memtotal_mb}}"
=========================
#执行
ansible-playbook debug.yml
PLAY [test] **************
TASK [Gathering Facts] ***************
ok: [node1]
TASK [debug] *********** #任务一 输出了主机名
ok: [node1] => {
"msg": "主机名是:test"
}
TASK [debug] ***********************#任务二 输出了内存大小
ok: [node1] => {
"msg": "总内存大小:798"
}
PLAY RECAP ***********
node1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#可能会有疑问 变量的值哪来的 上面仔细看看 会发现执行了一个Gathering Facts的任务 就是这个任务带来的 setup模块的功能 默认执行
#修改下debug.yml测试下上面的说法
vim ~/ansible/debug.yml
================================
---
- hosts: test
gather_facts: false #加这个 目的是取消获取变量的任务
================================
ansible-playbook debug.yml #执行
PLAY [test] ***************
TASK [debug] **********#直接执行我们的任务了
fatal: [node1]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible_hostname' is undefined\n\nThe error appears to be in '/root/ansible/debug.yml': line 5, column 13, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - debug:\n ^ here\n"}
PLAY RECAP **********************
node1 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
#发现报错了 msg中提到 ansible_hostname 没有定义!!! 变相说明Gathering Facts是获取变量的
自定义变量的方法
已经知道了debug模块是通过输出变量来辅助检查每个任务执行情况的 那么除了上面Gathering Facts获取的变量 有没有自己定义或者其他变量呢? 有的
- inventory变量
还记得主机清单文件吗? 上面Inventory补充还提到了几个变量呢 我们还能在这些文件中设置自定义变量
vim ~/ansible/inventory
====================================
[test]
node1 my_variable="我自己定义的变量"
[webserver:vars]
my_variable="我给webserver定义的变量" #两种自定义变量的方式
#给test,webserver都定义了对应专属变量my_variable 但是值是不一样的
====================================
vim ~/ansible/variable_test.yml #写个测试剧本 测试两个专属变量是不同的
==============================
---
- hosts: test,webserver
tasks:
- name: 输出
debug:
msg: "我要输出:{{my_variable}}"
================================
ansible-playbook variable_test.yml #使用测试剧本
PLAY [test,webserver] **********
TASK [Gathering Facts] ****************
ok: [node1]
ok: [node3]
ok: [node4]
TASK [输出] ***************
ok: [node1] => {
"msg": "我要输出:我自己定义的变量" #node1属于test 输出了专属变量
}
ok: [node3] => {
"msg": "我要输出:我给webserver定义的变量" #node3,4属于webserver 输出了专属变量
}
ok: [node4] => {
"msg": "我要输出:我给webserver定义的变量"
}
PLAY RECAP ****************
node1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node4 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#效果达到了 每个组专属的变量
- host facts变量
往上翻debug测试显示信息就是host facts变量的使用
- playbook变量
在.yml文件中定义
vim ~/ansible/variable_test.yml #直接在inventory变量那个剧本里面改好了 码不动了
====================================
---
- hosts: test,webserver
vars:
my_variable="我是playbook变量" #自定义 我还是叫my_variable 看看优先级
tasks:
- name: 输出
debug:
msg: "我要输出:{{my_variable}}"
====================================
ansible-playbook variable_test.yml #改了测试
PLAY [test,webserver] *********
TASK [Gathering Facts] **********
ok: [node3]
ok: [node1]
ok: [node4]
TASK [输出] **************
ok: [node1] => { #发现都是我在playbook中自定义的
"msg": "我要输出:我是playbook变量"
}
ok: [node3] => { #说明了一个问题 playbook中的自定义变量优先级是高于清单文件的变量的
"msg": "我要输出:我是playbook变量"
}
ok: [node4] => {
"msg": "我要输出:我是playbook变量"
}
PLAY RECAP ***************
node1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node4 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 单独定义一个变量文件
playbook通过var_files来指定变量文件
vim ~/ansible/file_var.yml
===========================
---
- hosts: test
vars_files: ~/ansible/variables.yml #自己定义的一个变量文件
tasks:
- name: files_variable
user: #user模块调用变量赋值
name: "{{iname}}" #赋值用户名
password: "{{ipass | password_hash('sha512')}}" #ipass密码变量
============================
vim ~/ansible/variables.yml #上面var_files指定的
=========================
---
iname: cloud #定义用户名
ipass: '123456' #定义密码
=========================
ansible-playbook file_var.yml #测试
#node1查看
id cloud #查看用户是否创建了
uid=1002(cloud) gid=1002(cloud) groups=1002(cloud) #创建成功了 文件中变量引用成功
- 交互输入变量
playbook中的vars_prompt参数来交互读取变量
vim ~/ansible/vars_prompt.yml
==================================
---
- hosts: test
vars_prompt:
- name: "your_name" #定义一个变量叫your_name
prompt: "what is you name?"#提示信息 等待用户输入
private: no #不回显输入值
default: "我是默认名字" #默认值 为空时自动顶上
#类似shell的 read -p "提示信息" 变量名
===================================
- 任务返回结果键值对当成变量
playbook中的register
vim ~/ansible/register.yml
============================
---
- hosts: test
tasks:
- name: 获取返回结果当成变量
shell: "echo test > /mnt/test.txt"
register: test_return #将shell模块执行结果作为变量保存
=============================
总结
变量的使用,利于playbook的灵活使用,还能通过debug模块输出来辅助查看变量信息达到排错的功能