自动化工具--Ansible
Ansible
ansible简介
ansible是一种可以批量管理远程远程主机的的自动化运维工具
ansible配置文件:
/etc/ansible/ansible.cfg 主配置文件,配置ansible工作特性,也可以在项目的目录中创建此文件,当前目录下如果也有ansible.cfg,则此文件优先生效,建议每个项目目录下,创建独有的ansible.cfg文件,Ansible 的默认配置文件 /etc/ansible/ansible.cfg ,其中大部分的配置内容无需进行修改
/etc/ansible/hosts 主机清单
/etc/ansible/roles/ 存放角色的目录
ansible主机清单
默认的inventory file为 /etc/ansible/hosts,inventory file可以有多个,生产建议在每个项目目录下创建项目独立的hosts文件
主机清单格式:
inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组 中
此外,当如若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明
如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机
例:
ansible支持多种格式的主机清单:[server_name]为自定义内容
host
[server_name]
host
...
[server_name1]
host
...
[server_name2]
host
...
实现嵌套
[server_all:children]
server_name1
server_name2
[test]
host ansible_connection=ssh ansible_ssh_port=端口 ansible_ssh_user=连接用户
ansible_ssh_password=密码
...
#执行ansible命令时显示别名,如web01,支持定义变量供主机使用
[server_names]
serve1 ansible_ssh_host=host1
serve2 ansible_ssh_host=host2
[websrvs:vars]
ansible_ssh_password=password
范例:
[websrv]
10.0.0.27
[dbsrv]
10.0.0.18
ansible 相关工具大多数是通过ssh协议,实现对远程主机的配置管理、应用部署、任务执行等功能 建议:使用此工具前,先配置ansible主控端能基于密钥认证的方式联系各个被管理节点
#!/bin/bash
ips='10.0.0.27 10.0.0.18'
rpm -q sshpass >/dev/null || yum -y insatll sshpass
[ -f /root/.ssh/id_rsa ] || ssh-keygen -f /root/.ssh/id_rsa -P ''
export SSHPASS='123456'
for i in $ips
do
{ sshpass -e ssh-copy-id -o StrictHostKeyChecking=no $i ;} &
done
wait
ansible查看帮助
ansible-doc [options] [module...]
-l, --list #列出可用模块
-s, --snippet #显示指定模块的playbook片段
ansible使用
Ansible Ad-Hoc 的执行方式的主要工具就是 ansible
格式:
ansible <host-pattern> [-m module_name] [-a args]
--version #显示版本
-m module #指定模块,默认为command
-v #详细过程 -vv -vvv更详细
--list-hosts #显示主机列表,可简写 --list
-C, --check #检查,并不执行
-T, --timeout=TIMEOUT #执行命令的超时时间,默认10s
-k, --ask-pass #提示输入ssh连接密码,默认Key验证
-u, --user=REMOTE_USER #执行远程执行的用户,默认root
-b, --become #代替旧版的sudo 切换
--become-user=USERNAME #指定sudo的runas用户,默认为root
-K, --ask-become-pass #提示输入sudo时的口令
-f FORKS, --forks FORKS #指定并发同时执行ansible任务的主机数
ansible的Host-pattern用于匹配被控制的主机的列表
All :表示所有Inventory中的所有主机
同时还支持
'*' 通配符,匹配内容用 ""
':'逻辑或,匹配内容用 ""
':&'逻辑与,匹配内容用 ""
':!'逻辑非,匹配内容用 ''
综合逻辑,匹配内容用 ''
正则表达式,匹配内容用 ""
ansible命令执行过程
1. 加载自己的配置文件,默认/etc/ansible/ansible.cfg
2. 加载自己对应的模块文件,如:command
3. 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户
$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
4. 给文件+x执行
5. 执行并返回结果
6. 删除临时py文件,退出
范例:
[root@centos7 ~]# ansible all --list
hosts (2):
10.0.0.27
10.0.0.18
[root@centos7 ~]# ansible webserver --list
hosts (1):
10.0.0.27
[root@centos7 ~]# ansible dbserver --list
hosts (1):
10.0.0.18
[root@centos7 ~]# ansible "db*" --list
hosts (1):
10.0.0.18
[root@centos7 ~]# ansible "db*:web*" --list
hosts (2):
10.0.0.18
10.0.0.27
ansible-playbook
此工具用于执行编写好的 playbook 任务
[root@centos7 data]# vim hello.yaml
---
- hosts: all
remote_user: root
tasks:
- name: hello world
command: wall hello world
[root@centos7 data]# ansible-playbook hello.yaml
ansible-vault
此工具可以用于加密解密yml文件
ansible-vault encrypt hello.yml #加密
ansible-vault decrypt hello.yml #解密
ansible-vault view hello.yml #查看
ansible-vault edit hello.yml #编辑加密文件
ansible-vault rekey hello.yml #修改口令
ansible-vault create new.yml #创建新文件
Ansible常用模块
ping 模块
功能:测试远程主机连通性
[root@centos7 data]# ansible all -m ping
10.0.0.27 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.0.0.18 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
Shell 模块
功能:和command相似,用shell执行命令,支持各种符号,比如:*,$, >
注意:此模块不具有幂等性
[root@centos7 data]# ansible all -m shell -a "hostname -I"
10.0.0.27 | CHANGED | rc=0 >>
10.0.0.27
10.0.0.18 | CHANGED | rc=0 >>
10.0.0.18
Script 模块
功能:在远程主机上运行ansible服务器上的脚本(无需执行权限)
注意:此模块不具有幂等性
[root@centos7 data]# ansible all -m script -a script.sh
10.0.0.27 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 10.0.0.27 closed.\r\n",
"stderr_lines": [
"Shared connection to 10.0.0.27 closed."
],
"stdout": "10.0.0.27 \r\n",
"stdout_lines": [
"10.0.0.27 "
]
}
10.0.0.18 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 10.0.0.18 closed.\r\n",
"stderr_lines": [
"Shared connection to 10.0.0.18 closed."
],
"stdout": "10.0.0.18 \r\n",
"stdout_lines": [
"10.0.0.18 "
]
}
Copy 模块
功能:从ansible服务器主控端复制文件到远程主机
[root@centos7 data]# ansible all -m copy -a "src=/data/script.sh dest=/data/"
10.0.0.27 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "9c73218a465637d8e69b5a313d72634cab082501",
"dest": "/data/script.sh",
"gid": 0,
"group": "root",
"md5sum": "dd648acb20ec6b67f338f2af0a049fec",
"mode": "0644",
"owner": "root",
"size": 24,
"src": "/root/.ansible/tmp/ansible-tmp-1656574490.85-23965-23856603304984/source",
"state": "file",
"uid": 0
}
10.0.0.18 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"checksum": "9c73218a465637d8e69b5a313d72634cab082501",
"dest": "/data/script.sh",
"gid": 0,
"group": "root",
"md5sum": "dd648acb20ec6b67f338f2af0a049fec",
"mode": "0644",
"owner": "root",
"size": 24,
"src": "/root/.ansible/tmp/ansible-tmp-1656574490.8-23966-115216944889568/source",
"state": "file",
"uid": 0
}
注意:"content='内容' dest=文件"可以将内容直接写入远程主机文件中
在复制目录时,目录后又/ 复制目录,目录后没有/ 复制目录下文件
backup=yes选项在复制到远程主机时,如果目标存在则先备份
Fetch 模块
功能:从远程主机提取文件至ansible的主控端,copy相反,目前不支持目录
[root@centos7 data]# ansible all -m fetch -a "src=/etc/passwd dest=/data/"
10.0.0.27 | CHANGED => {
"changed": true,
"checksum": "f46e74616780e28c950837c16571665b058c3233",
"dest": "/data/10.0.0.27/etc/passwd",
"md5sum": "388824fe0e2029fba5ef752f0e0fab2c",
"remote_checksum": "f46e74616780e28c950837c16571665b058c3233",
"remote_md5sum": null
}
10.0.0.18 | CHANGED => {
"changed": true,
"checksum": "bbc6e343974d164f4f1a337def3fdeaa631d36b5",
"dest": "/data/10.0.0.18/etc/passwd",
"md5sum": "5df294b28938a994ed8c1f8cbd1f2a26",
"remote_checksum": "bbc6e343974d164f4f1a337def3fdeaa631d36b5",
"remote_md5sum": null
}
[root@centos7 data]# ls 10.0.0.*/etc/
10.0.0.18/etc/:
passwd
10.0.0.27/etc/:
passwd
File 模块
功能:设置文件属性,创建软链接等
[root@centos7 data]# ansible all -m file -a "path=/data/test.txt state=touch"
10.0.0.27 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/data/test.txt",
"gid": 0,
"group": "root",
"mode": "0644",
"owner": "root",
"size": 0,
"state": "file",
"uid": 0
}
10.0.0.18 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"dest": "/data/test.txt",
"gid": 0,
"group": "root",
"mode": "0644",
"owner": "root",
"size": 0,
"state": "file",
"uid": 0
}
[root@centos7 data]# ansible all -m file -a "path=/data/test state=directory"
10.0.0.27 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/data/test",
"size": 6,
"state": "directory",
"uid": 0
}
10.0.0.18 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/data/test",
"size": 6,
"state": "directory",
"uid": 0
}
[root@centos7 data]# ansible all -m shell -a "ls /data/"
10.0.0.27 | CHANGED | rc=0 >>
script.sh
test
test.txt
10.0.0.18 | CHANGED | rc=0 >>
script.sh
test
test.txt
unarchive 模块
功能:解包解压缩
实现有两种用法:
1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes,此为默认值,可省略
2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no
常见参数:
copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,
会在远程主机上寻找src源文件
remote_src:和copy功能一样且互斥,yes表示在远程主机,不在ansible主机,no表示文件在ansible
主机上
src:源路径,可以是ansible主机上的路径,也可以是远程主机(被管理端或者第三方主机)上的路径,如果是远程主机上的路径,则需要设置copy=no
dest:远程主机上的目标路径
mode:设置解压缩后的文件权限
[root@centos7 data]# ansible 10.0.0.27 -m unarchive -a "src=/data/mysql-5.7.33-linux-glibc2.12-x86_64.tar.gz dest=/data/ copy=yes"
10.0.0.27 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/data/",
"extract_results": {
"cmd": [
"/usr/bin/gtar",
"--extract",
"-C",
"/data/",
"-z",
"-f",
"/root/.ansible/tmp/ansible-tmp-1656576444.73-24464-156337659830963/source"
],
"err": "",
"out": "",
"rc": 0
},
"gid": 0,
"group": "root",
"handler": "TgzArchive",
"mode": "0755",
"owner": "root",
"size": 94,
"src": "/root/.ansible/tmp/ansible-tmp-1656576444.73-24464-156337659830963/source",
"state": "directory",
"uid": 0
}
[root@centos7 data]# ls
mysql-5.7.33-linux-glibc2.12-x86_64 script.sh test test.txt
Service 模块
功能:管理服务
[root@centos7 data]# ansible all -m service -a 'name=httpd state=started'
[root@centos7 data]# systemctl status httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
Active: active (running) since Thu 2022-06-30 16:21:11 CST; 2min 22s ago
state=started/restarted/stoped/reloaded 服务状态
enabled=yes 开机自启
Setup 模块
功能: setup 模块来收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机较多,会影响执行速度
[root@centos7 data]# ansible all -m setup -a "filter=ansible_all_ipv4_addresses"
10.0.0.18 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"10.0.0.18"
],
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false
}
10.0.0.27 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"10.0.0.27"
],
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
Cron 模块
功能:计划任务
支持时间:minute,hour,day,month,weekday
[root@centos7 data]# ansible all -m cron -a "hour=*/10 job='/bin/bash /data/script' name=scritp disabled=no"
10.0.0.27 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"envs": [],
"jobs": [
"scritp"
]
}
10.0.0.18 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"envs": [],
"jobs": [
"scritp"
]
}
[root@centos7 data]# crontab -l
#Ansible: scritp
* */10 * * * /bin/bash /data/script
Yum 和 Apt 模块
功能:
yum 管理软件包,只支持RHEL,CentOS,fedora,不支持Ubuntu其它版本
apt 模块管理 Debian 相关版本的软件包
[root@centos7 data]# ansible 10.0.0.27 -m yum -a 'name=httpd state=present'
10.0.0.27 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"installed": [
"httpd"
]
[root@centos7 data]# ansible 10.0.0.27 -m shell -a "rpm -q httpd"
[WARNING]: Consider using the yum, dnf or zypper module rather than running 'rpm'. If you need to use command because yum,
dnf or zypper 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.
10.0.0.27 | CHANGED | rc=0 >>
httpd-2.4.6-95.el7.centos.x86_64
User 模块
功能:管理用户
[root@centos7 data]# ansible 10.0.0.27 -m user -a "name=test uid=1024"
10.0.0.27 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 1024,
"home": "/home/test",
"name": "test",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 1024
}
[root@centos7 data]# id test
uid=1024(test) gid=1024(test) groups=1024(test)
Group 模块
功能:管理组
[root@centos7 data]# ansible 10.0.0.27 -m group -a "name=test_group gid=2048"
10.0.0.27 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 2048,
"name": "test_group",
"state": "present",
"system": false
}
Lineinfile 模块
ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时,存在问题,无法正常进行替换 。其实在ansible自身提供了两个模块:lineinfile模块和replace模块,可以方便的进行替换
一般在ansible当中去修改某个文件的单行进行替换的时候需要使用lineinfile模块
regexp参数 :使用正则表达式匹配对应的行,当替换文本时,如果有多行文本都能被匹配,则只有最后面被匹配到的那行文本才会被替换,当删除文本时,如果有多行文本都能被匹配,这么这些行都会被删除。
如果想进行多行匹配进行替换需要使用replace模块
Replace 模块
该模块有点类似于sed命令,主要也是基于正则进行匹配和替换,建议使用
[root@centos7 data]# ansible 10.0.0.27 -m replace -a "path=/data/fstab regexp='^(UUID=*)' replace='#\1'"
10.0.0.27 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"msg": "4 replacements made"
}
[root@centos7 data]# cat fstab
#
# /etc/fstab
# Created by anaconda on Wed Jan 19 12:08:41 2022
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
#UUID=3f6b6d7e-825b-4983-b1c0-822c4a2539f4 / xfs defaults 0 0
#UUID=1c37b4ff-d945-40e7-8bbb-471211a10827 /boot xfs defaults 0 0
#UUID=fbacfb2e-6736-4881-80b0-0e0176f1011c /data xfs defaults 0 0
#UUID=b376739b-b8f5-41e5-8c0c-2c1a0ec12e15 swap swap defaults 0 0
SELinux 模块
该模块管理 SELInux 策略
[root@centos7 data]# ansible 10.0.0.18 -m selinux -a "state=disabled"
mount 挂载和卸载
功能: 挂载和卸载文件系统
#永久挂载
ansible all -m mount -a 'src= path= opts="_netdev" state=mounted'
#永久卸载
ansible websrvs -m mount -a 'src= path= state=absent'
stat判断文件状态
[root@centos7 data]# ansible all -m stat -a 'path=/data/fstab'
10.0.0.27 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"stat": {
"atime": 1656578257.6191027,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 8,
"charset": "us-ascii",
"checksum": "01eb0765bafd693168139653c45270c5a7448c2d",
"ctime": 1656578253.3401027,
"dev": 2051,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 84461,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "0644",
"mtime": 1656578253.340102,
"nlink": 1,
"path": "/data/fstab",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": 599,
"uid": 0,
"version": "1413777910",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
}
10.0.0.18 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"stat": {
"exists": false
}
}
playbook
playbook 剧本是由一个或多个"play"组成的列表
play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作
Playbook 文件是采用YAML语言编写的
Playbook 核心组件
1 hosts 组件
Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中
2 remote_user 组件
remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
3 task列表和action组件
play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致
每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。
如果未提供name,则action的结果将用于输出
task两种格式:
action: module arguments #示例: action: shell wall hello
module: arguments #建议使用 #示例: shell: wall hello
4 其它组件说明
某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers任务
还可以通过"tags"给task 打标签,可在ansible-playbook命令上使用-t指定进行调用
playbook 命令
ansible-playbook <filename.yml> ... [options]
--syntax-check #语法检查,可缩写成--syntax, 相当于bash -n
-C --check #模拟执行,只检测可能会发生的改变,但不真正执行操作,dry run
--list-hosts #列出运行任务的主机
--list-tags #列出tag
--list-tasks #列出task
--limit 主机列表 #只针对主机列表中的特定主机执行
-i INVENTORY #指定主机清单文件,通常一个项对应一个主机清单文件
--start-at-task START_AT_TASK #从指定task开始执行,而非从头开始,START_AT_TASK为任务的name
-v -vv -vvv #显示过程
忽略错误 ignore_errors
如果一个task出错,默认将不会继续执行后续的其它task,利用 ignore_errors: yes 可以忽略此task的错误,继续向下执行playbook其它task
---
- hosts: all
tasks:
- name: error
command: /bin/false
ignore_errors: yes
- name: ipaddress
shell: hostname -I
[root@centos7 data]# ansible-playbook ignore.yaml
PLAY [all] ******************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************
ok: [10.0.0.18]
ok: [10.0.0.27]
TASK [error] ****************************************************************************************************************
fatal: [10.0.0.27]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.001753", "end": "2022-06-30 17:05:05.410635", "msg": "non-zero return code", "rc": 1, "start": "2022-06-30 17:05:05.408882", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring
fatal: [10.0.0.18]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.001144", "end": "2022-07-01 01:05:03.116615", "msg": "non-zero return code", "rc": 1, "start": "2022-07-01 01:05:03.115471", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring
TASK [ipaddress] ************************************************************************************************************
changed: [10.0.0.27]
changed: [10.0.0.18]
PLAY RECAP ******************************************************************************************************************
10.0.0.18 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
10.0.0.27 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
handlers和notify
---
- hosts: all
remote_user: root
gather_facts: no
tasks:
- name: ip a
shell: ip a
notify:
- message
handlers:
- name: message
debug:
msg: this is handlers
[root@centos7 data]# ansible-playbook notify.yaml
PLAY [all] ******************************************************************************************************************
TASK [ip a] *****************************************************************************************************************
changed: [10.0.0.27]
changed: [10.0.0.18]
RUNNING HANDLER [message] ***************************************************************************************************
ok: [10.0.0.27] => {
"msg": "this is handlers"
}
ok: [10.0.0.18] => {
"msg": "this is handlers"
}
PLAY RECAP ******************************************************************************************************************
10.0.0.18 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.27 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
tags组件
在playbook文件中,可以利用tags组件,为特定 task 指定标签,当在执行playbook时,可以只执行特 定tags的task,而非整个playbook文件
可以一个task对应多个tag,也可以多个task对应一个tag
还有另外3个特殊关键字用于标签, tagged, untagged 和 all,它们分别是仅运行已标记,只有未标记和所 有任务。
---
- hosts: 10.0.0.27
remote_user: root
gather_facts: no
tasks:
- name: tags1
debug:
msg: this is tags1
tags:
- tags1
- name: tags2
debug:
msg: this is tags2
tags:
- tags2
- name: tags3
debug:
msg: this is tags3
tags:
- tags3
[root@centos7 data]# ansible-playbook --list-tags tags.yaml
playbook: tags.yaml
play #1 (10.0.0.27): 10.0.0.27 TAGS: []
TASK TAGS: [tags1, tags2, tags3]
[root@centos7 data]# ansible-playbook -t tags2 tags.yaml
PLAY [10.0.0.27] ************************************************************************************************************
TASK [tags2] ****************************************************************************************************************
ok: [10.0.0.27] => {
"msg": "this is tags2"
}
PLAY RECAP ******************************************************************************************************************
10.0.0.27 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@centos7 data]# ansible-playbook --skip-tags tags2 tags.yaml
PLAY [10.0.0.27] ************************************************************************************************************
TASK [tags1] ****************************************************************************************************************
ok: [10.0.0.27] => {
"msg": "this is tags1"
}
TASK [tags3] ****************************************************************************************************************
ok: [10.0.0.27] => {
"msg": "this is tags3"
}
PLAY RECAP ******************************************************************************************************************
10.0.0.27 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
playbook使用变量
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量调用方式: 通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效
变量来源:
1. ansible 的 setup facts 远程主机的所有变量都可直接调用
2. 通过命令行指定变量,优先级最高
ansible-playbook -e varname=value test.yml
3. 在playbook文件中定义
vars:
var1: value1
var2: value2
4. 在独立的变量YAML文件中定义
- hosts: all
vars_files:
- vars.yml
5. 在主机清单文件中定义
主机(普通)变量:主机组中主机单独定义,优先级高于公共变量
组(公共)变量:针对主机组中所有主机定义统一变量
6. 在项目中针对主机和主机组定义
在项目目录中创建 host_vars和group_vars目录
7. 在role中定义
变量的优先级从高到低如下
-e 选项定义变量 -->playbook中vars_files --> playbook中vars变量定义 -->host_vars/主机名文件 -->主机清单中主机变量--> group_vars/主机组名文件-->group_vars/all文件--> 主机清单组变量
使用 setup 模块中变量
本模块自动在playbook调用,不要用ansible命令调用,生成的系统状态信息, 并存放在facts变量中
facts 包括的信息很多,如: 主机名,IP,CPU,内存,网卡等
register注册变量
---
- hosts: 10.0.0.27
remote_user: root
gather_facts: no
tasks:
- name: register
shell: hostname
register: var
- name: print var
debug:
msg: "{{ var }}"
template
template功能:可以根据和参考模块文件,动态生成相类似的配置文件
template文件必须存放于templates目录下,且命名为 .j2 结尾
yaml/yml 文件需和templates目录平级,目录结构如下示例:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2
在.j2文件中可使用变量实现根据主机配置动态调整
例如:使用 ansible_processor_vcpus变量调整nginx配置
worker_processes {{ ansible_processor_vcpus }};
使用:
- name: template config
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能
{% for i in EXPR %}
...
{% endfor %}
示例:
{% for i in range(1,10) %}
server_name web{{i}};
{% endfor %}
定义一个列表变量,遍历列表,根据列表元素动态生成.j2文件
使用 if条件判断,决定是否生成相关的配置信息
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }} #注意缩进
{% endif %}
root {{ vhost.root }} #注意缩进
}
{% endfor %}
范例: 生成keepalived配置文件
vrrp_instrance VI_1 {
{% if ansible_fqdn == "ka1" %}
state MASTER
priority 100
{% elif ansible_fqdn == "ka2" %}
state SLAVE
priority 80
{% endif% }
......
}
使用循环迭代
迭代:当有需要重复性执行的任务时,可以使用迭代机制
迭代 with_items(loop) 对迭代项的引用,固定内置变量名为"item" 要在task中使用with_items给定要迭代的元素列表 注意: ansible2.5版本后,可以用loop代替with_items
---
- hosts: 10.0.0.27
remote_user: root
gather_facts: no
tasks:
- name: register
debug:
msg: "{{ item }}"
with_items:
- item1
- item2
- item3
[root@centos7 data]# ansible-playbook var.yaml
PLAY [10.0.0.27] ************************************************************************************************************
TASK [register] *************************************************************************************************************
ok: [10.0.0.27] => (item=item1) => {
"msg": "item1"
}
ok: [10.0.0.27] => (item=item2) => {
"msg": "item2"
}
ok: [10.0.0.27] => (item=item3) => {
"msg": "item3"
}
PLAY RECAP ******************************************************************************************************************
10.0.0.27 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在迭代中,还可以嵌套子变量,关联多个变量在一起使用
---
- hosts: 10.0.0.27
remote_user: root
gather_facts: no
tasks:
- name: register
user: name={{ item.name }} uid={{ item.uid }} system={{ item.system }}
with_items:
- {name: 'chen',uid: '1000',system: 'yes'}
when
when语句可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否 的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式
---
- hosts: 10.0.0.27
remote_user: root
tasks:
- name: os
debug: msg="centos7"
when: ansible_distribution_major_version == "7"
- name: os
debug: msg="centos8"
when: ansible_distribution_major_version == "8"
block:当满足条件时执行block分组的task
---
- hosts: 10.0.0.27
remote_user: root
tasks:
- block:
- debug: msg="centos7"
- debug: msg="centos7"
when:
ansible_facts['distribution_major_version'] == "7"
changed_when 检查task返回结果,决定是否继续向下执行
- name: check config
shell: /usr/sbin/nginx -t
register: check_nginx_config
changed_when:
- (check_nginx_config.stdout.find('successful')) #如果执行结果中有successful字符串,则继续执行,如果没有则停止向下执行
- false #nginx -t 每次成功执行是changed状态,关闭此changed状态
滚动执行
管理节点过多导致的超时问题解决方法
默认情况下,Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例,可以使用serial关键 字定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次并行执行的主机数 占总数的比例
- hosts: all
serial: 2 #每次只同时处理2个主机,将所有task执行完成后,再选下2个主机再执行所有task,直至所有主机
- name: test serail
hosts: all
serial: "20%" #每次只同时处理20%的主机
yaml文件的相互调用
利用include 或 include_tasks 可以在某个task中调用其它的只有task内容的yaml文件
也可以将多个包含完整内容的yml文件由一个yml统一调用
- name: excute b.yml
include: b.yml #调用另一个yaml文件
#include_tasks: b.yml #另一种写法
[root@ansible ansible]#cat total_tasks.yml
- import_playbook: tasks1.yml
- import_playbook: tasks2.yml
roles
用于层次性、结构化地组织playbook。roles能够根据层次型结 构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。 简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地 include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
roles:多个角色的集合目录, 可以将多个的role,分别放至roles目录下的独立子目录中
roles目录结构:
playbook1.yml
playbook2.yml
roles/
project1/
tasks/
files/
vars/
templates/
handlers/
default/
meta/
project2/
tasks/
files/
vars/
templates/
handlers/
default/
meta/
Roles各目录作用
roles/project/ :项目名称,有以下子目录
files/ :存放由copy或script模块等调用的文件
templates/:template模块查找所需要模板文件的目录
tasks/:定义task,role的基本元素,至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含
handlers/:至少应该包含一个名为main.yml的文件;此目录下的其它的文件需要在此文件中通过
include进行包含
vars/:定义变量,至少应该包含一个名为main.yml的文件;此目录下的其它的变量文件需要在此文件中通过include进行包含
meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需在此文件中通过include进行包含
default/:设定默认变量时使用此目录中的main.yml文件,比vars的优先级低
创建role的步骤
1 创建role的目录结构.在以roles命名的目录下分别创建以各角色名称命名的目录,如mysql等,在每个角色命名的目录中分别创建相关的目录和文件,比如tasks、files、handlers、templates和vars等目录;用不到的目录可以创建为空目录,也可以不创建
2 编写和准备role的功能文件
3 编写playbook文件调用需要的角色应用于指定的主机
利用 ansible-galaxy 创建角色目录的结构
ansible-galaxy init test_role
playbook 调用角色
---
- hosts: websrvs
remote_user: root
roles:
- mysql
- memcached
- nginx
---
- hosts: all
remote_user: root
roles:
- role: mysql
username: mysql
- { role: nginx, username: nginx }
---
- hosts: all
remote_user: root
roles:
- { role: nginx, username: nginx, when: ansible_distribution_major_version == '7' }
playbook安装二进制mysql
---
- hosts: 10.0.0.27
remote_user: root
gather_facts: no
tasks:
- name: intsall package
yum: name=libaio,numactl-libs
- name: add group
group: name=mysql
- name: add user
user: name=mysql group=mysql system=yes shell=/sbin/nologin
- name: unarchive mysql
unarchive: src=/data/mysql-5.7.33-linux-glibc2.12-x86_64.tar.gz dest=/usr/local/ copy=yes owner=root group=root
- name: create link
file: src=/usr/local/mysql-5.7.33-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link
- name: change PATH
shell: echo "PATH=/usr/local/mysql/bin:$PATH" >/etc/profile.d/mysql.sh
- name: mysql script
shell: source /etc/profile.d/mysql.sh
- name: create config
copy: content="[mysqld]\nserver-id=1\nlog-bin\ndatadir=/data/mysql\nsocket=/data/mysql/mysql.sock\nlog-error=/data/mysql/mysql.log\npid-file=/data/mysql/mysql.pid\n[client]\nsocket=/data/mysql/mysql.sock\n" dest=/etc/my.cnf
- name: initialize
shell: mysqld --initialize-insecure --user=mysql --datadir=/data/mysql
- name: create start script
shell: cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
- name: add mysqld
shell: chkconfig --add mysqld
- name: start mysql
service: name=mysqld state=started
测试
[root@centos7 data]# ansible-playbook install_mysql.yaml
PLAY [10.0.0.27] **************************************************************************************************************************************************************************
TASK [intsall package] ********************************************************************************************************************************************************************
ok: [10.0.0.27]
TASK [add group] **************************************************************************************************************************************************************************
ok: [10.0.0.27]
TASK [add user] ***************************************************************************************************************************************************************************
ok: [10.0.0.27]
TASK [create link] ************************************************************************************************************************************************************************
ok: [10.0.0.27]
TASK [change PATH] ************************************************************************************************************************************************************************
changed: [10.0.0.27]
TASK [mysql script] ***********************************************************************************************************************************************************************
changed: [10.0.0.27]
TASK [create config] **********************************************************************************************************************************************************************
ok: [10.0.0.27]
TASK [initialize] *************************************************************************************************************************************************************************
changed: [10.0.0.27]
TASK [create start script] ****************************************************************************************************************************************************************
changed: [10.0.0.27]
TASK [add mysqld] *************************************************************************************************************************************************************************
changed: [10.0.0.27]
TASK [start mysql] ************************************************************************************************************************************************************************
changed: [10.0.0.27]
PLAY RECAP ********************************************************************************************************************************************************************************
10.0.0.27 : ok=11 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@centos7 data]# ss -ant
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
ESTAB 0 0 10.0.0.27:22 10.0.0.17:53972
ESTAB 0 52 10.0.0.27:22 10.0.0.1:59397
LISTEN 0 80 [::]:3306 [::]:*
LISTEN 0 128 [::]:80 [::]:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
批量部署apache
---
- hosts: all
remote_user: root
tasks:
- name: install package
yum: name=gcc,make,pcre-devel,openssl-devel,expat-devel,bzip2 state=installed
- name: unarchive apr
unarchive: src=/data/apr-1.7.0.tar.bz2 dest=/data/ copy=yes
- name: unarchive apr-util
unarchive: src=/data/apr-util-1.6.1.tar.bz2 dest=/data/ copy=yes
- name: unarchive httpd2.4
unarchive: src=/data/httpd-2.4.46.tar.bz2 dest=/data/ copy=yes
- name: configuer apr
shell: chdir=/data/apr-1.7.0 ./configure --prefix=/app/apr && make && make install
- name: configuer apr-util
shell: chdir=/data/apr-util-1.6.1 ./configure --prefix=/app/apr-util --with-apr=/app/apr && make && make install
- name: configuer httpd
shell: chdir=/data/httpd-2.4.46 ./configure --prefix=/app/http2.4 --enable-so --enable-ssl --enable-cgi --enable-rewrite --with-zlib --with-pcre --with-apr=/app/apr --with-apr-util=/app/apr-util --enable-modules=most --enable-mpms-shared=all --with-mpm=prefork && make && make install
- name: create group
group: name=apache system=yes
- name: create user
user: name=apache group=apache system=yes shell=/sbin/nologin create_home=no
- name: change user
shell: grep -E "^User apache" /app/http2.4/conf/httpd.conf || sed -r -e "s/^User.*/User apache/" -e "s/^Group.*/Group apache/" /app/http2.4/conf/httpd.conf
- name: source PATH
shell: echo "PATH=/app/http2.4/bin:$PATH" > /etc/profile.d/httpd.sh && source /etc/profile.d/httpd.sh
- name: man
shell: echo "MANDATORY_MANPATH /app/http2.4/man " >> /etc/man_db.conf
- name: unit file
template: src=httpd.service.j2 dest=/usr/lib/systemd/system/httpd.service
- name: system-daemon
shell: systemctl daemon-reload
- name: start httpd
service: name=httpd state=started
- name: create index.html
template: src=index.html dest=/var/www/html/index.html
- name: start httpd
service: name=httpd state=started
[root@centos7 data]# cat templates/index.html
{{ ansible_default_ipv4.address }}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下