最新要闻
- 变天了!x86 PC陨落:ARM大暴走
- 高通憋出新大招:4G杀手来了
- 国美电器多个破产申请被驳回 苏泊尔在列
- 当前关注:脸都不要了!《黑棉花:悟能》无耻碰瓷《黑神话:悟空》
- Intel中国特供新U i7-13790F开卖:缓存多3MB 竟贵了150元!
- 最资讯丨吴京与粉丝合照被滤镜坑惨:没有明星能逃过美颜摧残
- 环球时讯:明天上映!《流浪地球2》发布港版预告片:MOSS竟然说英文
- 科大讯飞:类ChatGPT技术今年5月落地 AI学习机产品先用
- 天天速看:31.98万元!理想L7 Air发布:性能不变 无空气悬架
- 天天速读:三星S23 Ultra拍月亮100倍变焦的效果:把马斯克都惊艳到了
- 暴雪关停国服后 CEO发声:游戏行业被亚洲主宰 东西方竞争不平衡
- 累计交付27万台 李想:理想成为国内家庭消费者首选豪华SUV
- 世界最新:高通全球首发5G NR-Light基带:主打中端物联网、峰值速率220兆
- 城市行驶每公里仅1毛钱!理想L7出行成本不足宝马X5十分之一
- 宗申新款电动车闪电侠发布:续航超200公里 仪表盘可手机投屏
- 环球观速讯丨丢失两年的手机半夜仍被人试图解锁 被系统远程拍下照片
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
全球快播:Linux-ansible
集群自动化维护-必备工具-Ansible
一、概述
参考思维导图
自动化运维:批量管理,批量分发,批量执行,维护......
【资料图】
Ansible 是python写的
批量管理工具 | 说明 |
---|---|
Ansible | 无客户端,基于ssh进行管理与维护 |
Saltstack | 需要安装客户端,基于ssh进行管理,与ansible |
terraform | tf批量管理基础设施(主要用于创建公有云) |
二、Ansible管理架构
Inventory 主机清单:被管理主机的ip列表,分类
ad-hoc 模式:命令行批量管理(使用ansible模块),临时任务
playbook 剧本模式:类似把操作写成脚本,可以重复运行这个脚本
三、部署与配置
1.部署
[root@m01 ~]# yum -y install ansible
2.配置
[root@m01 ~]# egrep -vn "^#|^$" /etc/ansible/ansible.cfg 10:[defaults]#修改配置文件关机主机验证(就是远程连接时的yes/no):host_key_checking71:host_key_checking = False #解开注释即可#修改配置文件开启日志功能111:log_path = /var/log/ansible.log #解开注释即可327:[inventory]340:[privilege_escalation]346:[paramiko_connection]370:[ssh_connection]431:[persistent_connection]445:[accelerate]460:[selinux]469:[colors]485:[diff]
四、Ans-inventory 主机清单
什么是主机清单:让ansible管理的节点的列表
ansible 默认读取在/etc/ansible/hosts文件,并非/etc/hosts
实际使用中一般我们会把主机清单文件存放在指定的目录中,运行ansible的时候,通过-i来指定主机清单文件
1.主机清单必会格式
主机清单格式:[分类或分组的名字] #注意分类要体现出服务器的作用 分组:一般按照层次,功能,业务进行分组ip地址或主机名或域名 #注意主机名要能解析才行
#对主机分组并进行连接测试[root@m01 ~]# cat /etc/ansible/hosts [web]172.16.1.7[nfs]172.16.1.31[backup]172.16.1.41[root@m01 ~]# ansible all -m ping172.16.1.41 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong"}172.16.1.7 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong"}172.16.1.31 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong"}
ansible命令格式:
ansible 主机ip或分组或all -m 指定使用的模块名字
这里的ping模块用于检查被管理端是否可以访问
2.子组
#创建新的分组包含已有的分组backup和nfs[root@m01 ~]# cat /etc/ansible/hosts[web]172.16.1.7[nfs]172.16.1.31[backup]172.16.1.41[data:children]nfsbackup[root@m01 ~]# ansible data -m ping172.16.1.41 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong"}172.16.1.31 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong"}
子组使用children关键词创建
格式:
[data:children] #子组名字:children
3.指定用户,密码
不推荐,推荐先配置密钥认证,然后进行管理
#没有设置密钥认证,主机清单如何书写[root@m01 ~]# ssh 172.16.1.7 hostnameroot@172.16.1.7"s password: #172.16.1.7已经没有密钥认证[root@m01 ~]# cat /etc/ansible/hosts[web]172.16.1.7 ansible_user=root ansible_password=1 ansible_port=22 #书写格式[nfs]172.16.1.31[backup]172.16.1.41[data:children]nfsbackup[root@m01 ~]# ansible web -m ping172.16.1.7 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong"}
五、Ansible必知必会模块
1. ansible模块概述
- ansible中模块就类似于Linux中的命令,我们Linux命令管理系统,我们通过ansible模块实现批量管理
- ansible中模块一般相当于Linux中的一些命令,yum模块,file模块,user模块
- ansible中模块拥有不同的选项,这些选项一般都一些单词,拥有自己的格式与要求
参考官方文档:https://docs.ansible.com/ansible/latest/collections/ansible/builtin/index.html#plugins-in-ansible-builtin
模块分类 | 模块 |
---|---|
命令和脚本模块 | command模块,ansible默认的模块,执行简单的命令,不支持特殊符号 |
shell模块 执行命令,支持特殊符号 | |
script模块 分发脚本并执行 | |
文件 | file 创建目录,文件,软链接 |
copy 远程分发文件,修改权限,所有者,备份 | |
服务 | systemd服务管理 |
service 服务管理 | |
软件包 | yum_repository yum源 |
yum命令 | |
get_url 下载软件 | |
系统管理 | mount模块 挂载 |
cron模块 定时任务 | |
用户管理 | group模块 管理用户组 |
user模块 管理用户 | |
其他 | unarchive 压缩解压 |
synchronize rsync模块 | |
mysql_db,mysql_user 数据库模块 | |
ansible管理docker,k8s,zabbix,grafana | |
用于调试模块 | ping 模块检查,ansible与其他节点的联通性 |
debug 模块 用于检查/显示 变量 |
2. 命令格式
ansible | |||
---|---|---|---|
ansible | 主机清单(all/web/172.16.1.7) | -m 模块名 | -a 模块中的选项 |
-i 指定主机清单文件 | -m 指定模块 | -a 指定模块中的选项 |
温馨提示:
-a 选项的内容中如果有 " " ,那么-a 的 " " 要变成 " " ,或者内容中的变成 " "
3. 命令与脚本类模块
3.1 command模块
ansible默认的模块,适用于执行简单的命令,不支持特殊符号
#批量获取所有主机的主机名[root@m01 ~]# ansible web -m command -a "hostname"172.16.1.7 | CHANGED | rc=0 >>web01[root@m01 ~]# ansible web -a "hostname"172.16.1.7 | CHANGED | rc=0 >>web01
3.2 shell模块
与command模块类似,但是shell支持特殊符号
#批量删除/tmp/下面所有内容[root@m01 ~]# ansible web -m shell -a "rm -rf /tmp/*"[WARNING]: Consider using the file module with state=absent rather than running "rm". If you need to use command because file is insufficient you canadd "warn: false" to this command task or set "command_warnings=False" in ansible.cfg to get rid of this message.172.16.1.7 | CHANGED | rc=0 >>
注意事项:
-a 后边的命令不能用别名,如果有特殊符号要使用撬棍
温馨提示:
shell 模块不推荐执行较为复杂的指令,如果需要执行放在脚本中执行
避免因为特殊符号和引号导致的问题
3.3 script模块
执行流程:
分发脚本(传输脚本),在被管理端运行脚本
[root@m01 ~]# cat /server/scripts/ansible_script.sh #!/bin/bash#author: wh#desc: 系统巡检脚本hostname hostname -I ip a s eth0 |awk -F"[ /]+" "NR==3{print $3}"uptime whoami date +%Fsleep 5#执行脚本[root@m01 ~]# ansible web -m script -a "/server/scripts/ansible_script.sh"172.16.1.7 | CHANGED => { "changed": true, "rc": 0, "stderr": "Shared connection to 172.16.1.7 closed.\r\n", "stderr_lines": [ "Shared connection to 172.16.1.7 closed." ], "stdout": "web01\r\n10.0.0.7 172.16.1.7 \r\n10.0.0.7\r\n 17:30:35 up 14:57, 3 users, load average: 0.06, 0.15, 0.14\r\nroot\r\n2023-02-02\r\n", "stdout_lines": [ "web01", "10.0.0.7 172.16.1.7 ", "10.0.0.7", " 17:30:35 up 14:57, 3 users, load average: 0.06, 0.15, 0.14", "root", "2023-02-02" ]}#执行脚本被控端流程#把脚本先放在临时目录,执行完在删除[root@web01 ~]# ps -ef|grep ansibleroot 10621 10513 0 09:18 pts/2 00:00:00 /bin/sh -c /root/.ansible/tmp/ansible-tmp-1675300696.78-5875-246300159085630/ansible_script.sh && sleep 0root 10632 10621 0 09:18 pts/2 00:00:00 /bin/bash /root/.ansible/tmp/ansible-tmp-1675300696.78-5875-246300159085630/ansible_script.shroot 10642 10203 0 09:18 pts/1 00:00:00 grep --color=auto ansible[root@web01 ~]# cd /root/.ansible/tmp[root@web01 ~/.ansible/tmp]# lltotal 0
4.文件相关模块
4.1 file模块
file模块不仅可以管理文件,还可以管理目录,管理软链接
file模块相当于把touch命令,mkdir命令,rm命令,ln -s命令结合在一起
模块选项 | 说明 |
---|---|
path | 路径(目录,文件) |
src | source源,源文件一般用于link(创建软链接),用于指定源文件 |
state | 状态:具体要做什么,创建/删除,操作文件/操作目录state=directory 创建目录state=file (默认)更新文件,如果文件不存在也不创建state=link 创建软链接state=touch 创建文件state=absent 删除(如果是目录,递归删除目录) |
mode | 创建并修改权限 |
owner | 设置属主 |
group | 设置属组 |
#创建/opt/test.txt[root@m01 ~]# ansible web -m file -a "path=/opt/test.txt state=touch"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "dest": "/opt/test.txt", "gid": 0, "group": "root", "mode": "0644", "owner": "root", "size": 0, "state": "file", "uid": 0}[root@m01 ~]# ansible web -a "ls /opt/"172.16.1.7 | CHANGED | rc=0 >>test.txt#创建目录/test/a/b/c/[root@m01 ~]# ansible web -m file -a "path=/test/a/b/c/ state=directory"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "gid": 0, "group": "root", "mode": "0755", "owner": "root", "path": "/test/a/b/c/", "size": 6, "state": "directory", "uid": 0}[root@m01 ~]# ansible web -a "tree /test/"172.16.1.7 | CHANGED | rc=0 >>/test/└── a └── b └── c3 directories, 0 files#创建软连接 /etc/hosts创建软连接到/opt/下[root@m01 ~]# ansible web -m file -a "src=/etc/hosts path=/opt/hosts state=link"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "dest": "/opt/hosts", "gid": 0, "group": "root", "mode": "0777", "owner": "root", "size": 10, "src": "/etc/hosts", "state": "link", "uid": 0}[root@m01 ~]# ansible web -a "ls -l /opt/"172.16.1.7 | CHANGED | rc=0 >>total 0lrwxrwxrwx 1 root root 10 Feb 2 17:47 hosts -> /etc/hosts-rw-r--r-- 1 root root 0 Feb 2 17:43 test.txt#创建/ans-backup/目录 所有者是test,权限是700[root@m01 ~]# ansible web -m file -a "path=/ans-backup mode=700 owner=test state=directory"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "gid": 0, "group": "root", "mode": "0700", "owner": "test", "path": "/ans-backup", "size": 6, "state": "directory", "uid": 2001}[root@m01 ~]# ansible web -a "ls -ld /ans-backup"172.16.1.7 | CHANGED | rc=0 >>drwx------ 2 test root 6 Feb 2 17:49 /ans-backup#删除/test/目录[root@m01 ~]# ansible web -m file -a "path=/test/ state=absent"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "path": "/test/", "state": "absent"}[root@m01 ~]# ansible web -a "ls /test/"172.16.1.7 | FAILED | rc=2 >>ls: cannot access /test/: No such file or directorynon-zero return code
温馨提示:
查看模块帮助,可以通过 ansible-doc -s 模块名 来查看。
[root@m01 ~]# ansible-doc -s file
4.2 copy模块
批量分发:scp,1个节点(管理节点)发送文件或压缩包到所有被管理端。注意:copy是单向的传输
模块选项 | 说明 |
---|---|
src | source 源文件,管理端的某个文件 |
dest | destination 目标,被管理端的目录/文件 |
backup | backup=yes 会在覆盖前进行备份,文件内容要有变化与区别 |
mode | 修改权限 |
owner | 修改为指定的所有者 |
group | 修改为指定的用户组 |
#分发书写好的/etc/hosts文件,如果文件存在则备份下[root@m01 ~]# ansible web -m copy -a "src=/etc/hosts dest=/etc/hosts backup=yes"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "backup_file": "/etc/hosts.25211.2023-02-02@17:56:27~", "changed": true, "checksum": "665a4fa576811b11d78028074633acaddc8c292e", "dest": "/etc/hosts", "gid": 0, "group": "root", "md5sum": "b304c1bff962a2f1aaa79a4b5c618126", "mode": "0644", "owner": "root", "size": 334, "src": "/root/.ansible/tmp/ansible-tmp-1675331786.28-9824-177488215351037/source", "state": "file", "uid": 0}[root@web01 ~]# ll -d /etc/hosts*-rw-r--r-- 1 root root 334 Feb 2 17:56 /etc/hosts-rw-r--r-- 1 root root 330 Feb 2 10:38 /etc/hosts.25211.2023-02-02@17:56:27~ #备份文件
补充:
copy是推送,批量推送
fetch是拉取,批量拉取,使用较少
4.3 lineinfile
类似于sed "cai".
模块选项 | 说明 |
---|---|
path | 要修改的文件,指定文件 |
regexp | 修改正则匹配的内容,如果匹配多行,修改最后一行 |
line | 写入的内容 |
create | yes 如果文件不存在,进行创建 |
4.4 replace
类似于sed -i "sg"
4.5 unarchive
模块 | 说明 |
---|---|
creates | 一个文件名,当它已经存在时,这个步骤将不会被运行 |
copy | 默认为yes,拷贝的文件从ansible主机复制到远程主机,no在远程主机上寻找src源文件解压 |
src | tar源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需设置copy=no |
dest | 远程主机上的目标绝对路径 |
mode | 设置解压缩后的文件权限 |
exec | 列出需要排除的目录和文件 |
remote_src | 设置remote_src=yes为解包目标上已经存在的档案。对于Windows目标,改用win_unzip模块。 |
owner | 解压后文件或目录的属主 |
group | 解压后的目录或文件的属组 |
5.服务管理模块
systemd相当于Linux systemctl命令
systemd模块 | 说明 |
---|---|
name | 用于指定服务名称 |
enabled | yes开机自启动(yes/no) |
state | 表示服务开,关,重启...state=started 开启state=stopped 关闭state=reloaded 重读配置文件state=restarted 重启(关闭再开启) |
daemon-reload | yes是否重新加载对应的服务的管理配置文件 |
#开启firewalld服务并设置开机自启动[root@m01 ~]# ansible web -m systemd -a "name=firewalld enabled=yes state=started"[root@m01 ~]# ansible web -a "systemctl status firewalld"172.16.1.7 | CHANGED | rc=0 >>● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2023-02-02 19:02:37 CST; 49s ago Docs: man:firewalld(1) Main PID: 26620 (firewalld) CGroup: /system.slice/firewalld.service └─26620 /usr/bin/python2 -Es /usr/sbin/firewalld --nofork --nopidFeb 02 19:02:37 web01 systemd[1]: Starting firewalld - dynamic firewall daemon...Feb 02 19:02:37 web01 systemd[1]: Started firewalld - dynamic firewall daemon.Feb 02 19:02:37 web01 firewalld[26620]: WARNING: AllowZoneDrifting is enabled. This is considered an insecure configuration option. It will be removed in a future release. Please consider disabling it now.#关闭firewalld服务并不让开机自启动[root@m01 ~]# ansible web -m systemd -a "name=firewalld enabled=no state=stopped"[root@m01 ~]# ansible web -a "systemctl status firewalld"172.16.1.7 | FAILED | rc=3 >>● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled) Active: inactive (dead) Docs: man:firewalld(1)Feb 02 10:59:31 web01 systemd[1]: Starting firewalld - dynamic firewall daemon...Feb 02 10:59:33 web01 systemd[1]: Started firewalld - dynamic firewall daemon.Feb 02 10:59:34 web01 firewalld[13868]: WARNING: AllowZoneDrifting is enabled. This is considered an insecure configuration option. It will be removed in a future release. Please consider disabling it now.Feb 02 10:59:48 web01 systemd[1]: Stopping firewalld - dynamic firewall daemon...Feb 02 10:59:48 web01 systemd[1]: Stopped firewalld - dynamic firewall daemon.Feb 02 19:02:37 web01 systemd[1]: Starting firewalld - dynamic firewall daemon...Feb 02 19:02:37 web01 systemd[1]: Started firewalld - dynamic firewall daemon.Feb 02 19:02:37 web01 firewalld[26620]: WARNING: AllowZoneDrifting is enabled. This is considered an insecure configuration option. It will be removed in a future release. Please consider disabling it now.Feb 02 19:03:54 web01 systemd[1]: Stopping firewalld - dynamic firewall daemon...Feb 02 19:03:54 web01 systemd[1]: Stopped firewalld - dynamic firewall daemon.non-zero return code
补充:
systemd模块适用于目前大部分的Linux系统
service模块适用于管理旧的Linux系统
6.软件管理模块
6.1 yum模块
yum模块并不只是yum命令,包含了yum/apt命令
模块选项 | 说明 |
---|---|
name | 指定的软件包名字,可以指定多个,通过","分隔 |
state | installed 安装(也可以写为present)默认removed 删除 (也可以写为absent)lastest 安装或更新 |
update_cache | 可以设置为no,表示不更新本地yum缓存,这样下载快。实际应用建议开启 |
#安装常用的软件htop,tree,lrzsz,sshpass[root@m01 ~]# ansible web -m yum -a "name=tree,lrzsz"172.16.1.7 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "msg": "", "rc": 0, "results": [ "tree-1.6.0-10.el7.x86_64 providing tree is already installed", "lrzsz-0.12.20-36.el7.x86_64 providing lrzsz is already installed" ]}
6.2 get_url模块
相当于wegt命令,所有主机能访问网络才行
推荐在管理节点下载号,使用copy仅分发即可
模块选项 | 说明 |
---|---|
url | 指定要下载的地址 |
dest | 下载到哪个目录 |
#下载zabbix-agent的软包到/app/tools下面zabbix-agent地址为:https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm[root@m01 ~]# ansible web -m file -a "path=/app/tools state=directory"[root@m01 ~]# ansible web -m get_url -a "url="https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm" dest=/app/tools "172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "checksum_dest": null, "checksum_src": "19d3cab2ee9d0f69d0d8752165def185615c9607", "dest": "/app/tools/zabbix-agent-6.0.13-release1.el7.x86_64.rpm", "elapsed": 1, "gid": 0, "group": "root", "md5sum": "ee1fb29f984b12a1bb381e881293e154", "mode": "0644", "msg": "OK (543376 bytes)", "owner": "root", "size": 543376, "src": "/root/.ansible/tmp/ansible-tmp-1675337078.76-10471-19543799047354/tmpIEKEMp", "state": "file", "status_code": 200, "uid": 0, "url": "https://mirrors.aliyun.com/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.13-release1.el7.x86_64.rpm"}如果要安装,可以调用yum模块安装本地的软件name=/app/tools/zabbix-agent-6.0.13-release1.el7.x86_64.rpm
6.3 yum_repository模块
一般都是写好yum配置文件,copy分发过去,很少用这个模块
模块选项 | 说明 |
---|---|
name | yum源中的名字[epel] |
description | yum源的注释说明,对应的是name的内容 |
baseurl | yum源中的baseurl下载地址 |
enabled | 是否启动这个源yes/no |
gpgcheck | 是否启动gpgcheck功能 no |
file | 指定yum源的文件 自动添加.repo 默认与模块的名字一样 |
[root@web01 ~]# cat /etc/yum.repos.d/epel.repo [epel]name=Extra Packages for Enterprise Linux 7 - $basearchbaseurl=http://mirrors.aliyun.com/epel/7/$basearchfailovermethod=priorityenabled=1gpgcheck=0gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
yum配置文件内容 | yum源的模块的选项 |
---|---|
[epel] | name=epel #默认yum源文件的名字和这个一致 |
name=Extra Packages xxxxx | description="Extra Packages xxxxx" |
baseurl=http://mirrors.aliyun.com/epel/7/$basearch | baseurl="http://mirrors.aliyun.com/epel/7/$basearch" |
enabled=1 | enabled=yes |
gpgcheck=0 | gpgcheck=no |
[nginx-stable]name=nginx stable repobaseurl=http://nginx.org/packages/centos/$releasever/$basearch/gpgcheck=1enabled=1gpgkey=https://nginx.org/keys/nginx_signing.keymodule_hotfixes=true[root@m01 ~]# ansible web -m yum_repository -a "name=nginx description="nginx repo" baseurl="http://nginx.org/packages/centos/$releasever/$basearch/" gpgcheck=no enabled=yes"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "repo": "nginx", "state": "present"}[root@m01 ~]# ansible web -a "cat /etc/yum.repos.d/nginx.repo"172.16.1.7 | CHANGED | rc=0 >>[nginx]baseurl = http://nginx.org/packages/centos/$releasever/$basearch/enabled = 1gpgcheck = 0name = nginx repo
温馨提示:
nginx yum源的地址:http://nginx.org/en/linux_packages.html#RHEL
7.用户管理模块
7.1 user模块
相当于用户管理的useradd,userdel
模块选项 | 说明 |
---|---|
name | www 用户名 |
uid | 指定uid |
group | 指定用户组,一般用于事项创建好了用户组,通过选项指定 |
shell | 指定命令解释器:默认是/bin/bash |
create_home | 是否创建家目录(yes/no) |
state | present 添加absent 删除 |
password | 加密的密码 |
#创建www-ans用户uid 2000虚拟用户[root@m01 ~]# ansible web -m user -a "name=www-ans uid=2000 shell=/sbin/nologin create_home=no state=present"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "comment": "", "create_home": false, "group": 2000, "home": "/home/www-ans", "name": "www-ans", "shell": "/sbin/nologin", "state": "present", "system": false, "uid": 2000}[root@m01 ~]# ansible web -a "id www-ans"172.16.1.7 | CHANGED | rc=0 >>uid=2000(www-ans) gid=2000(www-ans) groups=2000(www-ans)
#批量更改密码[root@m01 ~]# ansible all -i localhost, -m debug -a "msg={{ "1" |password_hash("sha512","mima")}}"localhost | SUCCESS => { "msg": "$6$mima$/JbXK6m0czPNRNkpNqMoAI.5kk6XZBreAKaTpV1OFDd7YGXbUe2ySHgky2KaFnUKw7ghVY2G0zer5jhLWp3DT0"}#更新密码。密码为1[root@m01 ~]# ansible web -m user -a "name=test password={{ "1" |password_hash("sha512","mima")}} state=present"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "append": false, "changed": true, "comment": "", "group": 2001, "home": "/home/test", "move_home": false, "name": "test", "password": "NOT_LOGGING_PASSWORD", "shell": "/bin/bash", "state": "present", "uid": 2001}
补充:
关于{{ }}的解释
{{ "1" |password_hash("sha512","mima")}}
表示密码 1 ,经过管道,传递给了password_hash()插件,sha512加密算法,mima是随机字符用于生成随机加密后的密码
7.2 group模块
模块选项 | 说明 |
---|---|
name | 指定用户组的名字 |
gid | 指定组的gid |
state | present 添加absent 删除 |
8. mount 模块
实现mount命令进行挂载可以修改/etc/fstab实现永久挂载
模块选项 | 说明 |
---|---|
fstype | filesystem type 指定文件系统,xfs ,ext4, iso9660,nfs |
src | 源地址,nfs地址 |
path | 注意这里不是dest,挂载点(要把源挂载到哪里) |
state | 下表 |
mount模块的state参数可使用的值 | |
---|---|
absent | 卸载并修改fstab |
umounted | 卸载不修改/etc/fstab |
present | 仅修改/etc/fstab 不挂载 |
mounted | 挂载并修改/etc/fstab |
remounted | 重新挂载 |
# 通过ans管理在web01上挂载nfs:/data挂载到web01的/ans-upload/#在web服务器上安装nfs[root@m01 ~]# ansible web -m yum -a "name=nfs-utils state=present"#创建挂载点[root@m01 ~]# ansible web -m file -a "path=/ans-upload state=directory"#挂载nfs[root@m01 ~]# ansible web -m mount -a "src=172.16.1.31:/data/ path=/ans-upload fstype=nfs state=mounted"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "dump": "0", "fstab": "/etc/fstab", "fstype": "nfs", "name": "/ans-upload", "opts": "defaults", "passno": "0", "src": "172.16.1.31:/data/"}#检查[root@m01 ~]# ansible web -a "df -h"172.16.1.7 | CHANGED | rc=0 >>Filesystem Size Used Avail Use% Mounted ondevtmpfs 475M 0 475M 0% /devtmpfs 487M 0 487M 0% /dev/shmtmpfs 487M 26M 461M 6% /runtmpfs 487M 0 487M 0% /sys/fs/cgroup/dev/mapper/centos-root 17G 2.3G 15G 14% //dev/sda1 1014M 138M 877M 14% /boottmpfs 98M 0 98M 0% /run/user/0172.16.1.31:/data 17G 2.0G 16G 12% /ans-upload[root@m01 ~]# ansible web -a "grep upload /etc/fstab"172.16.1.7 | CHANGED | rc=0 >>172.16.1.31:/data/ /ans-upload nfs defaults 0 0#卸载[root@m01 ~]# ansible web -m mount -a "path=/ans-upload state=absent"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "dump": "0", "fstab": "/etc/fstab", "name": "/ans-upload", "opts": "defaults", "passno": "0"}
9.cron模块
用于管理系统的定时任务,替代了crontab -e
模块选项 | 说明 |
---|---|
name | 定时任务名字,一定要加上,对用注释 |
minute | 分钟 minute="*/2" |
hour | 小时 |
day | 日期 |
month | 月份 |
week | 周几 |
job | 指定命令或脚本(定向到空) |
state | present 添加定时任务(默认)absent 删除 |
# 每3分钟同步时间[root@m01 ~]# ansible web -m cron -a "name="3.ansible rsync time" minute="*/3" job="/sbin/ntpdate ntp1.aliyun.com &>/dev/null" state=present"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "envs": [], "jobs": [ "3.ansible rsync time" ]}[root@m01 ~]# ansible web -a "crontab -l"172.16.1.7 | CHANGED | rc=0 >>#1.配置时间同步*/2 * * * * /sbin/ntpdate ntp1.aliyun.com &>/dev/null#2.定时备份etc和定时任务* * * * * sh /server/scripts/conf_backup.sh &>/dev/null#Ansible: 3.ansible rsync time*/3 * * * * /sbin/ntpdate ntp1.aliyun.com &>/dev/null#删除定时任务[root@m01 ~]# ansible web -m cron -a "name="3.ansible rsync time" state=absent"172.16.1.7 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "envs": [], "jobs": []}[root@m01 ~]# ansible web -a "crontab -l"172.16.1.7 | CHANGED | rc=0 >>#1.配置时间同步*/2 * * * * /sbin/ntpdate ntp1.aliyun.com &>/dev/null#2.定时备份etc和定时任务* * * * * sh /server/scripts/conf_backup.sh &>/dev/null#清理已有的定时任务,不是ansible创建的ansible all -a "sed -i "/ntpdate/d" /var/spool/cron/root"
10. debug
用于调试
模块选项 | 说明 |
---|---|
msg | 输出提示 |
六、剧本
1.概述
剧本:
playbook文件,用于长久保存并且实现批量管理,维护,部署的文件,类似于脚本存放命令和变量
剧本yaml格式,yaml格式的文件:空格,冒号
ans剧本 | ans ad-doc | |
---|---|---|
共同点 | 批量使用,使用模块 | 批量管理,使用模块 |
区别 | 重复调用 | 不是很方便,不容易重复使用 |
应用场景 | 部署服务,多个步骤的任务 | 测试模块,临时性任务 |
2.剧本书写格式:
[root@m01 /server/scripts/playbook]# cat 1.show.yml ---#可以写可以不写- hosts: all#角色:play 指定你要管理的主机(主机清单里面的) tasks:#任务:tasks 具体要执行的模块 - name: 01 打开冰箱门 shell: echo 01 >>/tmp/bingxiang.log#模块: 根据你的操作流程,步骤选择模块 - name: 02 把大象放入冰箱 shell: echo 02 >>/tmp/bingxiang.log - name: 03 关上冰箱的门 shell: echo 03 >>/tmp/bingxiang.log #书写剧本,注意以.yml或.yaml结尾#执行剧本:[root@m01 /server/scripts/playbook]# cat hosts[web]172.16.1.7#[nfs]#172.16.1.31#[backup]#172.16.1.41#[data:children]#nfs#backup[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts 1.show.yml PLAY [all] *********************************TASK [Gathering Facts] *********************ok: [172.16.1.7]TASK [01 打开冰箱门] ****************************changed: [172.16.1.7]TASK [02 把大象放入冰箱] **************************changed: [172.16.1.7]TASK [03 关上冰箱的门] ***************************changed: [172.16.1.7]PLAY RECAP *********************************172.16.1.7 : ok=4 changed=3 unreachable=0 ailed=0 skipped=0 rescued=0 ignored=0
补充:
执行的时候显示奶牛
可以删除软件或修改ansible.cfg配置进行关闭
nocows=1 去掉注释即可
书写Ans playbook注意事项:
- 同一个层级的内容对齐
- 不同层级的通过2个空格对齐
- 不能使用tab键
3.剧本案例
一般步骤:
- 列出流程
- 找出每个步骤的命令
- 把上面的步骤与命令--->找出对应的ans模块
- 书写剧本
- 书写剧本前拍摄快照,边书写剧本边测试,最后测试完成,恢复快照,重新跑一次(分步测试,联合测试)
3.1 创建目录并分发文件
1. 创建目录/server/files/2. /etc/hosts文件发送过去/server/files/[root@m01 /server/scripts/playbook]# cat 2.fenfa.yml --- - hosts: all tasks: - name: 1.创建目录 file: path: /server/files/ state: directory - name: 2.分发文件 copy: src: /etc/hosts dest: /server/files
3.2 分发软件包,安装软件包,启动服务
1.zabbix-agent软件包(下载)2.安装软件包3.配置(略)4.启动开机自启动[root@m01 /server/scripts/playbook]# cat 3.zabbix.yml --- - hosts: all tasks: - name: 1.下载软件包 get_url: url: https://mirrors.tuna.tsinghua.edu.cn/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.7-1.el7.x86_64.rpm dest: /tmp/ validate_certs: no - name: 2.安装软件包 yum: name: /tmp/zabbix-agent-6.0.7-1.el7.x86_64.rpm state: present - name: 3.配置软件包 debug: msg: "进行配置zabbix-agent" - name: 4.启动软件包 systemd: name: zabbix-agent enabled: yes state: started
3.3 nfs 服务
nfs服务端:在backup上部署nfs服务,共享/backup-nfs目录,all_squash,匿名用户:nfsnobody
nfs客户端:web挂载 /ans-upload目录挂载nfs服务端共享的/backup-nfs(永久挂载)
服务端流程:1. 部署nfs-utils,rpcbind2. 修改配置文件3. 创建共享目录并改所有者4. 启动服务rpcbind,nfs(注意顺序)客户端流程:1. 安装nfs-utils2. 挂载与永久挂载[root@m01 /server/scripts/playbook]# cat 4.nfs-playbook.yml- hosts: backup tasks: - name: 部署nfs-utils,rpcbind yum: name: nfs-utils,rpcbind state: present - name: 修改配置文件 lineinfile: path: /etc/exports line: "/backup-nfs 172.16.1.0/24(rw,all_squash)" - name: 创建共享目录并改所有者 file: path: /backup-nfs state: directory owner: nfsnobody group: nfsnobody - name: 启动服务rpcbind systemd: name: rpcbind enabled: yes state: started - name: 启动服务nfs systemd: name: nfs enabled: yes state: started - hosts: web tasks: - name: 安装nfs-utils yum: name: nfs-utils state: present - name: 挂载与永久挂载 mount: src: 172.16.1.41:/backup-nfs path: /ans-upload fstype: nfs state: mounted
七、Ansible中的变量
变量无处不在,在ans中大部分的地方都可以定义变量
常用的创建变量的地方:剧本中,类似与 `` 功能,共用的变量文件
可以定义变量的地方 | 说明 |
---|---|
在剧本文件中的定义 | 比较常用,仅限于当前的play使用 |
register变量(注册变量) | 实现脚本中反引号的功能,可以获取命令结果 |
变量文件,根据主机清单分组进行定义变量 | 如果多个剧本,使用相同的变量 |
inventory主机清单中定义变量 | 用于批量修改主机使用, |
命令行中 | 几乎不用 |
facts变量 | 一般用于获取主机基本信息:ip,主机名,系统 |
1. 剧本中使用变量
#批量创建/test/a/b/c/d/[root@m01 /server/scripts/playbook]# cat 5.vars.yml - hosts: all vars: dir: /test/a/b/c/d/ tasks: - name: 创建目录 file: path: "{{ dir }}" state: directory注:vars: variable 变量的内容,变量dir就是一个变量,变量的内容就是右边的内容
温馨提示:
使用变量的时候如果变量是某个选项的开头,则变量引用的时候需要加上双引号
file:
path: "{{ dir }}" #这种要添加,变量是开头.
file:
path: /test/{{ dir }} #这种可以不加引号,变量不 是开头.
注意事项:
在剧本play中定义变量:
- 仅仅在当前play生效
- 一般用来存放路径,用户名,ip地址
- 注意引号的使用
2. 共用变量-变量文件
[root@m01 /server/scripts/playbook]# cat vars_file.yml user: wwwdir: /dest[root@m01 /server/scripts/playbook]# cat 6.vars_file.yml - hosts: all vars_files: ./vars_file.yml tasks: - name: 测试 debug: msg: "测试vars: {{ user }} {{dir}}" [root@m01 /server/scripts/playbook]# ansible-playbook -i hosts 6.vars_file.yml PLAY [all] ****************************TASK [Gathering Facts] ************************ok: [172.16.1.7]ok: [172.16.1.41]TASK [测试] *****************************ok: [172.16.1.7] => { "msg": "测试vars: www /dest"}ok: [172.16.1.41] => { "msg": "测试vars: www /dest"}PLAY RECAP ****************************172.16.1.41 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.1.7 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3. 共用变量- 根据主机组使用变量
group_vars根据主机清单的分组去匹配
变量文件
主机组创建变量文件
xxxx-check.ymlgroup_vars/ lb/vars.yml #存放lb组的变量 web/vars.yml #存放web组的变量 data/vars.yml #存放xxx组的变量 all/vars.yml #所有主机共用的变量 未来一般使用all分组即可,把所有变量存放在一起,供剧本使用.
[root@m01 /server/scripts/playbook]# mkdir -p group_vars/all[root@m01 /server/scripts/playbook]# cat group_vars/all/vars.yml user: wwwdir: /test[root@m01 /server/scripts/playbook]# cat 7.ans_group_vars.yml - hosts: all tasks: - name: 测试所有主机 debug: msg: "测试所有主机: {{ user }} {{ dir }}"- hosts: web tasks: - name: 测试web主机 debug: msg: "测试web主机: {{ user }}{{ dir }}"[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts 7.ans_group_vars.yml PLAY [all] ****************************TASK [Gathering Facts] ************************ok: [172.16.1.7]ok: [172.16.1.41]TASK [测试所有主机] *************************ok: [172.16.1.7] => { "msg": "测试所有主机: www /test"}ok: [172.16.1.41] => { "msg": "测试所有主机: www /test"}PLAY [web] ****************************TASK [Gathering Facts] ************************ok: [172.16.1.7]TASK [测试web主机] ************************ok: [172.16.1.7] => { "msg": "测试web主机: www/test"}PLAY RECAP ****************************172.16.1.41 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
温馨提示:
group_vars应用提示:
-般使用group_vars中all分组
4. register 变量注册变量
本质上就是用来实现脚本的反引号功能
用户通过命令获取的内容都存放到register变量中
某个register变量的信息 "msg": { "changed": true, "cmd": "date +%F", "delta": "0:00:00.004257", "end": "2023-02-04 15:17:24.290526", "failed": false, "rc": 0, "start": "2023-02-04 15:17:24.286269", "stderr": "", "stderr_lines": [], "stdout": "2023-02-04", "stdout_lines": [ "2023-02-04" ] }[root@m01 /server/scripts/playbook]# cat 8.reg.yml - hosts: web tasks: - name: get date shell: date +%F register: result - name: 打印result内容 debug: msg: "{{ result.stdout }}"[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts 8.reg.yml PLAY [web] *********************************TASK [Gathering Facts] *********************ok: [172.16.1.7]TASK [get date] ****************************changed: [172.16.1.7]TASK [打印result内容] **************************ok: [172.16.1.7] => { "msg": "2023-02-04"}PLAY RECAP *********************************172.16.1.7 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
补充:
register注册变量
变量名.stdout获取输出
json形式数据.
key: value
键: 值 变量:
内容 date +%F
stdout部分是我们想要的内容.
register变量result.
result.stdout #std standard output 标准输出
5. facts变量
- ans内置变量,ans运行剧本的时候会有一个默认的task(Gathering Facts)
- 运行剧本的时候ans会收集每个主机的基本信息,这些信息形成的变量叫做fact变量
- fatcs变量setup模块获取
#查看fact变量[root@m01 /server/scripts/playbook]# ansible web -m setup [root@m01 /server/scripts/playbook]# cat 9.facts.yml - hosts: web tasks: - name: 测试 debug: msg: | 系统ip是{{ ansible_default_ipv4.address }} 系统主机名是{{ ansible_hostname }} 系统是{{ ansible_distribution }} 系统版本是{{ ansible_distribution_version }}[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts 9.facts.yml PLAY [web] *********************************TASK [Gathering Facts] *********************ok: [172.16.1.7]TASK [测试] **********************************ok: [172.16.1.7] => { "msg": "系统ip是10.0.0.7\n系统主机名是web01\n系统是CentOS\n系统版本是7.9\n"}PLAY RECAP *********************************172.16.1.7 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 常用fact变量ansible_hostname #主机名ansible_memtotal_mb #内存大小(总计) 单位mbansible_processor_vcpus #cpu数量ansible_default_ipv4.address #默认的网卡ip eth0ansible_distribution #系统发行版本名字ansible_processor_vcpusansible_processor_coresansible_date_time.date
应用建议:
- 通过facts变量获取系统的基本信息
- 通过facts变量获取信息并进行判断
- 如果不需要可以进行关闭,加速剧本的运行( gather_facts: no)
八、流程控制
1. handlers触发器
应用场景:
一般用于分发配置文件的时候,如果文件发生变化则重启服务,如果没有变化则不重启
[root@m01 /server/scripts/playbook]# cat hosts [web]172.16.1.7[nfs]172.16.1.31#[backup]#172.16.1.41[ubuntu]10.0.0.100#[data:children]#nfs#backup##[rsync_client:children]#web#nfs[root@m01 /server/scripts/playbook]# cat 10.handler.yml - hosts: nfs gather_facts: no tasks: - name: 分发文件 copy: src: exports dest: /etc/exports backup: yes notify: - 重启服务 handlers: - name: 重启服务 systemd: name: nfs state: reloaded #修改文件之后执行结果 [root@m01 /server/scripts/playbook]# ansible-playbook -i hosts 10.handler.yml PLAY [nfs] *********************************TASK [分发文件] ********************************changed: [172.16.1.31]RUNNING HANDLER [重启服务] *********************changed: [172.16.1.31]PLAY RECAP *********************************172.16.1.31 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #没有修改文件结果[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts 10.handler.yml PLAY [nfs] *********************************TASK [分发文件] ********************************ok: [172.16.1.31]PLAY RECAP *********************************172.16.1.31 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
补充:
格式:
埋雷:设置绊雷(notify: 写个名字) , handlers设置名字和模块
注意事项
- handlers放在剧本的最后,否则都会被识别为handlers
- notify的名字要和handlers的名字一样
2. when判断
用于给ans运行的task模块设置条件,满足或不满足条件在运行对应的模块(不满足条件的主机提示skip)
应用建议
when进行判断,一般facts变量或register变量一起使用
#CentOS安装sl,tree Ubuntu安装 cmatrix,lolcat[root@m01 /server/scripts/playbook]# cat 11.when.yml - hosts: all tasks: - name: CentOS安装sl,tree yum: name: sl,tree state: present when: ansible_distribution == "CentOS" - name: Ubuntu安装 cmatrix,lolcat apt: name: cmatrix,lolcat state: present when: ansible_distribution == "Ubuntu" [root@m01 /server/scripts/playbook]# ansible-playbook -i hosts 11.when.yml PLAY [all] *********************TASK [Gathering Facts] *********************ok: [172.16.1.7]ok: [172.16.1.31]ok: [10.0.0.100]TASK [CentOS安装sl,tree] *********************skipping: [10.0.0.100]ok: [172.16.1.7]ok: [172.16.1.31]TASK [Ubuntu安装 cmatrix,lolcat] *********************skipping: [172.16.1.7]skipping: [172.16.1.31]ok: [10.0.0.100]PLAY RECAP *********************10.0.0.100 : ok=2 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 172.16.1.31 : ok=2 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 172.16.1.7 : ok=2 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
when中使用的符号==等于!=不等于is match(web)ansible_hostname is match("web|backup") #类似于grep,正则.ansible_hostname is not match("web|backup") #取反,排除.
3.循环
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html
- with_* :with_item
- loop
#批量启动nfs,crond[root@m01 /server/scripts/playbook]# cat 12.loop.yml - hosts: web tasks: - name: 重启nfs,crond systemd: name: "{{ item }}" state: restarted #with_items: loop: - nfs - crond#循环与多个变量[root@m01 /server/scripts/playbook]# cat 13.loop_vars.yml - hosts: web gather_facts: no tasks: - name: add user user: name: "{{ item.name }}" uid: "{{ item.uid }}" shell: /bin/bash state: present loop: - { name: "test1",uid: 2011} - { name: "test2",uid: 2012}
九、剧本调试
1. 检查语法与单步执行
-C --check 模拟运行,不做出改变。一些变量可能会提示报错。因为-C没有真正运行剧本。有些变量获取不到
--syntax-check 只做语法检查,不运行
--step 单步运行,y执行这个task,n忽略这个task,c自动运行
[root@m01 /server/scripts/playbook]# cat 2.fenfa.yml --- - hosts: web tasks: - name: 1.创建目录 file: path: /server/files/ state: directory - name: 2.分发文件 copy: src: /etc/hosts dest: /server/files#-C[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts -C 2.fenfa.yml PLAY [web] *********************TASK [Gathering Facts] *********************************************************ok: [172.16.1.7]TASK [1.创建目录] *********************ok: [172.16.1.7]TASK [2.分发文件] *********************ok: [172.16.1.7]PLAY RECAP *********************172.16.1.7 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts --syntax-check 2.fenfa.yml playbook: 2.fenfa.yml#--step[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts --step 2.fenfa.yml PLAY [web] *********************Perform task: TASK: Gathering Facts (N)o/(y)es/(c)ontinue: yPerform task: TASK: Gathering Facts (N)o/(y)es/(c)ontinue: *********************TASK [Gathering Facts] *********************************************************ok: [172.16.1.7]Perform task: TASK: 1.创建目录 (N)o/(y)es/(c)ontinue: cPerform task: TASK: 1.创建目录 (N)o/(y)es/(c)ontinue: ******************************TASK [1.创建目录] ******************************************************************ok: [172.16.1.7]TASK [2.分发文件] ******************************************************************ok: [172.16.1.7]PLAY RECAP *********************172.16.1.7 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2. tag标签
tag标签类似于超市物品的分类,只不过tag标签是给ansible中的task进行分类,加上标记
运行剧本的时候运行指定的tag标签或排除某些tag
[root@m01 /server/scripts/playbook]# cat 14.tags.yml - hosts: nfs tasks: - name: 01. 部署nfs-utils,rpcbind yum: name: nfs-utils,rpcbind state: present tags: - 01.install - name: 02. 修改配置文件 lineinfile: path: /etc/exports line: "/backup-nfs 172.16.1.0/24(rw,all_squash)" create: true tags: - 02.conf - name: 03. 创建共享目录并改所有者 file: path: /backup-nfs owner: nfsnobody group: nfsnobody state: directory tags: - 03.dir - name: 04. 启动服务rpcbind,nfs(注意顺序) systemd: name: "{{ item }}" enabled: yes state: started loop: - rpcbind - nfs tags: - 04.start_srv #list-tags显示剧本中所有的tags标签[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts --list-tags 14.tags.yml playbook: 14.tags.yml play #1 (nfs): nfsTAGS: [] TASK TAGS: [01.install, 02.conf, 03.dir, 04.start_srv]#运行剧本的时候#-t 运行的标签,如果多个标签通过","分割#skip-tags 排除指定的tags,如果多个标签通过","分割[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts -t 04.start_srv 14.tags.yml PLAY [nfs] *********************TASK [Gathering Facts] *********************ok: [172.16.1.31]TASK [04. 启动服务rpcbind,nfs(注意顺序)] *********************ok: [172.16.1.31] => (item=rpcbind)ok: [172.16.1.31] => (item=nfs)PLAY RECAP *********************172.16.1.31 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3.忽略错误
运行剧本的时候,因为重复运行导致的错误提示,并发是真的错误.
比如:目录已经存在,用户已经存在.
在这种情况下,我们可以通过ignore_errors忽略错误,让剧本可以继续运行.
ignore_errors: true true/falseyes/no
十、 Jinja2模板
应用场景:
进行分发配置文件或文件的时候,需要在文件中使用变量,需要使用jinja2文件,需要使用template分发
1.基本使用
#分发motd文件,motd文件中包含ans变量(目标文件是/etc/motd).[root@m01 /server/scripts/playbook]# cat 15.jinja2.yml - hosts: web tasks: - name: 分发motd template: src: motd.j2 dest: /etc/motd backup: yes[root@m01 /server/scripts/playbook]# cat motd.j2 welcome to oldboy elastic linux system操作需谨慎,删根弹指间.主机名: {{ ansible_hostname }}ip地址: {{ ansible_default_ipv4.address }}内存大小: {{ ansible_memtotal_mb }}CPU数量: {{ ansible_processor_vcpus }}核心总数: {{ ansible_processor_cores }}发行版本: {{ ansible_distribution }}[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts 15.jinja2.yml PLAY [web] *****************************************TASK [Gathering Facts] *****************************ok: [172.16.1.7]TASK [分发motd] **************************************ok: [172.16.1.7]PLAY RECAP *****************************************172.16.1.7 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [root@m01 /server/scripts/playbook]# ssh 172.16.1.7Last login: Mon Feb 6 17:15:03 2023 from 172.16.1.61welcome to oldboy elastic linux system操作需谨慎,删根弹指间.主机名: web01ip地址: 10.0.0.7内存大小: 972CPU数量: 1核心总数: 1发行版本: CentOS[root@web01 ~]# cat /etc/motdwelcome to oldboy elastic linux system操作需谨慎,删根弹指间.主机名: web01ip地址: 10.0.0.7内存大小: 972CPU数量: 1核心总数: 1发行版本: CentOS
2.判断使用
根据主机名或ip或其他条件,生成不同的配置文件
/tmp/keepalived.conflb01lb02配置文件内容/tmp/keepalived.confweb01 配置文件内容state MASTER/tmp/keepalived.confbackup 配置文件内容state BACKUP[root@m01 /server/scripts/playbook]# cat 15.jinja2-if.yml- hosts: all tasks: - name: 分发配置文件 template: src: templates/keepalived.conf.j2 dest: /tmp/keepalived.conf[root@m01 /server/scripts/playbook]# tree templates/templates/├── keepalived.conf.j2└── motd.j20 directories, 2 files[root@m01 /server/scripts/playbook]# cattemplates/keepalived.conf.j2#this is keepalived.conf{% if ansible_hostname "web01" %} state 主节点{% elif ansible_hostname "backup" %} state 备节点{% endif %}[root@m01 /server/scripts/playbook]#
3.循环
配置文件 server.conf web服务器的/tmp/目录下10.0.0.510.0.0.610.0.0.710.0.0.810.0.0.910.0.0.10{% for ip in [1,2,3,4,5,6] %} 10.0.0.{{ ip }}{% endfor %}{% for ip in range(2,11) %} 10.0.0.{{ ip }}{%endfor%}{% for ip in ["lidao","oldwang"] %} 10.0.0.{{ ip }}{%endfor%}
十一、include文件包含
在我们书写剧本的时候,会涉及到多个步骤,还会涉及到服务端和客户端.
发现剧本越来越大,不容易进行分析与阅读.
把剧本拆分开,分成2个文件服务端,客户端.
这时候可以通过include_tasks的功能把多个剧本文件合并在一起,让剧本变成多个方便阅读与维护.
应用场景:
1个ansible剧本内容过多,涉及到多个play,可读性变弱,不方便测试
于是把单个大的剧本拆分成多个,小的剧本
多个小的剧本可以通过include功能合并使用
[root@m01 /server/scripts/playbook]# cat 16.deploy_nfs_server.yml- name: 部署nfs-utils,rpcbind yum: name: nfs-utils,rpcbind state: present- name: 修改配置文件 lineinfile: path: /etc/exports line: "/backup-nfs 172.16.1.0/24(rw,all_squash)"- name: 创建共享目录并改所有者 file: path: /backup-nfs state: directory owner: nfsnobody group: nfsnobody - name: 启动服务rpcbind systemd: name: rpcbind enabled: yes state: started- name: 启动服务nfs systemd: name: nfs enabled: yes state: started [root@m01 /server/scripts/playbook]# cat 16.deploy_nfs_client.yml - name: 安装nfs-utils yum: name: nfs-utils state: present- name: 挂载与永久挂载 mount: src: 172.16.1.41:/backup-nfs path: /ans-upload fstype: nfs state: mounted[root@m01 /server/scripts/playbook]# cat 16.deploy_nfs_all.yml - hosts: backup tasks: - include_tasks: 16.deploy_nfs_server.yml- hosts: web tasks: - include_tasks: 16.deploy_nfs_client.yml
十二、roles
roles官网
通过使用include_tasks功能,大型剧本,缩小体积,变的更加模块化
但是有新问题,handlers,变量文件,发送配置文件(j2文件)存放比较混乱
于是人们发明了一套规范,这个规范是一套剧本目录结构的要求与标准,让书写剧本的时候,把剧本的内容和需要的文件,按照目录的要求,分类别存储
这套规则,叫roles规则,roles的本质是规定了1套目录结构,用于书写剧本
roles/目录top.yml #主剧本/入口剧本hosts#主机清单 -i hostsnfs-server/#功能files/ #files目录存放配置文件,剧本中使用的文件的目录,默认在files下面templates/ #存放.j2文件,templatetasks/#剧本中tasks内容存放在这个目录中main.ymlhandlers/#存放触发器内容main.ymlgroup_vars#存放变量allmain.yml
十三、 Vault
加密指定的文件,ansible-vault 用于加密敏感信息
hosts 文件
变量文件
这两个文件一般加密
#加密文件[root@m01 /server/scripts/playbook]# ansible-vault encrypt hosts New Vault password: Confirm New Vault password: Encryption successful[root@m01 /server/scripts/playbook]# cat hosts $ANSIBLE_VAULT;1.1;AES256646162346164633237613633373736366638666231633765643664643836383834623636613835316435356439356538616465316435386539323930626136300a383462323035313731333730656132613638356234393230363863623766653339343564316233373637663832303133326335336566303466623338363035310a6236653061323136663430313065363036366161636138393765303066363162366638306361336263313262616461643935323034313465656466393438303366613863333535643636313736393431386338643434653431303536386132633837386237363235613639346363343666313662313261343336366338346463653833373631326264303764353663366536393138346439366433333039636338643065393432663364306133613034633265313064356633663561336239323366326332343638396135663466616437303663313561633130363461623732343432343866346436373164636332333662346165336634343766303661303136396333323133623431623439643333633561376135636631643735393465393566636263613566383534343735333831356531346465663161666132336630[root@m01 /server/scripts/playbook]# ansible -i hosts web -m ping[WARNING]: * Failed to parse /server/scripts/playbook/hosts with yaml plugin: Attempting to decrypt but no vault secrets found[WARNING]: * Failed to parse /server/scripts/playbook/hosts with ini plugin: Attempting to decrypt but no vault secrets found[WARNING]: Unable to parse /server/scripts/playbook/hosts as an inventory source[WARNING]: No inventory was parsed, only implicit localhost is available[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match "all"[WARNING]: Could not match supplied host pattern, ignoring: web#使用时加--ask-vault-pass[root@m01 /server/scripts/playbook]# ansible -i hosts web --ask-vault-pass -m pingVault password: 172.16.1.7 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong"}#解密文件[root@m01 /server/scripts/playbook]# ansible-vault decrypt hostsVault password: Decryption successful[root@m01 /server/scripts/playbook]# cat hosts[web]172.16.1.7[nfs]172.16.1.31[backup]172.16.1.41[ubuntu]10.0.0.100#[data:children]#nfs#backup##[rsync_client:children]#web#nfs
十四、 Galaxy
官网
#官网人家写好的nginx的rolesansible-galaxy collection install nginxinc.nginx_core
十五、优化
性能:
ssh连接速度优化
UseDNS no #相当于网络命令的-n选项.GSSAPIAuthentication no #关闭GSS认证.
不要让ansible运行交互式命令
需要使用ansible,yum安装软件,可以自建本地yum仓库,然后ansible安装(自建yum源,自己制作的rpm包)
调整ansible并发数量,实际调整根据负载情况进行
-f 调整并发数量,默认是5
/etc/ansible/ansible.cfg 中 forks= 5
给ansible配置缓存(redis),队列,缓存facts
给主机进行分组操作与管理
关闭 gather_facts,如果不用facts变量可以关闭
剧本中: gather_facts: false
配置文件中:gathering = explicit
关闭host,key,check 一般使用密码认证的时候需要关闭,如果不关闭
配置文件中:host_key_checking = False
安全:
配置sudo用户
先在被管理端新增ansible用户,ans ALL=(ALL) NOPASSWD: ALL
配合vpm,jms一起使用
用户--->vpn--->jms--->ansible
用户密码,进行加密(hash,ansible-vault)
#配置sudo[root@m01 /server/scripts/playbook]# egrep -v "^$|#"/etc/ansible/ansible.cfg[defaults]sudo_user = ans 被管理端上具有sudo权限的用户nopasswd: ALLremote_user = ans 被管理端使用的用户,不指定默认是当前用户/rootremote_port = 22 被管理端ssh端口号host_key_checking = Falselog_path = /var/log/ansible.log[inventory][privilege_escalation]become=True 开启sudo功能become_method=sudo 使用sudo命令become_user=root 普通用户切换为root[paramiko_connection][ssh_connection][persistent_connection][accelerate][selinux][colors][diff]被管理端:ans ALL=(ALL) NOPASSWD: ALL` 密码是1,ssh端口是 22重新分发密钥给ans普通用户.ssh-copy-id ans@10.0.0.7测试ansible -i hosts web -m ping
#新增用户[root@m01 /ansible/roles]# cat add_ans.yml - hosts: all tasks: - name: "新增ans用户" user: name: ans shell: /bin/bash state: present - name: "设置密码" shell: "echo 2|passwd --stdin ans"#分发秘钥 [root@m01 /ansible/roles]# cat fenfa_ans.sh #!/bin/bash#author: wh#version: v2 #desc: 一键创建秘钥对 分发秘钥对 #1.varsuser=anspass=2ips="172.16.1.7 172.16.1.31 172.16.1.41". /etc/init.d/functions#1.4 判断是否联网或是否可以使用yum#1.5 加入判断sshpass命令是否存在,如果不存在则安装#2.创建秘钥对if [ -f ~/.ssh/id_rsa ] ;then echo "已经创建过秘钥对"else echo "正在创建秘钥对...." ssh-keygen -t rsa -f ~/.ssh/id_rsa -P "" &>/dev/null if [ $? -eq 0 ];then action "密钥创建成功" /bin/true else action "密钥创建失败" /bin/false fifi#3.通过循环发送公钥for ip in $ips do sshpass -p${pass} ssh-copy-id -i ~/.ssh/id_rsa.pub -oStrictHostKeyChecking=no ${user}@$ip &>/dev/null if [ $? -eq 0 ];then action "$ip 公钥分发 成功" /bin/true else action "$ip 公钥分发 失败" /bin/false fidone[root@m01 /ansible/roles]# sh fenfa_ans.sh 已经创建过秘钥对172.16.1.7 公钥分发 成功 [ OK ]172.16.1.31 公钥分发 成功 [ OK ]172.16.1.41 公钥分发 成功 [ OK ]#被控制端[root@nfs ~]# visudoans ALL=(ALL) NOPASSWD: ALL #第100行新增#修改为root不允许登录[root@web01 ~]# grep RootLogin /etc/ssh/sshd_configPermitRootLogin no#重启远程[root@web01 ~]# systemctl restart ssh#这个时候提示权限不足[root@m01 /ansible/roles]# ansible -i hosts web -m ping172.16.1.7 | UNREACHABLE! => { "changed": false, "msg": "Failed to connect to the host via ssh: Permission denied (publickey,password).", "unreachable": true}#管理端修改位置[root@m01 ~]# egrep -v "^$|^#" /etc/ansible/ansible.cfg [defaults]sudo_user = ans #取消注释,修改用户名remote_user = ans#新增这一行,就不要用下边的了remote_port = 22#取消注释host_key_checking = Falselog_path = /var/log/ansible.lognocows = 1[inventory][privilege_escalation]become=True#取消注释become_method=sudo#取消注释become_user=root#取消注释[paramiko_connection][ssh_connection][persistent_connection][accelerate][selinux][colors][diff][root@m01 /ansible/roles]# ansible -i hosts web -m ping172.16.1.7 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong"}
案例:
书写nfs部署剧本:服务端,客户端书写rsync部署剧本:服务端,客户端(定时任务 + 脚本)书写sersync部署剧本(存储服务器上).nfs服务端:nfs安装rpcbind,nfs-utils创建共享目录,修改属主属组 /data修改配置文件启动rpcbind启动nfsnfs 客户端:web安装nfs-utils挂载目录 /uploadrsync服务端:backup安装rsync配置rsync创建用户创建共享目录,修改属组属主 /backup创建密码文件并写入密码修改权限 rsync.password启动rsyncrsync客户端:nfs,web安装rsync分发备份脚本 back-conf.sh分发密码文件,修改权限为600 创建定时任务sersync服务端: nfs创建软件目录解压软件包移动bin目录拷贝配置文件创建快捷方式启动服务sersync客户端: backup创建备份目录,修改属主属组 /nfsbackup rsync[root@m01 /server/scripts/playbook]# cat group_vars/all/vars.yml user: wwwgroup: wwwnfs_dir: /dataweb_nfs_dir: /uploadrsync_dir: /backupsersync_dir: /nfsbackup[root@m01 /server/scripts/playbook/file]# lltotal 728-rw-r--r-- 1 root root 780 Feb 4 16:43 back-conf.sh-rwxr-xr-x 1 root root 2219 Feb 4 15:24 confxml.xml-rw------- 1 root root 2 Feb 4 15:40 rsync.client-rw-r--r-- 1 root root 561 Feb 4 15:32 rsyncd.conf-rw-r--r-- 1 root root 727290 Feb 4 15:23 sersync2.5.4_64bit_binary_stable_final.tar.gz[root@m01 ~]# cat /server/scripts/playbook/9.ansible_nfs_rsync_sersync.yml #nfs服务端- hosts: nfs tasks: - name: 安装rpcbind,nfs-utils yum: name: rpcbind,nfs-utils state: present - name: 创建共享目录,修改属主属组 file: path: "{{ nfs_dir }}" state: directory owner: nfsnobody group: nfsnobody - name: 修改配置文件 lineinfile: path: /etc/exports line: "/data/ 172.16.1.0/24(rw)" create: yes - name: 启动rpcbind systemd: name: rpcbind enabled: yes state: started - name: 启动nfs systemd: name: nfs enabled: yes state: started#nfs客户端- hosts: web tasks: - name: 安装nfs-utils yum: name: nfs-utils state: present - name: 挂载目录 mount: src: 172.16.1.31:/data path: "{{ web_nfs_dir }}" fstype: nfs state: mounted#rsync服务端 - hosts: backup tasks: - name: 安装rsync yum: name: rsync state: present - name: 配置rsync copy: src: ./file/rsyncd.conf dest: /etc/rsyncd.conf - name: 创建用户 user: name: rsync create_home: no shell: /sbin/nologin - name: 创建共享目录,修改属组属主 /backup file: path: "{{ rsync_dir }}" state: directory owner: rsync group: rsync - name: 创建密码文件并写入密码修改权限 lineinfile: path: /etc/rsync.password line: rsync_backup:1 create: yes mode: 600 - name: 启动rsync systemd: name: rsyncd enabled: yes state: started#rsync客户端- hosts: rsync_client tasks: - name: 安装rsync yum: name: rsync state: present - name: 分发备份脚本 copy: src: ./file/back-conf.sh dest: /server/scripts/back-conf.sh - name: 分发密码文件 copy: src: ./file/rsync.client dest: /etc/rsync.client mode: 600 - name: 创建定时任务 cron: name: backup conf minute: "*/2" job: sh /server/scripts/back-conf.sh &>/dev/null state: present#sersync服务端- hosts: nfs tasks: - name: 创建bin目录 file: path: /app/tools/sersync/bin/ state: directory - name: 创建conf目录 file: path: /app/tools/sersync/conf/ state: directory - name: 解压sersync2.5.4_64bit_binary_stable_final.tar.gz unarchive: src: ./file/sersync2.5.4_64bit_binary_stable_final.tar.gz dest: /root/ - name: 移动目录 shell: "mv GNU-Linux-x86/sersync2 /app/tools/sersync/bin" - name: 拷贝配置文件 copy: src: ./file/confxml.xml dest: /app/tools/sersync/conf/confxml.xml #- name: 创建快捷方式 # shell: "ln -s /app/tools/sersync/bin/sersync2 /bin/" - name: 创建快捷方式 file: path: /bin/sersync2 src: /app/tools/sersync/bin/sersync2 state: link - name: 启动sersync shell: "sersync2 -rdo /app/tools/sersync/conf/confxml.xml"#sersync客户端- hosts: backup tasks: - name: 创建同步目录 file: path: "{{ sersync_dir }}" owner: rsync group: rsync state: directory
故障
1.ansible 提示"provided hosts list is empty"
[root@m01 ~]# ansible all -m ping[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match "all"原因:主机清单是空的
2.ansible 提示"Please add this host"s fingerprint to your known_hosts file to manage this host"
[root@m01 ~]# ansible web -m ping172.16.1.7 | FAILED! => { "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host"s fingerprint to your known_hosts file to manage this host."}#原因:~/.ssh/known_hosts 文件被删除了#解决方法:1.执行下ssh远程命令,输入下yes/no2.关闭主机认证取消/etc/ansible/ansible.cfg 配置文件中第71行:host_key_checking = False这一行的注释
3.ansible playbook下载软件包的时候提示""
[root@m01 /server/scripts/playbook]# ansible-playbook -i hosts 3.zabbix.yml PLAY [all] *********************************TASK [Gathering Facts] *********************ok: [172.16.1.7]TASK [1.下载软件包] *****************************fatal: [172.16.1.7]: FAILED! => {"changed": false, "dest": "/tmp/", "elapsed": 0, "gid": 0, "group": "root", "mode": "01777", "msg": "Request failed: ", "owner": "root", "size": 4096, "state": "directory", "uid": 0, "url": "https://mirrors.tuna.tsinghua.edu.cn/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.7-1.el7.x86_64.rpm"}PLAY RECAP *********************************172.16.1.7 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 #原因:get_url下载https,会进行验证#解决:get_url:url: https://mirrors.tuna.tsinghua.edu.cn/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.71.el7.x86_64.rpmdest: /tmp/validate_certs: no #加这个选项
全球快播:Linux-ansible
天天视点!Python教程:selenium模块用法教程
世界报道:带你体验下来自人工智能ChatGPT的魅力
【全球热闻】小白也能做应用(一)之fusion app介绍
高层次综合器(Vivado HLS)的设计流程[原创www.cnblogs.com/helesheng]
变天了!x86 PC陨落:ARM大暴走
高通憋出新大招:4G杀手来了
国美电器多个破产申请被驳回 苏泊尔在列
当前关注:脸都不要了!《黑棉花:悟能》无耻碰瓷《黑神话:悟空》
Intel中国特供新U i7-13790F开卖:缓存多3MB 竟贵了150元!
当前快报:【Windows】Microsoft Store无法打开:关闭自动更新(请联系系统管理员更改此设置)
最资讯丨吴京与粉丝合照被滤镜坑惨:没有明星能逃过美颜摧残
环球时讯:明天上映!《流浪地球2》发布港版预告片:MOSS竟然说英文
资讯:log4cxx配置日期回滚策略中增加MaxFileSize属性
天天看点:MySQL索引的基本理解
当前关注:强大的Excel工具,简便Vlookup函数操作:通用Excel数据匹配助手V2.0
通过python,将excel中的数据写入二维列表
天天日报丨爬虫基础
科大讯飞:类ChatGPT技术今年5月落地 AI学习机产品先用
天天速看:31.98万元!理想L7 Air发布:性能不变 无空气悬架
天天速读:三星S23 Ultra拍月亮100倍变焦的效果:把马斯克都惊艳到了
世界今头条!分布式配置nacos搭建踩坑指南(上)
焦点消息!TVS二极管
(七)elasticsearch 源码之元数据CulsterState
暴雪关停国服后 CEO发声:游戏行业被亚洲主宰 东西方竞争不平衡
累计交付27万台 李想:理想成为国内家庭消费者首选豪华SUV
世界最新:高通全球首发5G NR-Light基带:主打中端物联网、峰值速率220兆
城市行驶每公里仅1毛钱!理想L7出行成本不足宝马X5十分之一
消息!drf认证/权限/频率/分页-过滤-排序
报道:【时间基准】NTP网络时钟服务器助力智能农业系统
快播:C和Python实现快速排序-三数中值划分选择主元(非随机)
宗申新款电动车闪电侠发布:续航超200公里 仪表盘可手机投屏
环球观速讯丨丢失两年的手机半夜仍被人试图解锁 被系统远程拍下照片
网友吐槽快递派送延误 韵达总部:人手紧张正调配
《狂飙》蜚声海外 英国小伙们沉迷剧集无法自拔:竟被打斗画面吸引
今日热文:大货车实线变道 女子科三被别停挂科当场发飙
全球热消息:土耳其一城市震后被海水倒灌:汽车泡在水里
环球观焦点:漂浮在数万米高空 你见到的“不明飞行物”:很可能就是一只气球
一加Ace 2支持双频GPS:发布会上没讲 结果被很多网友误伤
【天天播资讯】太火爆!ChatGPT多次因访问量激增而宕机
程序员常用的6款效率工具,准时下班不是梦
世界看点:春节假期“清零”,任务管理飞项快速助你回到高效状态
全球最新:win10系统,软件不可用,无法调用摄像头
Linux内核跟踪和性能分析
要闻:14年了:“千年老二”微软终于有机会扳倒谷歌搜索
热消息:微星推出Cubi 5 12M迷你主机:仅0.66L、配备双网口
世界热点评!女生应聘被问是否单身!当事公司:要求单身正常 将起诉举报者
【全球时快讯】近50年来首次!日本沙滩惊现大量沙丁鱼 原因未知:开排核废水、也要大地震?
最新资讯:国产车开门红:1月比亚迪称王 大众沦落第三 合资腰斩
03-Pandas详解
今日热讯:ChatGPT能做什么?零基础教你免费使用ChatGPT和账号注册
当前速看:美团面试失败后,翻了两年前的面试题,发现根本不是一个难度的
当前简讯:Linux安装
Spring Boot发送GET/POST请求——RestTemplate的基本使用
当前报道:自研指令集没有侵权MIPS 国产CPU龙芯赢了:摆脱官司
当前讯息:自燃车辆引燃邻车 损失谁来赔?法院释疑
天天最新:基于 eBPF 的 Serverless 多语言应用监控能力建设
世界最新:构建亿级别的消息推送基础模型
全球热文:Linux开源工具之nethogs命令介绍
精选!COBOL教程_编程入门自学教程_菜鸟教程-免费教程分享
华硕发布新款Vivobook 13 Slate笔记本:Intel 7W超低功耗U
今日精选:3岁女童喊脚疼被确诊癌症晚期:神经母细胞瘤 儿童癌症之王
天天微速讯:剧版《三体》弹幕互动量破2000万!豆瓣涨至8.3分
【热闻】iPhone 15 Ultra狂堆料!价格可能贵出天际
环球热议:全球不足50人!宝鸡发现1例罕见黄金血型:比熊猫血更稀有
环球资讯:ASP.Net Core 教程_编程入门自学教程_菜鸟教程-免费教程分享
ChatGPT保姆级注册教程
group by 、concat_ws()、 group_caoncat()的使用
全球热头条丨Jedis那么低性能,还在用吗? lettuce时代开幕啦
热资讯!阿里IM技术分享(十):深度揭密钉钉后端架构的单元化演进之路
强震已致超7700人遇难!土耳其地震背后的人祸 建筑不达标、豆腐渣工程多
全球热议:全球首架国产大飞机C919首飞三亚 民航最高接待礼“过水门”接风
环球关注:iPhone 15 Pro系列拿到三星顶级屏幕!超出S23系列整整两代
全球消息!高级Excel教程_编程入门自学教程_菜鸟教程-免费教程分享
重点聚焦!Serverless 时代开启,云计算进入业务创新主战场
【天天报资讯】Go的参数是传值还是传引用问题
【环球聚看点】【踩坑记录】单测中@PostConstruct多次执行
免费无广告 微软电脑管家2.7公测版发布:任务栏被意外修改有救了
4599元!佳能EOS R50发布:329克超轻便 支持无裁切6K
天天信息:研发10几年、花费千亿:日本国产大飞机为何失败?就是畸形产物
全球微速讯:LV将涨价?国人排长龙抢购 买万元包像在赶集:世界首富曾感慨中国用户有钱
高级Excel图表教程_编程入门自学教程_菜鸟教程-免费教程分享
Apache ANT 教程_编程入门自学教程_菜鸟教程-免费教程分享
焦点播报:算法学习笔记(15): Trie(字典树)
今日讯!火山引擎 DataTester“智能发布”:覆盖产品研发、测试、上线全流程,一站式智能管理 A/B 实验
DB2教程_编程入门自学教程_菜鸟教程-免费教程分享
马斯克将于3月1日公布特斯拉宏图第三篇章 第二篇章已烂尾
世界观速讯丨国产车企1:1复刻几十年前的MINI外观专利 宝马抗议!结果判了
【独家焦点】真心没想到!五旬男子开车撞上护栏:只因刚割了双眼皮
全球热消息:全世界最后一只袋狼究竟是怎么死的?
民企第一只 京东仓储REIT上市:认购额超718亿元遭疯抢
当前视讯!C#(进制转换) NumberConversion
ChatGPT国内也能用吗?ChatGPT国内镜像站点分享给你们
微动态丨暴躁小钢炮!极氪X实车亮相:零百加速3秒级
环球微速讯:《仙剑奇侠传》《和平精英》梦幻联动:赵灵儿端枪吃鸡
啥身材都能包!真维斯连帽卫衣大促:日常100元 现价50到手
6年来苹果iPhone涨价近50% 还会继续涨 库克不怕没人买
《流浪地球2》导演郭帆:国产科幻片工业流程还是初级 吃饭都会出大错误
童话二分之一的大结局是什么?童话二分之一演员表
金棕色适合什么肤色?金棕色和金栗色茶色的区别有哪些?