Akemi

Ansible笔记集合

2024/04/26

如果出现无法载图的情况,请检查与github的连通性

centos安装ansible

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
control-host节点(可联网)
#调整网络配置
外网网络-从dhcp获取
内部网络

从epel安装
yum -y install ansible
yum list | grep ansible
ansible.noarch 2.9.27-1.el7 epel
ansible-collection-microsoft-sql.noarch 1.1.0-1.el7_9 extras
ansible-doc.noarch 2.9.27-1.el7 epel
ansible-inventory-grapher.noarch 2.4.4-1.el7 epel
ansible-lint.noarch 3.5.1-1.el7 epel
ansible-openstack-modules.noarch 0-20140902git79d751a.el7 epel
ansible-python3.noarch 2.9.27-1.el7 epel
ansible-review.noarch 0.13.4-1.el7 epel
ansible-test.noarch 2.9.27-1.el7 epel
centos-release-ansible-27.noarch 1-1.el7 extras
centos-release-ansible-28.noarch 1-1.el7 extras
centos-release-ansible-29.noarch 1-1.el7 extras
centos-release-ansible26.noarch 1-3.el7.centos extras
kubernetes-ansible.noarch 0.6.0-0.1.gitd65ebd5.el7 epel
python2-ansible-runner.noarch 1.0.1-1.el7 epel
python2-ansible-tower-cli.noarch 3.3.9-1.el7 epel
vim-ansible.noarch 3.2-1.el7 epel

yum -y install ansible

ansible --version
ansible 2.9.27
config file = /root/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Nov 14 2023, 16:14:06) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]

sshpass快速分发

分发hosts文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/bash  

# 从/etc/hosts中提取IP地址并跳过前两行
ips=$(awk 'NR > 2 { print $1 }' /etc/hosts)

# 统计IP地址的数量
ip_count=$(echo "$ips" | wc -l)

#定义主机密码password
PASSWORD="1"

# 如果没有找到任何IP地址,则退出脚本
if [ $ip_count -eq 0 ]; then
echo "No IP addresses found to ping."
exit 1
fi

# 循环遍历每个IP地址
for ip in $ips; do
# 使用ping命令测试连通性,-c 1 表示发送一个ping包,-W 1 表示等待1秒超时
if ping -c 1 -W 1 "$ip" &> /dev/null; then
echo "Ping successful for $ip, attempting to SCP /etc/hosts."

# 使用sshpass进行无密码SSH登录和scp传输,请确保sshpass已安装
# 注意:将YOUR_PASSWORD替换为实际的SSH密码,出于安全考虑,不建议在脚本中硬编码密码
sshpass -p "$PASSWORD" scp /etc/hosts "$ip":/etc/hosts

# 检查scp命令的退出状态
if [ $? -eq 0 ]; then
echo "/etc/hosts successfully copied to $ip."
else
echo "Failed to copy /etc/hosts to $ip."
fi
else
echo "Ping failed for $ip, skipping SCP."
fi
done

echo "Ping and SCP process completed for $ip_count IP addresses."

ansible配置文件

静态inventory文件

定义了ansible管理的主机

静态inventory文件

动态inventory文件是一个脚本,会连接到管理系统的节点信息数据库,并将节点信息以特定的格式输出(json)

支持子组children

支持通过ipv4划分管理主机的范围,如192.168.[10:11].[1:254],2001:db8::[a:f]

inventroy文件中有两个特殊主机组,all表示所有主机,ungrouped表示不属于任何主机组的被管理主机

查看主机信息(测试)ansible -i inventory all --list-hosts

新节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
yum -y install epel-release
yum update
yum -y install ansible

cat > inventory << EOF
1panel
pve
ws-k8s-master1
ws-k8s-master2
ws-k8s-master3
harbor
ws-k8s-node1
ws-k8s-node2
ws-k8s-node3
ceph-node1
ceph-node2
ceph-node3
docker-host

[k8s:children]
master
worknode

[manager]
1panel
pve

[master]
ws-k8s-master1
ws-k8s-master2
ws-k8s-master3

[worknode]
ws-k8s-node1
ws-k8s-node2
ws-k8s-node3

[storage]
ceph-node1
ceph-node2
ceph-node3

[activity]
harbor
docker-host
EOF

#测试
ansible -i inventory all --list-hosts
hosts (13):
ws-k8s-node1
ws-k8s-node2
ws-k8s-node3
ceph-node1
ceph-node2
ceph-node3
1panel
pve
harbor
docker-host
ws-k8s-master1
ws-k8s-master2
ws-k8s-master3

ansible -i inventory k8s --list-hosts
hosts (6):
ws-k8s-master1
ws-k8s-master2
ws-k8s-master3
ws-k8s-node1
ws-k8s-node2
ws-k8s-node3

ansible.cfg配置文件

配置文件不是全局的,不同的用户管理的配置文件不同,一般每个用户都会有自己的配置文件和inventory文件。

默认配置文件为/etc/ansible/ansible.cfg

基本参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
以sector进行划分
sudo参数也可以
[defaults]
inventory = /root/inventory
#使用root进行ssh连接
remote_user = root
#ssh连接时不提示输入密码
ask_pass = true

[privilege_escalation]
#如果是remote_user是root,就不需要提权
#是否需要提权
become = true
#提权方式
become_method = sudo
#提权到root用户
become_user = root
#用sudo时不需要输入密码
become_ask_pass = false

连接方式可以不使用ssh。如连接windows时,需要添加变量group_vars,添加名为windows文件,指定ansible_connection和ansible_port

优先级

通过ansible --version 可以查看当前使用的配置文件

优先级从低到高

1.如果没有指定,则会默认使用/etc/ansible/ansible.cfg

2.家目录下的~/ansible.cfg

3.当前目录下的ansible.cfg(使用最多)

4.ANSIBLE_CONFIG变量指定的配置文件

使用方式——adhoc

1
2
3
4
5
6
7
8
9
10
11
12
ansible 主机组 -m 模块 -a 模块参数 -u remote_user --become表示提权 -i inventory路径
#帮助查看
ansible-doc 模块

ansible k8s -m ping

ansible k8s -m user -a "name=xhy uid=2345 state=present"
ansible k8s -m user -a "name=xhy uid=2345 state=absent"

ansible master -m command -a "kubectl get pods"
ansible localhost -a "id root"
ansible master -m yum -a "name=httpd state=latest"

使用方式——playbook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
cat first.yaml 
---
- name: first playbook
hosts: k8s
tasks:
- name: create user
user:
name: xhy
uid: 1234
state: present

ansible-playbook first.yaml
#
-v 增加输出详细信息
--syntax-check 检查错误
-C 模拟运行

#
在play中除了name hosts tasks
还可以指定remote_user,become这种参数优先级高于ansible.cfg

#模块状态
stableinterface ——稳定版
preview ——不稳定版
deprecated ——马上要被移除
removed ——已经移除

#supported by
core 核心团队
curated 友商支持的付费模块
community 社会开发者

yaml的写法特点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#对字符串来说加不加单引号双引号都一样
asdsada qwe q
'asdasd sda sa'
"qweqws sadqfq qwes"

#输出多行
---
- name: play1
hosts: all
tasks:
- debug:
msg: |
123123
123123
123123
#输出到同行
msg: >
123123
123123
123123

#列表形式,第二种更好
hosts: servera,serverc
hosts:
- servera
- serverc
hosts: [servera,serverc]

变量

var变量

命名规则:与linux类似,只能包含字母,数字和下划线

变量范围(由高到低):
全局级——对整个主机生效 ——写在命令行里
play级——只在单个play中生效 ——在playbook中定义
Host级——对单个host或主机组生效,一般生产环境使用的 ——在inventory文件中定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#定义变量
全局级(命令行):
ansible-playbook xxx.yaml -e "user=xxx"

play级(列表定义):
---
- name:
hosts:
vars:
- name: wangshneg
- name2: xhy

play级(文件定义):
---
- name:
hosts:
vars_files:
- /home/xxx.yml

hosts级(inventory文件):——主机变量与主机组变量
servera user=ws
[test]
serverb
serverc
[test:vars]
user=xhy

#在字符串中引用变量
{{ }}

#变量文件使用——相对路径,以playbook的目录为根目录
vars_files: ws/ws.yml

#debug的var模块——不需要{{}}
debug:
var: user

group_vars与host_vars

为了让ansible条理清晰,需要将变量从inventory文件中解耦出来,最后的产物就是group_vars与host_vars

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mkdir group_vars
mkdir host_vars

cd group_vars
#在这个目录下创建与主机组名称相同的名字
vim k8s
user: ws

---
- name: debug-test
hosts: k8s
tasks:
- name: test
debug:
var: user

#host_vars同理
创建ws-k8s-node1,node2,node3的文件,在其中添加变量

变量矩阵

也就是变量的层级,一些变量是某个变量下的子变量

1
2
3
4
5
6
7
8
9
10
cat ws-k8s-master1.yaml
user:
ws:
name: ws
age: 25
password: 123
xhy:
name: xhy
age: 24
password: 456
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
- name: debug-test
hosts: ws-k8s-master1
tasks:
- name: test
debug:
var: user.ws.password
#
TASK [test] ********************************************************************
ok: [ws-k8s-master1] => {
"user.ws.password": "123"
}

##################另一种写法
debug:
var: user['ws']['password']

register变量

能将task的运行状态记录下来,并以json文件格式输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
---
- name: debug-test
hosts: ws-k8s-master1
tasks:
- yum:
name: httpd
state: latest
register: details
ignore_errors: yes
- debug:
var: details
- debug:
var: details.rc
#################################################
TASK [debug] *******************************************************************
ok: [ws-k8s-master1] => {
"details": {
"changed": false,
"changes": {
"installed": [],
"updated": []
},
"failed": false,
"msg": "",
"rc": 0,
"results": [
"All packages providing httpd are up to date",
""
]
}
}
TASK [debug] ********************************************************************************************************
ok: [ws-k8s-master1] => {
"details.rc": "0"
}
比如这个rc值就可以用来做流程控制

vault加密(不常用)

ansible vault是ansible组件,可以解密加密ansible使用的数据。可以使用ansible-vault来创建,编辑,加密,解密或查看文件。比如一些敏感数据:密钥,token等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
常用用法:

#创建
ansible-vault create vault-test.yaml
name: ws
#
cat vault-test.yaml
#查看
ansible-vault view vault-test.yaml
#修改密码
ansible-vault rekey vault-test.yaml
#编辑
ansible-vault edit vault-test.yaml
#解密
ansible-vault decrypt vault-test.yaml

#非交互式,指定密码文件的写法
ansible-vault --vault-id=./mima.yaml edit vault-test.yaml

vault和playbook

调用加密文件的情况下,通过ansible-playbook --vault-id @prompt debug.yaml

facts变量

在ansible运行时自动采集的系统参数,如内存大小、系统版本、硬盘大小、FQDN等信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#输出facts变量
ansible ws-k8s-node1 -m setup >> facts.json

#playbook运行时自动会运行获取facts的task

常见facts:
ansible_hostname
ansible_fqdn
ansible_default_ipv4.addresses
ansible_interfaces
ansible_devices.vda.partitions.vda1.size
ansible_dns.nameservers
ansible_kernel

以上变量都可以通过debug{{ ansible_hostname }}来输出进行测试

实际场景中使用ansible_devices.vda.partitions或者cpu来判断硬件条件
在流程控制中做判断,来控制是否执行task

#关闭facts收集,每个play开始时都会收集,如果用不到可以关闭facts变量
在playbook文件中
---
- name: facts
hosts: all
gather_facts: no
...

#自定义facts变量
mkdir /etc/ansible/facts.d/ -p
创建一个.fact结尾的文件
[web]
name: https
此时收集facts变量,就会发现ansible_local内有了这个变量

magic变量

magic变量就是主机变量与主机组变量,与facts变量一样,是通过ansible自动采集的。|
与facts变量一样,主要用于ansible的条件判断。

四个主要的magic变量:

hostvars:
包含被管理主机的变量,并且可以用于获取其它主机变量的值。如果还没有为该主机搜集被管理主机的facts,就不会包含被管理主机的facts。
group_names:
列出所有当前被管理主机所在的组
groups:
列出所有在inventory中的groups和hosts
inventory_hostname
包含inventory中配置的当前被管理主机的hostname。由于各种原因,这可能和fact报告的主机名不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
ansible ws-k8s-node1 -m debug -a "var=hostvars['ws-k8s-node1']"
#
输出了ws-k8s-node1的hostvars
#
ws-k8s-node1 | SUCCESS => {
"hostvars['ws-k8s-node1']": {
"ansible_check_mode": false,
"ansible_diff_mode": false,
"ansible_facts": {},
"ansible_forks": 5,
"ansible_inventory_sources": [
"/root/inventory"
],
"ansible_playbook_python": "/usr/bin/python2",
"ansible_verbosity": 0,
"ansible_version": {
"full": "2.9.27",
"major": 2,
"minor": 9,
"revision": 27,
"string": "2.9.27"
},
"group_names": [
"k8s",
"worknode"
],
"groups": {
"activity": [
"harbor",
"docker-host"
],
"all": [
"ceph-node1",
"ceph-node2",
"ceph-node3",
"1panel",
"pve",
"harbor",
"docker-host",
"ws-k8s-master1",
"ws-k8s-master2",
"ws-k8s-master3",
"ws-k8s-node1",
"ws-k8s-node2",
"ws-k8s-node3"
],
"k8s": [
"ws-k8s-master1",
"ws-k8s-master2",
"ws-k8s-master3",
"ws-k8s-node1",
"ws-k8s-node2",
"ws-k8s-node3"
],
"manager": [
"1panel",
"pve"
],
"master": [
"ws-k8s-master1",
"ws-k8s-master2",
"ws-k8s-master3"
],
"storage": [
"ceph-node1",
"ceph-node2",
"ceph-node3"
],
"ungrouped": [],
"worknode": [
"ws-k8s-node1",
"ws-k8s-node2",
"ws-k8s-node3"
]
},
"inventory_dir": "/root",
"inventory_file": "/root/inventory",
"inventory_hostname": "ws-k8s-node1",
"inventory_hostname_short": "ws-k8s-node1",
"omit": "__omit_place_holder__b39936729c630932058e036789f5741d8fdea663",
"playbook_dir": "/root",
"user": "ws"
}
}
#常用groups与inventory_hostname

task控制

简单loop的使用

循环控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
---
- name: loop
hosts: worknode
vars:
- firewallservice: firewalld
- web_server: httpd
tasks:
- name: install
yum:
name:
- "{{ firewallservice }}"
- "{{ web_server }}"
state: latest
- name: service
service:
name: "{{ item }}"
enabled: false
state: stopped
loop:
- "{{ firewallservice }}"
- "{{ web_server }}"
=========================================================
---
- name: loop
hosts: worknode
vars:
web_service:
- firewalld
- httpd
tasks:
- name: install
yum:
name:
- "{{ item }}"
state: latest
loop: "{{ web_service }}"
- name: service
service:
name: "{{ item }}"
enabled: false
state: stopped
loop: "{{ web_service }}"
=========================================================
---
- name: loop
hosts: worknode
vars_files: var/yum.yaml
tasks:
- name: install
yum:
name:
- "{{ item }}"
state: latest
loop: "{{ web_service }}"
- name: service
service:
name: "{{ item }}"
enabled: false
state: stopped
loop: "{{ web_service }}"

带变量矩阵的loop

1
2
3
4
5
6
7
8
9
10
11
...
- user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- name: ws
group: jingyue
- name: xhy
group: youshi
...

条件判断

常用判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
vars:
ws: true
tasks:
- debug:
msg: "true"
when: ws
#当ws为true时触发事件,布尔值不常用
==========================================
tasks:
- debug:
msg: "defined"
when: ws is define
#当ws已定义时触发事件
==========================================
supported_distres:
- redhat
- centos
...
tasks:
- yum:
name: http
state: present
when: ansible_distribution in supported_distres
...
#当ansible_distribution在redhat或centos时,触发事件

多条件判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#且and
when: ansible_distribution == "Redhat" and ansible_kernel == "xxx"

when:
- ansible_distribution == "Redhat"
- ansible_kernel == "xxx"
#或or
when: ansible_distribution == "Redhat" or ansible_distribution == "Centos"

======================
when: >
( ansible_distribution == "redhat" and
ansible_distribution_major_version == "7" )
or
( ansible_distribution == "fedora" and
ansible_distribution_major_version == "28" )

loop+条件判断

1
2
3
4
5
6
7
8
9
10
11
12
13
user:
- name: ws
age: 25
- name: xhy
age: 24

...
tasks:
- debug:
msg: "{{ item }}"
loop: "{{ user.name }}"
when: user.age >= 25
...

handlers

检测task状态,如果task的条件达到handlers的要求,那么就会触发事件;
如果检测到比如服务已启动,那么就不会进行重启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
tasks:
- template: #做一个配置文件
src: xxxx
dest: xxxx
notify: #触发、通知
- restart httpd
#定义一个handlers,名字与notify的一致
#在handlers中定义重启httpd
handlers:
- name: restart httpd
service:
name: httpd
state: restarted

注:只有当一个play的所有task都成功,才会执行handlers

1
2
3
4
5
6
7
#忽略错误,错误出现时playbook会停止,忽略后,就算错误也不会停止运行playbook
tasks:
ignore_error: yes

#强制执行handlers,生产中必加
force_handlers: yes
tasks:

fail与changed控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ansible在使用shell模块时,每次都会标记为成功执行并changed
此时可以通过输出register
failed_when: "'Password missing' in register.stdout"
手动对脚本进行标记失败

#fail模块
直接输出错误信息
- fail:
msg: ""
when: "'Password missing' in register.stdout"

#手动标记changed状态
- name: xxx
command: "echo 'hello'"
changed_when: false
永远不是changed状态

block-rescue-always

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
block是一个块,可以包括多个task,被映射为一组逻辑的task,方便对多个task进行管理
比如在block后添加when,或者changed_when等

在block运行失败时,会运行rescue下的内容

无论block运行失败或成功,都会执行always下的内容

tasks:
- block:
- name: 升级
shell:
cmd: xxx
rescue:
- name: 回滚
shell:
cmd: xxx
always:
- name: 重启服务
shell:
cmd: xxx

常用模块

文件管理:

blockinfile 文件中插入内容
copy 复制
file 创建、删除文件
lineinfile 文本中插入内容
state 状态
synchronize 同步

J2模板文件:

在ansible安装服务后,服务使用的配置文件为默认文件,现在就有J2文件,可以根据变量进行配置文件的修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#/etc/hosts
{# /etc/hosts #} 注释
{{ ansible_facts['xxx']['xxx']}} {{ ansible_facts['hostname']}}

#template模块是专门用于传送j2模板的,会自动应用变量
tasks:
- template:
src: /tmp/j2/xxx
dest: /etc/hosts

#防止j2模板被更改
在ansible.cfg中添加
ansible_managed = Ansible managed
在j2文件中首行添加
{{ ansible_managed }}
下发后,会标注这个被ansible接管不要手动修改

#j2模板的特殊用法
for循环,类似于
{% for user in users %}
{{ user }}
{% endfor %}

条件判断if
{% if %}
{% else %}
{% enfif %}

简单调优

1
2
3
4
5
6
7
8
#ansible.cfg文件内添加
forks = 4
数量受cpu核心数量限制,允许OS同时操作的线程数
如果=1,则task会一个一个执行

#inventory文件内添加
serial: 2
表示单次执行2个task
CATALOG
  1. 1. centos安装ansible
  2. 2. sshpass快速分发
  3. 3. ansible配置文件
    1. 3.1. 静态inventory文件
    2. 3.2. ansible.cfg配置文件
      1. 3.2.1. 优先级
    3. 3.3. 使用方式——adhoc
    4. 3.4. 使用方式——playbook
      1. 3.4.1. yaml的写法特点
  4. 4. 变量
    1. 4.1. var变量
    2. 4.2. group_vars与host_vars
    3. 4.3. 变量矩阵
    4. 4.4. register变量
    5. 4.5. vault加密(不常用)
    6. 4.6. facts变量
    7. 4.7. magic变量
  5. 5. task控制
    1. 5.1. 简单loop的使用
    2. 5.2. 带变量矩阵的loop
    3. 5.3. 条件判断
    4. 5.4. 多条件判断
    5. 5.5. loop+条件判断
    6. 5.6. handlers
    7. 5.7. fail与changed控制
    8. 5.8. block-rescue-always
    9. 5.9. 常用模块
  6. 6. 简单调优