Ansible(自动化软件)

ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,批量修改配置、批量设置服务器密码、批量安装软件包、ansible只是提供一种框架(共有2864各模块)。主要包括:

  • 连接插件connection plugins:负责和被监控端实现通信;
  • host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
  • 各种模块核心模块、command、shell模块、自定义模块;
  • 借助于插件完成记录日志邮件等功能;
  • playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
  • 一:ansible原理:
    控制端主机自带很多模块(模块就是脚本);
  • ansible通过ssh远程被管理主机,将控制端的模块(脚本)或命令传输到被管理主机;

    在被管理端主机执行模块(脚本)或命令,执行不同的模块或命令可以实现不同的功能;

    最后ansible退出ssh远程(再退出之前,会自动把拷贝的文件删除)。

    绝大多数模块(脚本)都需要参数才能执行成功!!!类似于shell脚本的位置变量!

  1. 实验前期准备:

        在control电脑192.168.4.253操作:

1)###修改域名解析文件,给每个电脑添加一个域名解析,如果公司有DNS服务器也可以无此操作。

[root@control ~]# vim    /etc/hosts

不要修改或删除原来的任何内容,在文件最后添加新内容即可

  • 192.168.4.253    control
  • 192.168.4.11      node1
  • 192.168.4.12      node2
  • 192.168.4.13      node3
  • 192.168.4.14      node4
  • 192.168.4.15      node5
  • 备注:左边是IP右边是域名,添加后,以后电脑通信可以使用域名
  • 2)验证:

    [root@control ~]#  ping   node1

3)设置公钥 

ansible是基于ssh远程所有被管理主机,但是默认ssh需要密码

ansible远程N台主机,需要输入N次密码,不合理!

在ansible主机通过ssh-keygen生成密钥,然后将密钥拷贝给所有被管理主机

//生成密钥,-f指定密钥放到哪个文件里,-N不给密钥设置密码,''是两个单引号

  • [root@control ~]# ssh-keygen    -f    /root/.ssh/id_rsa    -N ''
  • [root@control ~]# ssh-copy-id   node1
  • Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
  • root@node1's password: <输入node1的密码>
  • [root@control ~]# ssh-copy-id   node2
  • [root@control ~]# ssh-copy-id   node3
  • [root@control ~]# ssh-copy-id   node4
  • [root@control ~]# ssh-copy-id   node5
  • 如何验证:(依次远程所有主机,测试是否需要密钥,应该不需要密码)
  • [root@control ~]#  ssh   node1
  • [root@node1 ~]#  exit

 4)  给control电脑192.168.4.253安装ansible软件包:

正常安装方式此处略

5)配置文件说明:

创建一个目录mkdir  /root/ansible/,在该目录下创建配置文件 /root/ansible/ansible.cfg

凡使用ansible必须先cd 到/root/ansible

  • [root@control ~]# mkdir    /root/ansible
  • [root@control ~]# vim     /root/ansible/ansible.cfg
  • [defaults]
  • inventory = /root/ansible/inventory
  • 备注:[defaults]是固定格式,代表默认配置
  • inventory是固定参数,不能改变,等于号后面是一个文件名(可以任意)
  • 等于号两边可以有空格或者没有空格都行
  • /root/ansible/inventory文件叫[清单文件]
  • 清单文件里面用来存放所有你需要ansible管理的电脑信息
  • [root@control ~]#   vim   /root/ansible/inventory
  • [test]                        #定义主机组(组名称任意)
  • node1                      #定义组中的具体主机,组中包括一台主机node1
  • [proxy]                     #定义主机组(组名称任意),英语词汇:proxy(代理人,委托人)
  • node2                      #proxy组中包括一台主机node2
  • [webserver]
  • node[3:4]                 #这里的node[3:4]等同于node3和node4
  • [database]
  • node5
  • [cluster:children]        #嵌套组(children为关键字),不需要也可以不创建嵌套组
  • webserver                  #嵌套组可以在组中包含其他组
  • database
  • 验证:

 二:ansible用法有两种:

  • ansible-adhoc   在命令行敲命令实现自动化;
  • ansible playbook     是提前写剧本(脚本),然后执行剧本(脚本);

方法一:ansible-adhoc

  • 通过命令执行ansible,格式如下:
  • ansible    目标主机或组    -m    模块     -a    参数
  • 备注:目标主机或组必须在清单文件里有定义
  • 备注:模块的本质是脚本,模块名称是由设计者定义
  • 备注:一个模块是否有参数,参数是什么,也是由设计者定义死的!

1)第一个模块:ping模块

[root@control ansible]# ansible   all   -m   ping

[root@control ansible]# ansible   node1,node3   -m   ping

[root@control ansible]# ansible   webserver   -m   ping

备注:可以远程主机名,可以远程组名字,也可以远程特殊all组(all组ansible自带)-m(module)模块:调用ping模块

ping模块,他的作用是用control主机ssh远程被管理主机,检查对方是否有python。

2)第二个模块:command(重要:这个模块也是默认模块)

  • command模块可以让你传命令给被控制端主机,在被控制端主机执行这个命令
  • [root@control ansible]# ansible  node1   -m    command   -a    "date"
  • node1 | CHANGED | rc=0 >>
  • Wed Dec 22 09:39:06 CST 2021
  • [root@control ansible]# ansible   webserver   -m   command   -a   "uname -r"
  • node4 | CHANGED | rc=0 >>
  • 4.18.0-193.el8.x86_64
  • node3 | CHANGED | rc=0 >>
  • 4.18.0-193.el8.x86_64
  • 备注:webserver是前面课程清单文件里面定义的组名称,-a后面是命令,可以自己任意
  • [root@control ansible]#  ansible    all     -a   "ip   a   s"
  • 备注:command模块是默认模块
  • 备注:ansible远程使用的是并发远程,哪个电脑反应速度快,就先返回哪个电脑的信息
  • 备注:ansible返回的结果是随机顺序
  • 备注:如何查看ansible所有的模块
  • [root@control ansible]# ansible-doc  -l    |   wc -l
  • //查看模块个数
  • [root@control ansible]# ansible-doc  -l
  • //(小写字母L)查看所有模块的名称,空格翻页,q退出
  • [root@control ansible]#  ansible-doc   ping
  • //查看ping模块的帮助,空格翻页,q退出
  • [root@control ansible]#  ansible-doc   command
  • //查看command模块的帮助,空格翻页,q退出
  • command可以将命令传给被管理主机,在被管理主机执行命令
  • 但是,command模块不支持>,|,<,&等符号,shell模块支持

3)第三个模块:shell模块

shell模块可以让你传命令给被控制端主机,在被控制端主机执行这个命令

错误的案例:

[root@control ansible]# ansible  node1  -m command  -a  "ps aux | wc -l"

node1 | FAILED | rc=1 >>

error: garbage option

备注:命令没问题,但是执行会报错

[root@control ansible]# ansible node1 -m command -a "echo abc > /tmp/a.txt"

执行不报错,但是无法创建文件

正确的案例:

[root@control ansible]# ansible  node1  -m shell  -a  "ps aux | wc -l"

[root@control ansible]# ansible node1 -m shell -a "echo abc > /tmp/a.txt"

备注:-m调用shell模块,-a后面是需要让shell模块传递的命令,命令可以任意

备注:ps aux查看计算机所有进程,wc -l是统计个数

注意事项:不可以使用command、shell、script模块执行交互命令,如vim、top等。

command和shell可以远程并执行命令,但是能执行的命令个数有限

如果有一个任务,需要执行50条命令才能完成,command和shell就比较吃力

4)第四个模块:script模块

我们可以提前写一个脚本(可以是shell、php、python、java...)

用script模块自动把脚本拷贝给所有被管理主机,在被管理主机执行脚本

[root@control ansible]# vim   test.sh

#!/bin/bash

dnf -y  install  httpd

systemctl start  httpd

echo hello world > /var/www/html/index.html

firewall-cmd --set-default-zone=trusted

备注:安装httpd,启动httpd服务,生成一个网页文件,设置防火墙信任所有

备注:不需要给脚本设置x权限

[root@control ansible]# ansible   webserver   -m   script   -a    "./test.sh"

//远程webserver组,组是前面清单文件定义的

//-m调用script模块,-a告诉计算机拷贝什么脚本,可以绝对路径也可以相对路径

如何测试:

使用浏览器访问http://192.168.4.13http://192.168.4.14

备注:webserver组里面有node3和node4两台主机

总结:command,shell,script模块,都是执行命令的模块

一般很多人任务shell模块是万能模块!

注:

command,shell,script模块都没有幂等性

ansible很多模块都有幂等性,而这三个模块刚好没有!

ansible我执行N次ansible命令和执行1次ansible命令结果一样!

幂等性是要求执行ansible一次命令和N次命令的结果一致!

 可以理解,带幂等性的计算机,等于有了智能的if判断,如果你已经有了,则自己不操作。

  • 5)第五个模块:file模块

file模块可以创建文件、创建目录、修改文件权限,所有者、所属组、删除文件、删除目录也可以创建文件的链接。

[root@control ansible]# ansible  node1   -m  file  -a   "path=/tmp/file.txt   state=touch"

 备注:远程node1,-m调用file模块,file模块需要参数,-a传递参数

  • path=定义文件名或目录名(名称可以任意),path是程序设计者已经定义死的
  • state=touch代表创建文件,state=directory代表创建目录,这个也是设计者定义死的

如何验证:

  • 打开node1,执行#ls   /tmp/file.txt,看看有没有这个文件
  • //修改文件或目录的权限,所有者,所属组
  • [root@control ansible]# ansible   test    -m file   -a   "path=/tmp/file.txt    owner=sshd   group=adm   mode=0666"
  • 备注:远程test组,test是组名,-m调用file模块,-a设置参数,  \代表换行
  • path=指定文件或目录名
  • owner指定文件的所有者(owner是固定的),group指定文件的所属组(group是固定的)
  • mode指定文件的权限,0666,   第一个0代表没有任何特殊权限(suid,sgid,sticky)
  • [root@control ansible]# ansible  test  -m   file   -a   "path=/tmp/file.txt   state=absent"
  • 备注:ansible远程test组,-m调用file模块,-a指定参数
  • path=指定要删除的文件或目录名,state=absent是固定的,代表删除的意思
  • 给文件就删除文件,给目录就删除目录
  • 如何验证:
  • 打开node1,执行ls  -l   /tmp/file.txt,查看文件是否被删除
  • [root@control ansible]# ansible   test   -m   file   -a    "path=/tmp/dir  state=directory"

  • 黄色或橙色:远程了被控制端主机,并且做了操作!
  • 绿色,是因为ansible的file模块有幂等性,你让他远程node1,创建/tmp/dir目录
  • 结果file模块发现node1已经有/tmp/dir目录了,则什么也不做,直接返回告诉你成功
  • 红色的代表失败了

    另外是紫色是警告【Warning】,比如使用shell创建文件,比如找不到远程的主机

  • ## ln    -s    /etc/hosts   /tmp/hosts
  • #这个命令/etc/hosts是源文件,给它做链接,链接是/tmp/hosts
  • //使用file模块给文件创建链接
  • [root@control ansible]# ansible   node1   -m    file  -a   "src=/etc/hosts    path=/tmp/host   state=link"
  • 备注:远程node1,-m调用file模块,-a传参数
  • src(source)英文单词:源,通过src指定源文件,path指定链接的路径(名称任意
  • state=link是软连接,state=hard是硬连接
  • 如何验证:
  • 打开node1,执行命令ls -l  /tmp/host 查看是否有连接 
  • 重要提示:所有模块的所有参数,都没有前后顺序,可以任意
  • 类似于ls   -la和ls  -al
  • 6)第六个模块:copy模块(拷贝文件)
  • 控制端主机------------------------------>>>>>>>>被控制端主机
  • [root@control ansible]#   echo AAA    >   ~/a3.txt
  • [root@control ansible]#  ansible    all   -m   copy    -a   "src=~/a3.txt    dest=/a3.txt"
  • 备注:ansible远程所有主机,all是组的名称
  • src(source)指定要拷贝的源文件,dest(destination)指定拷贝到哪里去(文件名任意)
  • src和dest是参数,是写copy模块的作者定义好的,不能修改
  • 如何验证:(所有被控制端主机都被拷贝了a3.txt文件)
  • 分别打开node1,node2,node3,node4,node5
  • 执行 # ls   /a3.txt    看看是否有文件
  • 7)第七个模块:fetch模块(拷贝文件)

  • 控制端主机<---------------被控制端主机
  • fetch模块可以把被控制端的文件拷贝给控制端主机
  • 如果我要把node1,node2,node3,node4,node5的/etc/hostname拷贝给自己
  • 文件名冲突,如何解决,ansible会自动创建以主机名命名的目录
  • [root@control ansible]# ansible    all   -m   fetch    -a  "src=/etc/hostname    dest=/root"
  • 备注:ansible远程all组,all是组名,-m调用fetch模块,
  • src指定拷贝的源文件,dest指定拷贝到哪里
  • 如何验证:在control电脑ls查看是否有文件
  • [root@control ansible]# ls  /root/node1/etc/
  • 8) 第八个模块:lineinfile|replace模块(修改文件内容)

  • lineinfile一次修改文件的一行(以行为单位)
  • replace一次修改文件一个字符(以字符或单词为单位)
  • [root@control ansible]# ansible   all   -m   lineinfile \
  •  -a   "path=/etc/issue   line='hello the world'"
  • 备注:ansible远程all组,远程所有主机,-m调用lineinfile模块
  • 这个模块是别人提前写好的脚本,这个脚本可以修改文件内容
  • -a给模块传递参数,否则它也不知道改什么文件,怎么改文件
  • path指定需要修改的文件名,line是往文件中添加一行内容(默认添加到文件末尾
  • path和line都是固定格式,文件名可以任意,文件内容可以任意
  • regexp=旧的内容(需要被修改的内容),replace=新的内容(内容任意)

    regexp=支持正则表达式(regexp是regular expression的缩写,正则表达式的意思)
  • 9)  第九个模块:user模块

  • user模块可以创建用户,配置用户信息(uid,组,密码,登录shell,家目录等),删除用户
  • //远程所有主机,创建tuser1用户,不做任何多余设置,用户所有属性都使用默认值
  • [root@control ansible]# ansible   all    -m    user    -a    "name=tuser1"
  • //创建用户tuser2,设置用户的属性
  • [root@control ansible]# ansible   all   -m   user \
  •  -a    "name=tuser2   uid=1020   group=adm  \
  •  groups=daemon,root    home=/home/tuser2    shell=/bin/bash"
  • 备注:name=指定用户名,uid=指定用户ID号,group=指定基本组
  • groups=指定附加组,home=指定用户的家目录,shell指定用户的登录shell解释器
  • admdaemon都是linux系统原本就自带的组的名称
  • 所有参数都是设计软件时定义好的不能变,参数的值可以任意
  • 如何验证:
  • 打开node1,node2,node3,node4,node5
  • 执行:#  id   tuser2
  • 执行:#  cat   /etc/passwd
  • CentOS7,CentOS8,RHEL7,RHEL8系统默认都是要求用户的密码使用sha512加密
  • //远程test组,给tuser1修改密码,密码是abc,密码经过管道做sha512加密
  • [root@control ansible]# ansible test -m user \
  •  -a "name=tuser1    password={{ 'abc' | password_hash('sha512')}}"
  • 备注:name=指定用户名,password=指定密码,linux要求密码必须是sha512加密
  • 所以把明文密码abc管道给password_hash程序加密,使用的是sha512算法加密
  • {{}}是固定格式,设计程序的人要求的!!
  • //删除用户,不删除家目录(类似于userdel)
  • [root@control ansible]# ansible   all   -m   user   \
  • -a    "name=tuser1    state=absent"
  • 备注:ansible远程所有主机,调用user模块,name指定用户名,state=absent代表删除用户
  • 如何验证:
  • 打开node1执行命令# id   tuser1,查看是否有用户,ls  /home/查看是否还有家目录
  • //删除用户,同时删除家目录(类似于userdel  -r)
  • [root@control ansible]# ansible   all   -m   user   \
  •  -a    "name=tuser2    state=absent   remove=true"
  • 如何验证:
  • 打开node1执行命令# id   tuser1,查看是否有用户,ls  /home/查看是否还有家目录
  • 11)  第十个模块:yum_repository模块

  • yum_repository模块可以修改/etc/yum.repos.d目录下的YUM配置文件
  • 是修改YUM配置文件的模块,可以新建配置文件,修改配置文件,删除配置文件
  • 这个模块所有的操作都是在/etc/yum.repos.d目录,不需要人为自己指定路径
  • 重要提示:下面的案例,仅演示语法,不考虑YUM合法性,创建后必须删除
  • [root@control ansible]# ansible    all    -m    yum_repository   \
  • -a    "name=benben   description=dachui   \
  •   baseurl=ftp://1.1.1.1     enabled=1    gpgcheck=0"
  • 备注:ansible远程所有主机,-m调用yum_repository模块自动创建YUM配置文件
  • name=benben,ansible会自动创建一个benben.repo文件,文件中有[benben]
  • description=dachui,对应yum配置文件中的name=dachui
  • baseurl,enabled,gpgcheck都是yum配置文件中的内容
  • 如何验证:
  • 打开node1,执行# cat  /etc/yum.repos.d/benben.repo,查看是有YUM配置文件
  • 翻历史命令,修改下参数,比如baseurl或者gpgcheck等
  • //没有benben则创建yum配置,有benben则修改yum配置文件
  • [root@control ansible]# ansible    all    -m    yum_repository   \
  • -a    "name=benben   description=dachui   \
  •   baseurl=ftp://2.2.2.2     enabled=0    gpgcheck=1"
  • 如何验证:
  • 打开node1,执行# cat  /etc/yum.repos.d/benben.repo,查看YUM配置文件
  • //删除yum配置文件
  • [root@control ansible]# ansible all -m yum_repository -a "name=benben state=absent"
  • //name=指定yum配置文件的名称,state=absent是删除yum配置文件
  • 如何验证:
  • 打开node1,执行# ls  /etc/yum.repos.d/  ,查看YUM配置文件是被删除
  • 重要提示:上面的案例,仅演示语法,不考虑YUM合法性,创建后必须删除

11)  第十一模块:yum模块

  • yum模块可以安装软件,卸载软件,升级软件
  • state=present代表安装软件,state=latest代表升级软件,state=absent代表卸载软件
  • //node1-node5默认都没有安装unzip软件,批量给所有主机安装unzip软件
  • [root@control ansible]# ansible   all   -m    yum    -a    "name=unzip"
  • 备注:调用yum模块,安装软件,state默认值为present,name=指定需要安装的软件名
  • [root@control ansible]# ansible all   -m   yum   -a   "name=unzip  state=latest"
  • 备注:调用yum模块,升级软件,state=latest代表升级,name=指定需要升级的软件名
  • 备注:name=‘*’的话,可以升级计算机的所有软件
  • [root@control ansible]# ansible all   -m   yum   -a   "name=unzip  state=absent"
  • 备注:调用yum模块,卸载软件,state=absent代表卸载,name=指定需要升级的软件名

12) 第十二模块:service模块

  • service模块可以管理服务,启动服务,关闭服务,重启服务,设置开机自启动
  • 使用httpd练习service模块,为了防止没有安装httpd,这里先使用yum模块装包
  • yum模块有幂等性,有这个包则不安装,没有则安装
  • [root@control ansible]# ansible   all   -m    yum    -a    "name=httpd"
  • service模块里面,state=started代表启动服务,state=stopped代表关闭服务
  • state=restarted代表重启服务,enabled=yes代表开启自启动,enabled=no关闭开机自启
  • =yes或=1是一个意思,=no和=0是一个意思!
  • [root@control ansible]# ansible  all  -m  service  -a  "name=httpd state=started"
  • 备注:远程所有主机,-m调用service模块,-a传递参数给模块
  • name=定义软件名称,state=started代表启动服务
  • 如何验证:
  • 打开node1:执行# systemctl   status   httpd ,检查服务是否启动
  • [root@control ansible]# ansible  all  -m  service  -a  "name=httpd state=stopped"
  • 备注:远程所有主机,-m调用service模块,-a传递参数给模块
  • name=定义软件名称,state=stopped代表关闭服务
  • 如何验证:
  • 打开node1:执行# systemctl   status   httpd ,检查服务是否启动(应该是关闭的)
  • [root@control ansible]# ansible  all  -m  service  -a  "name=httpd state=restarted"
  • 备注:远程所有主机,-m调用service模块,-a传递参数给模块
  • name=定义软件名称,state=restarted代表重启服务
  • 如何验证:
  • 打开node1:执行# systemctl   status   httpd ,检查服务是否启动(应该是开启的)
  • [root@control ansible]# ansible  all  -m  service  -a "name=httpd  enabled=yes"
  • 备注:远程所有主机,-m调用service模块,-a传递参数给模块
  • name=定义软件名称,enabled=yes代表设置开机自启动
  • 如何验证:
  • 打开node1:执行# systemctl   is-enabled   httpd ,检查服务是否为开机自启
  • 13)  第十三模块:lvg、lvol模块(跟逻辑卷有关的模块)
  • 开启node1虚拟机,给新硬盘分两个分区(大小不限),分区类型不限,不需要格式化
  • Linux系统安装了lvm2这个软件后,电脑才有pvcreate,vgcreate,lvcreate命令
  • //为了防止node1没有lvm2软件,这里通过ansible安装该软件
  • [root@control ansible]# ansible node1 -m yum -a "name=lvm2"
  • [root@control ansible]# ansible  node1   -m  lvg   -a  "vg=myvg   pvs=/dev/sdb1" 
  • 备注:ansible远程node1,-m调用lvg模块,-a给模块传递参数
  • vg=定义卷组名称,pvs=指定使用哪些硬盘做pv,组成vg卷组
  • pvs(s代表复数)可以是一块硬盘或分区,也可以是多个硬盘或分区,多个中间分号分隔
  • 如何验证:

    打开node1,执行命令# vgs 命令,查看是否有卷组
  • //翻历史命令,在pvs后面额外再添加一个分区,给vg扩容

    [root@control ansible]# ansible   node1  -m    lvg \

    -a    "vg=myvg    pvs=/dev/sdb1,/dev/sdb3"

  • 查看:
  • 备注:对myvg做扩容,使用sdb1和sdb3两个分区组成卷组

######  使用lvol模块创建逻辑卷

  • [root@control ansible]# ansible node1   -m   lvol   -a    "lv=mylv   vg=myvg  size=4g"
  • 备注:ansible远程node1,-m调用lvol模块,-a给模块传递参数
  • lv=定义需要创建的逻辑卷名称,
  • vg=定义使用哪个卷组创建逻辑卷
  • size=定义逻辑卷大小(容量任意,自己定义)
  • 如何验证:
  • 打开node1,执行命令# lvs 命令,查看LV逻辑卷是否被创建
  • //翻历史,把size修改为5G
  • [root@control ansible]# ansible node1   -m   lvol   -a    "lv=mylv   vg=myvg  size=5g"
  • 如何验证:
  • 打开node1,执行命令# lvs 命令,查看LV逻辑卷容量是否有变化
  • //删除逻辑卷
  • [root@control ansible]# ansible   node1   -m   lvol \
  • -a   "lv=mylv   vg=myvg   state=absent    force=yes"
  • 备注:ansible远程node1主机,-m调用lvol模块,-a给模块传递参数
  • lv=定义需要删除的逻辑卷名称,vg=指定逻辑卷的卷组,state=absent代表删除逻辑卷
  • force=yes代表强制删除
  • 如何验证:
  • 打开node1,执行# lvs   命令,查看是否有逻辑卷
  • //删除卷组
  • [root@control ansible]# ansible node1   -m   lvg   -a   "vg=myvg    state=absent"
  • 备注:ansible远程node1主机,-m调用lvg模块,-a给模块传递参数
  • vg=指定需要删除的卷组名称,state=absent代表删除的意思
  • 如何验证:
  • 打开node1,执行# vgs   命令,查看是否有卷组
  • 注:
  • ansible默认并发量为5,如果你有N台主机需要ansible远程;

    则ansible一次只远程其中5台,分多次远程;

    如果觉得并发了不够,则修改ansible.cfg配置文件forks=10,forks=20,forks=100....;

    但是,不是值越大越好,值越大,越占用计算机资源.

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值