ceph部署

ceph部署(mon)

更改的yum源(我这里用的公司的)
[root@node29 ~]# cat /etc/yum.repos.d/ceph.repo 
[obs-ceph]
name=Obs-Ceph-CentOS-$releasever
baseurl=http://10.1.31.40/ceph-rpm-centos7-x86_64-basic/ref/v14.2.11-2022071420/$basearch/
gpgcheck=0
[obs-ceph-noarch]
name=Obs-Ceph-CentOS-$releasever Noarch
baseurl=http://10.1.31.40/ceph-rpm-centos7-x86_64-basic/ref/v14.2.11-2022071420/noarch/
gpgcheck=0
You have new mail in /var/spool/mail/root
[root@node29 ~]# yum install ceph 

安装时遇到问题: 提示无法访问 host,后来发现,在yum.repos.d中,有个repo是失效的(用yum安装时会对 yum.repos.d 的源都检查一遍),所以无法通过,通过ip找到对应的rppo文件并移除就可以安装了

image-20220727194704455

安装完成后查看ceph 版本

[root@node31 tmp]# ceph -v
ceph version 14.2.11-2022071420 (cfbcf2f104d05f7d6c69573d275597371890966e) nautilus (stable)
安装mon准备工作

最开始是要先安装一个mon(moniter),mon也是集群最为关键的组件

创建 mon需要三个信息:

  • mon 名字

  • 集群 id (uuid)

  • 秘钥环 (认证信息)每个集群都需要个id,可以用uuidgen生产,将mon节点和节点ip和FSID进行映射并保存到指定文件中

集群id

uuidgen #k可以生产 uuid
monmaptool --create --add {hostname} {ip-address} --fsid {uuid} /tmp/monmap

秘钥环

#为 mon 创建秘钥环,并创建用户  用户名为  mon.
sudo ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'

#也是生成一个client,名字为  client.admin,以后的登录集群默认 使用这个用户(执行 ceph -s 默认指定的用户)
sudo ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'

#生成  client.bootstrap-osd, 引导osd用户 
sudo ceph-authtool --create-keyring /var/lib/ceph/bootstrap-osd/ceph.keyring --gen-key -n client.bootstrap-osd --cap mon 'profile bootstrap-osd' --cap mgr 'allow r'


#将 用户 client.admin的 keyring  加入到 mon中,bootstrap-osd也是、
#这里操作只是 把keyring文件拷贝到 mon的 keyring中
#mon 是管理秘钥的
sudo ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring
sudo ceph-authtool /tmp/ceph.mon.keyring --import-keyring /var/lib/ceph/bootstrap-osd/ceph.keyring

生成 monmap,使用 monmaptool 可以生成 ,需要结合 节点主机ip,和mon的名字,以及 fsid,可以生成 monmap

ceph中的map 我理解是存放某个功能节点信息的

[root@node29 bootstrap-osd]# monmaptool -h
usage: monmaptool [--print] [--create [--clobber] [--fsid uuid]]
        [--enable-all-features]
        [--generate] [--set-initial-members]
        [--add name 1.2.3.4:567] [--rm name]
        [--feature-list [plain|parseable]]
        [--feature-set <value> [--optional|--persistent]]
        [--feature-unset <value> [--optional|--persistent]]
        [--set-min-mon-release <release-major-number>]
        <mapfilename>
You have new mail in /var/spool/mail/root
[root@node29 bootstrap-osd]# monmaptool --create --add mon-node29 10.1.23.29  --fsid e518351f-a867-4ce6-b0c5-2e40a2bfcd1c /tmp/monmap
#查看生成了什么 
[root@node29 bootstrap-osd]# cat /tmp/monmap 
??¨gL?.@???^e??? ^e???  
mon-node298
mon-node29 
 
#用 monmaptool工具也可以看 打印的是 monmap的纯文本视图
[root@node29 bootstrap-osd]# monmaptool --print /tmp/monmap
monmaptool: monmap file /tmp/monmap
epoch 0
fsid e518351f-a867-4ce6-b0c5-2e40a2bfcd1c
last_changed 2022-08-10 15:59:26.547689
created 2022-08-10 15:59:26.547689
min_mon_release 0 (unknown)
0: v1:10.1.23.29:6789/0 mon.mon-node29
[root@node29 bootstrap-osd]# 

创建mon 数据的文件夹

sudo mkdir /var/lib/ceph/mon/{cluster-name}-{hostname}
[root@node29 bootstrap-osd]# sudo -u ceph mkdir -p /var/lib/ceph/mon/ceph-mon-node29

关联 mon进程 和 密钥,并且初始化 mon 数据目录

#ceph-mon -h 可以查看使用命令,不过 官网更为详细  https://docs.ceph.com/en/quincy/man/8/ceph-mon/
sudo -u ceph ceph-mon [--cluster {cluster-name}] --mkfs -i {hostname} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring

# --mkfs 初始化 保存mon 数据的目录  

#注意节点名字要和你的集群名字一致
sudo -u ceph ceph-mon --mkfs -i mon-node29 --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring

#执行后在 mon 的数据目录里多了
[root@node29 ceph-mon-node29]# ls -rh /var/lib/ceph/mon/ceph-mon-node29
store.db  kv_backend  keyring
# 是个 rocksdb数据库? 

最后编辑配置文件

vi /etc/ceph/ceph.conf
[global]
fsid = a7f64266-0894-4f1e-a635-d0aeaca0e993   # 用 uuidgen生产的uid
mon initial members = mon-node29
mon host = 192.168.0.1   #节点ip
public network = 192.168.0.0/24  #   掩码

# cephx 是一种验证方式,也可以设置为  none取消认证
auth cluster required = cephx   # 各个功能节点(mon,osd,mgr)之间交流 都是否需要验证
auth service required = cephx   # 各个功能节点(mon,osd,mgr)和集群之间的验证
auth client required = cephx    # 客户端需要验证  

osd journal size = 1024
osd pool default size = 3
osd pool default min size = 2
osd pool default pg num = 333
osd pool default pgp num = 500
osd crush chooseleaf type = 1

启动服务

sudo systemctl start ceph-mon@mon-node29
sudo systemctl status ceph-mon@mon-node29
#最后要 ceph -s验证下
[root@node29 ~]# ceph -s
  cluster:
    id:     311a4057-0837-4af8-92ab-a8053e4a3a57
    health: HEALTH_WARN
            OSD count 1 < osd_pool_default_size 3
 
  services:
    mon: 1 daemons, quorum mon-node29 (age 3h)
    mgr: node29(active, since 3h)
    osd: 1 osds: 1 up (since 2h), 1 in (since 2h)
 
  data:
    pools:   0 pools, 0 pgs
    objects: 0 objects, 0 B
    usage:   1.0 GiB used, 299 GiB / 300 GiB avail
    pgs:     

如果服务没有启,可以去 ceph的日志查看,定位问题

image-20220727202748125

添加多个 mon

一般来说,一个集群要三个 mon(选举),现在有三台服务器,每个服务器都安装一个mon

同步配置文件和秘钥

在ceph.conf 添加 节点ip和 mon 名字

#这里我添加的  mon-node31    推荐 mon名字格式为    mon-{hostname}
[root@node29 mon]# cat /etc/ceph/ceph.conf 
[global]
fsid = e518351f-a867-4ce6-b0c5-2e40a2bfcd1c 
mon initial members = mon-node29,mon-node30,mon-node31   #添加了 mon-node31
mon host = 10.1.23.29,10.1.23.30,10.1.23.31     #添加了 10.1.23.31    
public network = 10.1.23.0/24

auth cluster required = cephx
auth service required = cephx
auth client required = cephx

osd journal size = 1024
osd pool default size = 3
osd pool default min size = 2
osd pool default pg num = 333
osd pool default pgp num = 33

#debug_mon=20

#我这里将 ceph配置 和  client的keyring都拷贝到 node31上
[root@node29 mon]# scp /etc/ceph/* node31:/etc/ceph/
ceph.client.admin.keyring                                                        100%  151   189.6KB/s   00:00    
ceph.conf                                                                        100%  429     1.0MB/s   00:00    
You have new mail in /var/spool/mail/root
[root@node29 mon]# 

#bootstrap-osd 的keyring 也拷贝过去,这个为以后添加 osd做准备 
[root@node29 mon]#  scp /var/lib/ceph/bootstrap-osd/ceph.keyring root@node31:/var/lib/ceph/bootstrap-osd/
ceph.keyring                                                                     100%  129    13.9KB/s   00:00    
[root@node29 mon]# 

#复制最为关键的  mon 的keyring 
[root@node29 mon]#  scp /tmp/ceph.mon.keyring root@node31:/tmp/ceph.mon.keyring
ceph.mon.keyring                                                                 100%  506   668.9KB/s   00:00    
#--------------------------------------------------
#现在登录到 node31上,要注意这些操作是在那台机子上操作的
#--------------------------------------------------


#创建  保存mon数据目录 
[root@node31 lib]# sudo -u ceph mkdir -p /var/lib/ceph/mon/ceph-mon-node31

#刚才 复制了配置文件 和 client.admin 的keyring,现在可以和集群交互
#获取 集群中的mon. 的keyring,其实这一步我也可以在 node29上导出后再拷贝过来
[root@node31 mon]#  ceph auth get mon. -o /tmp/ceph.mon.keyring
exported keyring for mon.

#获取集群的 monmap
[root@node31 ~]# ceph mon getmap -o /tmp/ceph.mon.map
got monmap epoch 5

#初始化 mon   (这几步和部署第一个 mon是一样的)
[root@node31 ~]# sudo -u ceph ceph-mon --mkfs -i mon-node31 --monmap /tmp/ceph.mon.map --keyring /tmp/ceph.mon.keyring

#最为关键的一步   将mon添加到 集群内
[root@node31 ceph-mon-node31]# ceph mon add mon-node31 10.1.23.31:6789
adding mon.node2 at [v2:10.1.23.31:3300/0,v1:10.1.23.31:6789/0]
#启动 mon
[root@node31 ceph-mon-node31]# systemctl start ceph-mon@mon-node31

[root@node29 ~]# ceph -s
  cluster:
    id:     e518351f-a867-4ce6-b0c5-2e40a2bfcd1c
    health: HEALTH_WARN
            OSD count 2 < osd_pool_default_size 3
            clock skew detected on mon.mon-node30
 
  services:
    mon: 3 daemons, quorum mon-node29,mon-node30,mon-node31 (age 2m)
    mgr: node29(active, since 9h)
    osd: 2 osds: 2 up (since 23h), 2 in (since 23h)
 
  data:
    pools:   0 pools, 0 pgs
    objects: 0 objects, 0 B
    usage:   2.0 GiB used, 148 GiB / 150 GiB avail
    pgs:     
 
[root@node29 ~]# 


ceph 最开始 是要先创建一个 moniter ,最先创建的用户也是 mon,接下来创建 client,他们各自都有 keyring,上文有个步骤是将 client的 keyring 加入到mon的keyring,mon是有保存 client.admin 的秘钥,用户形成都是这 向下开始;刚才还有一个 bootstrap-osd也加入了 mon的keyring,这个 bootstrap-osd 以后将引导生成 osd用户;

集群启动,mon最先启动,然后才启动osd,mon启动时候是不需要想任何进程进行秘钥验证,其他用户验证操作时候,需要向mon进行验证keyring


添加mgr 节点

​ eph-mgr 的主要功能是提供外部监测和管理系统的接口

  1. 在ceph里各个节点 都要有秘钥进行认证 ,所以 创建 mgr前应该为添加秘钥

    # ceph auth get-or-create mgr.$name mon 'allow profile mgr' osd 'allow *' mds 'allow *'
    
    # 这命令的用途可以用  ceph auth -h 查看
    
    #(很多命令都可以以 ceph {模块功能名字} -h 查看到,当然如果你以 ceph -h是查看全部的)
    
    #我的 hostname 为node29上弄,所以mgr名字为 
    ceph auth get-or-create mgr.node29 mon 'allow *' osd 'allow *'
    #查看是否生产 mgr.node29的认证秘钥
    [root@node29 ceph-node29]# ceph auth get mgr.node29
    exported keyring for mgr.node29
    [mgr.node29]
    	key = AQBE/OBi5oFENxAAj5QZVDRi7NMOveXQTjathA==
    	caps mon = "allow *"
    	caps osd = "allow *"
    
  2. 创建mgr的数据目录

    # mkdir /var/lib/ceph/mgr/ceph-{hostname}/
    mkdir /var/lib/ceph/mgr/ceph-node29
    
  3. 将刚才生成的秘钥导出为 keyring

    ceph auth get mgr.node29 -o /var/lib/ceph/mgr/ceph-node29/keyring
    
  4. 启动mgr

    # ceph-mgr -i {hostname}
    ceph-mgr -i mgr.node29
    

添加osd

L版本中 ceph-disk 都被 ceph-volum 取代了,下面都是都使用ceph-volume 创建osd

傻瓜式安装:

用 ceph-volume 添加里面有很多细节,我看安装的日志,好像是执行了很多脚本,这里面具体细节原理,以后再补充(留坑)

#ceph-volume inventory 可以用于检测这个磁盘能否做 osd 
[root@node29 ceph]# ceph-volume inventory /dev/sdd3

====== Device report /dev/sdd3 ======

     available                 True
     rejected reasons          
     path                      /dev/sdd3
     device id                 QEMU_HARDDISK_drive-scsi0-0-0-1
     human readable size       50.00 GB
[root@node29 ceph]# 

  1. 用 ceph-volume 创建osd(osd在其他服务器上)

    #将其他其他节点的硬盘用做osd,需要有认证文件 
    # 将/var/lib/ceph/bootstrap-osd/ceph.keyring 拷贝到对应的服务上
    # 还需要拷贝相应的ceph配置文件
    #使用 ceph-volume 在osd节点创建osd 
    sudo ceph-volume lvm create --data /dev/hdd1
    
    
    
  2. 激活 osd

    #生产osd 可以查看osd 的id 和fsid
    [root@node31 ~]# ceph-volume lvm list
    
    
    ====== osd.2 =======
    
      [block]       /dev/ceph-ffbb3830-6bbf-4c6a-9e64-4d2817e64965/osd-block-5b5f3d72-caed-4369-91c1-c1667951a5e7
    
          block device              /dev/ceph-ffbb3830-6bbf-4c6a-9e64-4d2817e64965/osd-block-5b5f3d72-caed-4369-91c1-c1667951a5e7
          block uuid                ri9l8O-g17I-s2wn-memc-vJt0-B3E1-B2tSdX
          cephx lockbox secret      
          cluster fsid              311a4057-0837-4af8-92ab-a8053e4a3a57
          cluster name              ceph
          crush device class        None
          encrypted                 0
          osd fsid                  5b5f3d72-caed-4369-91c1-c1667951a5e7
          osd id                    2
          osdspec affinity          
          type                      block
          vdo                       0
          devices                   /dev/sdb
    #同过id 和fsid 激活 osd 
    
    sudo ceph-volume lvm activate 2 5b5f3d72-caed-4369-91c1-c1667951a5e7
    
    
    #如果osd 挂掉了    osd tree 里  状态为dowm
    #可以使用 systemctl restart重启服务,  @后面数字为 osd序号
    systemctl restart ceph-osd@3.service
    
  3. 验证

    #ceph -s 可以查看
    
手动安装
#需要一个 uuid
#以下相当于执行shell 脚本(只是抽出来一条一条执行)
[root@node31 ~]# UUID=$(uuidgen)
#UUID 会保存到当前bash 环境中
[root@node31 ~]# echo $UUID
47225359-3e97-4c95-b1ae-992339d44ddc

[root@node31 ~]# OSD_SECRET=$(ceph-authtool --gen-print-key)
[root@node31 ceph-4]# echo $OSD_SECRET
AQCotPVihM3rDBAAJ1ikAGBHtti5ogVSrZ/xRg==
[root@node31 ceph-4]# 


#获取 OSD的id 其实也可以推断出来,osd tree 就可以看到  osd.{number},新的 ID为  number+1 即可
ceph osd new $UUID 
[root@node31 ceph-4]#  ID = $(ceph osd new 2aff9fe6-eef8-4da2-9a03-d33ef062b2bb)
5
#注意,我这里是可以直接登录 集群的,如果你没有 keyring,需要想办法把 keyring 拷贝你要操作的机器上
# 创建osd目录  磁盘挂载的目录

mkdir /var/lib/ceph/osd/ceph-$ID

#格式化磁盘  (为甚用xfs 还没弄清楚)
mkfs.xfs /dev/sdb
#挂载 
mount /dev/sdb /var/lib/ceph/osd/ceph-$ID

#将 osd keyring 加入到 集群中
ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-$ID/keyring \
     --name osd.$ID --add-key $OSD_SECRET

#初始化
ceph-osd -i $ID --mkfs --osd-uuid $UUID

# 启动 osd 服务 
systemctl start ceph-osd@$ID


改变osd层级

在部署 OSD 时,它们会自动添加到 CRUSH 映射中的主机存储桶下,这个存储桶以运行它们的节点命名,默认是平面节点层次,但实际上为了故障隔离,可以添加不同的 bucket类型 到默认的层级中, 如 osd(device)host,chassis,rack,row,datacenter,zone,region,root等
实现 层级可以是 rack -> host -> osd

  1. 添加rack

    #添加rack
    ceph osd crush add-bucker rack01 rack
    
  2. 改变层级

    #默认是 osd直接在host下的,所以要需要修改host的root
    # ceph osd crush move 所在层级名 父层级名
    ceph osd crush move node31 rack=rack03
    
  3. 改变后效果

    [root@node29 ceph-node29]# ceph osd tree
    ID  CLASS WEIGHT  TYPE NAME           STATUS REWEIGHT PRI-AFF 
     -1       0.87900 root default                                
     -9       0.29300     rack rack01                             
     -3       0.29300         host node29                         
      0   hdd 0.29300             osd.0       up  1.00000 1.00000 
    -10       0.29300     rack rack02                             
     -5       0.29300         host node30                         
      1   hdd 0.29300             osd.1       up  1.00000 1.00000 
    -11       0.29300     rack rack03                             
     -7       0.29300         host node31                         
      2   hdd 0.29300             osd.2       up  1.00000 1.00000 
    # weight 是指定osd对应磁盘大小,
    # REWEIGHT
    

添加池

Ceph 的池是一个用来存储对象的逻辑分区,每个池中有一定数量pg,通过pg可以吧一定数量的对象映射到不同OSD中,

  1. 创建pool
#ceph osd pool create {pool-name} [{pg-num} [{pgp-num}]] [replicated] \[crush-rule-name] [expected-num-objects]
#PG是指定存储池存储对象的目录有多少个,PGP是存储池PG的OSD分布组合个数
#可以指定 
[root@node29 ceph-node29]# ceph osd pool create pool_A1 128 128 replicated 
pool 'pool_A1' created

  1. 查看 pool 信息
#查看创建的池  rados lspools也可以  ceph osd pool ls detail可以查看更多信息
[root@node29 ceph-node29]# ceph osd lspools
2 pool_A1
[root@node29 ceph-node29]# ceph osd pool ls detail
pool 2 'pool_A1' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 128 pgp_num 128 autoscale_mode warn last_change 38 flags hashpspool stripe_width 0

#查看 新建pool 的信息  
# ceph osd pool get {poolname} {value}
# value 是你想获得的信息
#eg
[root@node29 ceph-node29]# ceph osd pool get pool_A1 min_size
min_size: 2
[root@node29 ceph-node29]# ceph osd pool get pool_A1 pg_num
pg_num: 128
[root@node29 ceph-node29]# ceph osd pool get pool_A1 crush_rule
crush_rule: replicated_rule
[root@node29 ceph-node29]# ceph osd pool get pool_A1 size
size: 3
#如果忘记value参数,可以  ceph osd pool get 就会有其他value 参数了

#查看当前池的配额 对多可以存多少个对象 ,最多可以保存多大数据
[root@node29 ceph-3]# ceph osd pool get-quota pool_A1
quotas for pool 'pool_A1':
  max objects: 1k objects
  max bytes  : 10 GiB
[root@node29 ceph-3]# 


  1. 修改 pool 配置信息
#ceph osd pool set {pool-name} {key} {value}
#如更改 pool的副本数
ceph osd pool set pool_A1 size 3 
#这里面的 key 也就是上一步 get 里的value,不知道key参数可以参考上一步(当然官方文档有更详细的解释)

#设置pool里面最大object数量
ceph osd pool set-quota {poolname} max_objects {number}
[root@node29 ceph-node29]# ceph osd pool set-quota pool_A1 max_objects 1000
set-quota max_objects = 1000 for pool pool_A1


#设置pool里面最大容量
ceph osd pool set-quota {poolname}  max_bytes {byte number}
[root@node29 ceph-node29]# ceph osd pool set-quota pool_A1  max_bytes $((10 * 1024 * 1024 * 1024))
set-quota max_bytes = 10737418240 for pool pool_A1

[root@node29 ceph-node29]# ceph osd pool ls detail
pool 2 'pool_A1' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 128 pgp_num 128 autoscale_mode warn last_change 41 flags hashpspool max_bytes 10737418240 max_objects 1000 stripe_width 0

  1. 删除pool
#如果直接删除 
ceph osd pool delete    {poolname}  {poolname} --yes-i-really-really-mean-it
#如果直接执行 可能会出现
Error EPERM: pool deletion is disabled; you must first set the mon_allow_pool_delete config option to true before you can destroy a pool
#解决方案 : 在配置文件 ceph.conf 中添加  mon allow pool delete = true

rados命令实践

1. 池相关命令

再上一步添加池后,使用 rados命令对池增删数据,当然 rados也可以对创建池

#往池里加入一个对象,对象名为 obj_A  文件名为 mem_history
[root@node29 home]# rados -p pool_A1 put obj_A mem_history
#查看已插入的对象
[root@node29 home]# rados -p pool_A1 ls
obj_A
#查看对象信息
[root@node29 home]#  rados -p pool_A1 stat obj_A 
pool_A1/obj_A mtime 2022-07-28 17:34:54.000000, size 7943881
#查看资源池信息
[root@node29 home]# rados df -p pool_A1
POOL_NAME   USED OBJECTS CLONES COPIES MISSING_ON_PRIMARY UNFOUND DEGRADED RD_OPS      RD WR_OPS      WR USED COMPR UNDER COMPR 
pool_A1   23 MiB       1      0      3                  0       0        0     11 7.6 MiB      5 7.6 MiB        0 B         0 B 

total_objects    1
total_used       3.0 GiB
total_avail      897 GiB
total_space      900 GiB
# 资源池可以看出 存入了一个对象,占用了23m的空间 

#获取池里的对象内容 并导出来 -p 指的是poolname  get 后面 对象名 紧接着 输出的文件
[root@node29 home]# rados -p pool_A1 get obj_A tmp | head -n1 tmp
root     516703  1.2  0.1 16320864 419544 ?     Sl   09:15   0:10 python3 /opt/expontech/obs-manager/obs_manager/csm_manager_status.py
[root@node29 home]# 

#对象 追加内容
# rados -p pool_A1 append obj_A mem_history


#删除 对象
# rados -p pool_A1 rm obj_A


 3                  0       0        0     11 7.6 MiB      5 7.6 MiB        0 B         0 B 

total_objects 1
total_used 3.0 GiB
total_avail 897 GiB
total_space 900 GiB

资源池可以看出 存入了一个对象,占用了23m的空间

#获取池里的对象内容 并导出来 -p 指的是poolname get 后面 对象名 紧接着 输出的文件
[root@node29 home]# rados -p pool_A1 get obj_A tmp | head -n1 tmp
root 516703 1.2 0.1 16320864 419544 ? Sl 09:15 0:10 python3 /opt/expontech/obs-manager/obs_manager/csm_manager_status.py
[root@node29 home]#

#对象 追加内容

rados -p pool_A1 append obj_A mem_history

#删除 对象

rados -p pool_A1 rm obj_A


.....









​		
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值