ansible搭建

这篇具有很好参考价值的文章主要介绍了ansible搭建。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一,ansible是一种由Python开发的自动化运维工具,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能

二,特点

* 部署简单

* **默认使用ssh进行管理,基于python里的==paramiko==模块开发**

* 管理端和被管理端不需要启动服务

* 配置简单,功能强大,扩展性强

* 能过playbook(剧本)进行多个任务的编排

三,ansible搭建

实验准备三台机器,一台管理机 192.168.115.3,两台被管理机 192.168.115.4 192.168.115.5

#所有主机都要配置主机名和 hosts文件

[root@hd1 ~]# hostnamectl set-hostname hd1

[root@hd1 ~]# cat /etc/hosts

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4

::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.1.11 hd1

192.168.1.12 hd2

192.168.1.13 hd3

ansible搭建,ansible

#hd2和hd3 同上类似操作

关闭防火墙, selinux

ansible搭建,ansible

ansible搭建,ansible

时间同步

下载更新epel源

yum -y install epel-release
 

ansible搭建,ansible

管理机上安装ansible,被管理节点必须打开ssh服务

 yum install epel-release
yum install ansible
查看版本ansible --version

ansible搭建,ansible

实现master对agent的免密登录,只在master上做。(如果这一步不做,则在后面操作agent时都要加-k参数传密码;或者在主机清单里传密码

ssh-keygen

ansible搭建,ansible

ssh-copy-id   192.168.115.4      192.168.115.5

ansible搭建,ansibleansible搭建,ansible

在master上定义主机组,并测试连接性

vim /etc/ansible/hosts 

ansible搭建,ansible

 ansible -m ping group1

ansible搭建,ansible

查看支持的模块

ansible-doc -l

ansible搭建,ansible

hostname模块配置

hostname模块用于修改主机名(注意: 它不能修改/etc/hosts文件)

将其中一远程机器主机名修改为agent1

ansible 192.168.115.4 -m hostname -a 'name=agent1'
基本格式为: ansible 操作的机器名或组名 -m 模块名 -a "参数1=值1 参数2=值2" argment

ansible搭建,ansible

ansible搭建,ansible

测试完改回hd2

file模块

file模块用于对文件相关的操作(创建, 删除, 软硬链接等)

创建一个目录

ansible group1 -m file -a 'path=/test state=directory'

ansible搭建,ansible

ansible搭建,ansible

创建一个文件

ansible group1 -m file -a 'path=/test/111 state=touch'

ansible搭建,ansible

ansible搭建,ansible

递归修改owner,group,mode

ansible group1 -m file -a 'path=/test recurse=yes owner=bin group=daemon mode=1777'

ansible搭建,ansible

ansible搭建,ansible

测试完改回777权限

ansible搭建,ansible

删除目录 absent 缺席的(连同目录里的所有文件)

ansible group1 -m file -a 'path=/test state=absent'

ansible搭建,ansible

ansible搭建,ansible

创建文件并指定owner,group,mode等

ansible group1 -m file -a 'path=/tmp/111 state=touch owner=bin group=daemon mode=777'

ansible搭建,ansible

删除文件

ansible group1 -m file -a 'path=/tmp/111 state=absent'

ansible搭建,ansible

ansible搭建,ansible

创建软链接文件

ansible group1 -m file -a 'src=/etc/fstab path=/tmp/fstab state=link'

创建硬链接文件

ansible group1 -m file -a 'src=/etc/fstab path=/tmp/fstab2 state=hard'

copy模块

copy模块用于对文件的远程拷贝操作(如把本地的文件拷贝到远程的机器上)

在master上准备一个文件,拷贝此文件到group1的所有机器上

echo master > /tmp/222
ansible group1 -m copy -a 'src=/tmp/222 dest=/tmp/333'

ansible搭建,ansible

ansible搭建,ansible

使用content参数直接往远程文件里写内容(会覆盖原内容)

ansible group1 -m copy -a 'content="ha ha\n" dest=/tmp/333'

注意:ansible中-a后面的参数里也有引号时,记得要单引双引交叉使用,如果都为双引会出现问题

使用force参数控制是否强制覆盖

先在hd2 hd3里创建文件  touch /tmp/444

ansible搭建,ansible

如果目标文件已经存在,则不覆盖
ansible group1 -m copy -a 'src=/tmp/222 dest=/tmp/444 force=no'

如果目标文件已经存在,则会强制覆盖
ansible group1 -m copy -a 'src=/tmp/222 dest=/tmp/444 force=yes'

ansible搭建,ansible

ansible搭建,ansible

使用backup参数控制是否备份文件

backup=yes表示如果拷贝的文件内容与原内容不一样,则会备份一份
group1的机器上会将/tmp/333备份一份(备份文件命名加上时间),再远程拷贝新的文件为/tmp/333
ansible group1 -m copy -a 'src=/etc/fstab dest=/tmp/333 backup=yes owner=daemon group=daemon mode=777'

ansible搭建,ansible

ansible搭建,ansibleansible搭建,ansible

copy模块拷贝时要注意拷贝目录后面是否带"/"符号

/etc/yum.repos.d后面不带/符号,则表示把/etc/yum.repos.d整个目录拷贝到/tmp/目录下
ansible group1 -m copy -a 'src=/etc/yum.repos.d dest=/tmp/'

/etc/yum.repos.d/后面带/符号,则表示把/etc/yum.repos.d/目录里的所有文件拷贝到/tmp/目录下
ansible group1 -m copy -a 'src=/etc/yum.repos.d/ dest=/tmp/'

ansible搭建,ansible

ansible搭建,ansible

练习: 在master上配置好所有的yum源,然后拷贝到group1的远程机器上(要求目录内的内容完全一致)

master上配置yum源ansible搭建,ansible

ansible group1 -m file -a "path=/etc/yum.repos.d/ state=absent"   删除hd2 hd3上的/etc/yum.repos.d目录

ansible group1 -m copy -a "src=/etc/yum.repos.d dest=/etc/"   把hd1上的目录拷贝到hd2 hd3

ansible搭建,ansible

hd2 hd3查看ansible搭建,ansible

练习: 使用hostname模块修改过主机名后.在master上修改/etc/hosts文件,并拷贝到group1的远程机器上

先删除hd2 hd3的hosts文件,在master上修改好/etc/hosts文件,然后使用下面命令拷贝过去覆盖
ansible group1 -m copy -a "src=/etc/hosts dest=/etc/hosts"

ansible搭建,ansible

客户端查看

ansible搭建,ansible

user模块

user模块用于管理用户账号和用户属性。

创建aaa用户,默认为普通用户,创建家目录

ansible group1 -m user -a ‘name=aaa state=present’

ansible搭建,ansible

ansible搭建,ansible

创建bbb系统用户,并且登录shell环境为/sbin/nologin

ansible group1 -m user -a ‘name=bbb state=present system=yes  shell="/sbin/nologin"’

ansible搭建,ansible

创建ccc用户, 使用uid参数指定uid, 使用password参数传密码

echo 123456 | openssl passwd -1 -stdin
$1$1a.g59z9$kfIxvDIvOq0g20Sd2XMib0


​
下一句命令注意一下格式,密码要用双引号引起来,单引号的话验证时会密码不正确
ansible group1 -m user -a 'name=ccc uid=2000 state=present password="$1$1a.g59z9$kfIxvDIvOq0g20Sd2XMib0"'

ansible搭建,ansible

ansible搭建,ansible

创建一个普通用户叫hadoop,并产生空密码 密钥对

ansible group1 -m user -a 'name=hadoop generate_ssh_key=yes'

ansible搭建,ansible

删除aaa用户,但家目录默认没有删除

 ansible group1 -m user -a 'name=aaa state=absent'

ansible搭建,ansible

ansible搭建,ansible

删除bbb用户,使用remove=yes参数让其删除用户的同时也删除家目录

ansible group1 -m user -a 'name=bbb state=absent remove=yes'

ansible搭建,ansible

ansible搭建,ansible

group模块

group模块用于管理用户组和用户组属性。

创建组

ansible group1 -m group -a 'name=groupa gid=3000 state=present'

ansible搭建,ansible

删除组(如果有用户的gid为此组,则删除不了)

 ansible group1 -m group -a 'name=groupa state=absent'

ansible搭建,ansible

cron模块

cron模块用于管理周期性时间任务

创建一个cron任务,不指定user的话,默认就是root(因为我这里是用root操作的)。 如果minute,hour,day,month,week不指定的话,默认都为*

ansible group1 -m cron -a 'name="test cron1" user=root job="touch /tmp/111" minute=*/2' 

ansible搭建,ansible

ansible搭建,ansible

删除cron任务

 ansible group1 -m cron -a 'name="test cron1" state=absent'

 ansible搭建,ansible

yum_repository模块

yum_repository模块用于配置yum仓库。

增加一个/etc/yum.repos.d/local.repo配置文件

ansible group1 -m yum_repository -a "name=local description=localyum baseurl=file:///mnt/ enabled=yes gpgcheck=no"

ansible搭建,ansible

ansible搭建,ansible

注意:此模块只帮助配置yum仓库,但如果仓库里没有软件包,安装一样会失败。所以可以手动去挂载光驱到/mnt目录
# mount /dev/cdrom /mnt

删除/etc/yum.repos.d/local.repo配置文件

 ansible group1 -m yum_repository -a "name=local state=absent" 

ansible搭建,ansible

ansible搭建,ansible

yum模块(重点)

yum模块用于使用yum命令来实现软件包的安装与卸载。

使用yum安装一个软件(前提:group1的机器上的yum配置都已经OK)

ansible group1 -m yum -a 'name=vsftpd state=present'

ansible搭建,ansible

ansible搭建,ansible

使用yum安装httpd,httpd-devel软件,state=latest表示安装最新版本

ansible group1 -m yum -a 'name=httpd,httpd-devel state=latest' 

ansible搭建,ansible

ansible搭建,ansible

使用yum卸载httpd,httpd-devel软件

ansible group1 -m yum -a 'name=httpd,httpd-devel state=absent' 

ansible搭建,ansible

service模块(重点)

service模块用于控制服务的启动,关闭,开机自启动等。

启动vsftpd服务,并设为开机自动启动

ansible group1 -m service -a 'name=vsftpd state=started enabled=on'

关闭vsftpd服务,并设为开机不自动启动

ansible group1 -m service -a 'name=vsftpd state=stopped enabled=false'

练习: 在group1的被管理机里的mariadb里创建一个abc库

mysql -e user=root password=123456 "create database abc ;"

练习:

假设我主机清单里定义的group1里有多台机器,它们现在要做一个集群。此集群要求实现一个名为hadoop的普通用户之间的两两免密登录,如何实现(要求只在master上进行操作)?

script模块

script模块用于在远程机器上执行本地脚本。

在master上准备一个脚本
master# vim /tmp/1.sh
#!/bin/bash
mkdir /tmp/haha
touch /tmp/haha/{1..10}
​
在group1的远程机器里都执行master上的/tmp/1.sh脚本(此脚本不用给执行权限)
ansible group1 -m script -a '/tmp/1.sh'

扩展: 使用shell脚本实现在group1的被管理机里的mariadb里创建一个abc库

#!/bin/bash
​
yum install mariadb-server -y  &> /dev/null
​
systemctl start mariadb
systemctl enable mariadb
​
mysql << EOF
create database abc;
quit
EOF
​
把上面的脚本使用script模块在group1被管理机里执行即可

command与shell模块

两个模块都是用于执行linux命令的,这对于命令熟悉的工程师来说,用起来非常high。

shell模块与command模块差不多(command模块不能执行一些类似$HOME,>,<,|等符号,但shell可以)

ansible.builtin.command module – Execute commands on targets — Ansible Documentation

ansible.builtin.shell module – Execute shell commands on targets — Ansible Documentation

master# ansible -m command group1 -a "useradd user2"
master# ansible -m command group1 -a "id user2"
​
master# ansible -m command group1 -a "cat /etc/passwd |wc -l"       --报错
master# ansible -m shell group1 -a "cat /etc/passwd |wc -l"     --成功
​
master# ansible -m command group1 -a "cd $HOME;pwd"   --报错
master# ansible -m shell  group1 -a "cd $HOME;pwd"    --成功

注意: shell模块并不是百分之百任何命令都可以,比如vim或ll别名就不可以。不建议大家去记忆哪些命令不可以,大家只要养成任何在生产环境里的命令都要先在测试环境里测试一下的习惯就好。

三、playbook

playbook(剧本): 是ansible用于配置,部署,和管理被控节点的剧本。用于ansible操作的编排。

参考:Ansible playbooks — Ansible Documentation

使用的格式为yaml格式(saltstack,elk,docker,docker-compose,kubernetes等也都会用到yaml格式)

YMAL格式

  • 以.yaml或.yml结尾

  • 文件的第一行以 "---"开始,表明YMAL文件的开始(可选的)

  • 以#号开头为注释

  • 列表中的所有成员都开始于相同的缩进级别, 并且使用一个 "- " 作为开头(一个横杠和一个空格)

  • 一个字典是由一个简单的 键: 值 的形式组成(这个冒号后面必须是一个空格)

  • ==注意: 写这种文件不要使用tab键,都使用空格==

参考: YAML Syntax — Ansible Documentation

下面看一个官方的示例感受一下

---
# 一位职工记录
name: Example Developer
job: Developer
skill: Elite
employed: True
foods:
    - Apple
    - Orange
    - Strawberry
    - Mango
languages:
    ruby: Elite
    python: Elite
    dotnet: Lame

playbook实例

先直接来看一个实例

第1步: 创建一个存放playbook的目录(路径自定义)

master# mkdir /etc/ansible/playbook

第2步: 准备httpd配置文件,并修改成你想要的配置

master# yum install httpd -y
​
按需要修改你想要的配置(为了测试可以随意改动标记一下)
master# vim /etc/httpd/conf/httpd.conf

第3步: 写一个playbook文件(后缀为.yml或.yaml)

# vim /etc/ansible/playbook/example.yaml
---
- hosts: group1
  remote_user: root
  tasks:  
  - name: ensure apache is at the latest version    
    yum: name=httpd,httpd-devel state=latest
    
  - name: write the apache config file      
    copy: src=/etc/httpd/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
    
    notify:
    - restart apache
    
  - name: ensure apache is running (and enable it at boot)
    service: name=httpd state=started enabled=yes
    
  handlers: 
    - name: restart apache
      service: name=httpd state=restarted

第4步: 执行写好的palybook

  • 会显示出执行的过程,并且执行的每一步都有ok,changed,failed等标识

  • 执行如果有错误(failed)会回滚,解决问题后,直接再执行这条命令即可,并会把failed改为changed(幂等性)

# ansible-playbook /etc/ansible/playbook/example.yaml

Playbook常见语法

hosts: 用于指定要执行任务的主机,其可以是一个或多个由冒号分隔主机组.

remote_user: 用于指定远程主机上的执行任务的用户.

- hosts: group1         
  remote_user: root 

tasks: 任务列表, 按顺序执行任务.

  • 如果一个host执行task失败, 整个tasks都会回滚, 修正playbook 中的错误, 然后重新执行即可.

  tasks:
  - name: ensure apache is at the latest version    
    yum: name=httpd,httpd-devel state=latest
    
  - name: write the apache config file      
    copy: src=/etc/httpd/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf

handlers: 类似task,但需要使用notify通知调用。

  • 不管有多少个通知者进行了notify,等到play中的所有task执行完成之后,handlers也只会被执行一次.

  • handlers最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到了.

    notify:               
    - restart apache
    
  - name: ensure apache is running (and enable it at boot)
    service: name=httpd state=started enabled=yes
    
  handlers:
  - name: restart apache
    service: name=httpd state=restarted

练习: 修改httpd的端口为8080,再执行playbook测试

variables: 变量

  • 定义变量可以被多次方便调用

master# vim /etc/ansible/playbook/example2.yaml
---
- hosts: group1
  remote_user: root
  vars:
  - user: test1
  tasks:
  - name: create user
    user: name={{user}} state=present
~                                           
master# ansible-playbook /etc/ansible/playbook/example2.yaml

案例: playbook编排vsftpd

写一个playbook实现

  1. 配置yum

  2. 安装vsftpd包

  3. 修改配置文件(要求拒绝匿名用户登录)

  4. 启动服务并实现vsftpd服务开机自动启动

---
- hosts: group1                 
  remote_user: root                     
  tasks:                                
  - name: rm yum repository      
    file: path=/etc/yum.repos.d/ state=absent
    
  - name: 同步master上的yum源到group1
    copy: src=/etc/yum.repos.d dest=/etc/
    
  - name: ensure vsftpd is at the latest version        
    yum: name=vsftpd state=latest
    
  - name: write the apache config file          
    copy: src=/etc/vsftpd/vsftpd.conf dest=/etc/vsftpd/vsftpd.conf 
    
    notify:                             
    - restart vsftpd
    
  - name: ensure vsftpd is running (and enable it at boot)
    service: name=vsftpd state=started enabled=yes
    
  handlers:                     
    - name: restart vsftpd              
      service: name=vsftpd state=restarted

playbook编排多个hosts任务

---         # ---代表开始(可选项,不写也可以)
- hosts: 10.1.1.12
  remote_user: root
  tasks:
  - name: 创建/test1/目录
    file: path=/test1/ state=directory
# 这里不能用---分隔,会报语法错误(后面课程玩k8s编排也写YAML文件,是可以用---来分隔段落的)
- hosts: 10.1.1.13
  remote_user: root
  tasks:
  - name: 创建/test2/目录
    file: path=/test2/ state=directory
...         # ...代表结束(可选项,不写也可以)

案例: 编排nfs搭建与客户端挂载

1, 在master上准备nfs配置文件

# vim /etc/exports
/share  *(ro)

2, 编写yaml编排文件

# vim /etc/ansible/playbook/nfs.yml
---
- hosts: 10.1.1.12
  remote_user: root
  tasks:
  - name: 安装nfs服务相关软件包
    yum: name=nfs-utils,rpcbind,setup  state=latest
​
  - name: 创建共享目录
    file: path=/share/ state=directory
​
  - name: 同步nfs配置文件
    copy: src=/etc/exports dest=/etc/exports
​
    notify: restart nfs
​
  - name: 启动rpcbind服务,并设置为开机自启动
    service: name=rpcbind state=started enabled=on
​
  - name: 启动nfs服务,并设置为开机自启动
    service: name=nfs state=started enabled=on
​
  handlers:
  - name: restart nfs
    service: name=nfs state=restarted
​
- hosts: 10.1.1.13
  remote_user: root
  tasks:
  - name: 安装nfs客户端软件包
    yum: name=nfs-utils state=latest
​
  - name: 挂载nfs服务器的共享
    shell: mount 10.1.1.12:/share /mnt

3, 执行playbook文章来源地址https://www.toymoban.com/news/detail-706942.html

# ansible-playbook /etc/ansible/playbook/nfs.yaml

到了这里,关于ansible搭建的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ansible(2)-- ansible常用模块

    部署ansible:ansible(1)-- 部署ansible连接被控端_luo_guibin的博客-CSDN博客 目录  一、ansible常用模块 1.1 ping 1.2 command 1.3 raw 1.4 shell 1.5 script 1.6 copy 1.7 template 1.8 yum 11.0.1.13 主控端(ansible) 11.0.1.12 被控端(k8s-master) 查看主控端被控端IP,主控端(10.1.1.13)查看ansible配置文件的被控端,

    2024年02月11日
    浏览(39)
  • 【ansible】ansible配置文件详解

    目录 管理ansible的配置文件 一,配置ansible 二,据优先级选择执行ansible配置文件 1,按照优先级首先会匹配环境变量ANSIBLE_CONFIG  2,第二个匹配到./ansible.cfg文件  3,第三个匹配到~/.ansible.cfg文件 4,当以上文件都不存在时,ansible配置文件就会匹配到/etc/ansible/ansible.cfg 三,管理

    2024年02月04日
    浏览(39)
  • ansible(1)-- 部署ansible连接被控端

    目录 一、部署ansible 1.1 安装 1.2 测试连接 192.168.136.55 ansible 192.168.136.56 被控端 zabbix-s只是主机名,不用在意,更好该主机也安装了zabbix,不好更改。 下载阿里云epel源   被控端192.168.136.56生成的文件 ansible 自动安装,无需经过密码确认,ubantun、centos: 生产中使用ssh-copy-id复制

    2024年02月12日
    浏览(38)
  • 【ansible】认识ansible,了解常用的模块

    目录 一、ansible是什么? 二、ansible的特点? 三、ansible与其他运维工具的对比 四、ansible的环境部署 第一步:配置主机清单 第二步:完成密钥对免密登录 五、ansible基于命令行完成常用的模块学习 模块1:command模块 模块2:shell模块 模块3:cron模块 模块4:user模块 模块5:gro

    2024年02月20日
    浏览(40)
  • [Ansible系列]ansible playbook的条件语句

    目录 简介 when 1.  when的基本使用  2.   比较运算符 3.  逻辑运算符 4.   判断变量 5.  判断执行结果  6.  判断路径  7.  判断字符串  8.  判断整除  9.  其他 9.1  version  9.2   subset  9.3  superset  9.4  in  9.5  string  和 number  条件判断与block 1.  block  2.  rescue 

    2024年02月03日
    浏览(35)
  • [Ansible系列]ansible JinJia2过滤器

    目录 一.  JinJia2简介 二.  JinJia2模板使用  2.1  在play中使用jinjia2 2.2  template模块使用 2.3   jinjia2条件语句 2.4  jinjia2循环语句 2.5   jinjia2过滤器 2.5.1   default过滤器 2.5.2  字符串操作相关过滤器   2.5.3  数字操作相关过滤器 2.5.4  列表操作相关过滤器  2.5.5   应用于文件

    2024年02月02日
    浏览(47)
  • ansible创建用户账户和更新ansible库的密钥

    1.创建⽤户帐户 从 http://materials/user_list.yml 下载要创建的⽤户的列表,并将它保存到 /home/greg/ansible 在本次考试中使⽤在其他位置创建的密码库 /home/greg/ansible/locker.yml 。创建名为 /home/greg/ansible/users.yml 的 playbook ,从⽽按以下所述创建⽤户帐户: 职位描述为 developer 的⽤户应当

    2024年04月16日
    浏览(46)
  • 01_什么是ansible、基本架构、ansible工作机制、Ansible安装、配置主机清单、设置SSH无密码登录等

    1.什么是ansible 1.1.基本介绍 1.2.基本架构 1.3.基本特征 1.4.优点 1.5.ansible工作机制 2.Ansible安装 2.1.机器准备 2.2.安装ansible 2.2.1.安装epel源 2.2.2.安装ansible 2.2.3.查看ansible版本 2.2.4.树状结构展示文件夹 2.2.4.1.其中ansible.cfg的内容如下 2.2.4.2.host的默认内容是 2.3.配置主机清单 2.4.设置

    2024年02月14日
    浏览(45)
  • Ansible Rsync 使用Ansible Rsync模块进行文件传输

    在Ansible自动化工具中,Rsync模块(Rsync Module)是一个强大的组件,用于在Ansible控制节点和目标主机之间进行文件传输和同步。本文将深入探讨Ansible Rsync模块,了解它如何成为自动化任务中高效同步的自动化利器。 Ansible Rsync模块是Ansible的核心模块之一,它利用rsync工具进行文

    2024年02月14日
    浏览(44)
  • Ansible主机清单书写演示和ansible.cfg配置文件详解

    目录 主机清单(常见为INI格式) 一.定义主机列表 1.每行写一个 2.主机组 (1)定义简单主机组 (2)指定多台主机时可以通过书写范围来表示 (3)定义嵌套主机组 二.匹配主机和组 1.匹配所有主机 (1)all (2)特殊使用*号,单独使用无效 2.匹配指定主机或组 (1)匹配一个

    2024年02月07日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包