linux systemd_在Linux上启动时了解systemd

linux systemd

在本系列的第一篇文章“ 学习热爱systemd ”中,我研究了systemd的功能和体系结构以及围绕它替代旧的SystemV init程序和启动脚本的角色的争议。 在第二篇文章中,我将开始探索管理Linux启动顺序的文件和工具。 我将说明systemd启动顺序,如何更改默认启动目标(以SystemV术语表示运行级别),以及如何在不进行重新引导的情况下手动切换到其他目标。

我还将介绍两个重要的系统化工具。 第一个是systemctl命令,它是与systemd交互并向其发送命令的主要方式。 第二个是journalctl ,它提供对包含大量系统历史数据(例如内核和服务消息(信息和错误消息))的系统日志的访问。

在本文以及以后的文章中,请确保使用非生产系统进行测试和实验。 您的测试系统需要安装GUI桌面(例如Xfce,LXDE,Gnome,KDE或其他)。

我在上一篇文章中写道,我打算研究如何创建systemd单元并将其添加到本文的启动顺序中。 因为这篇文章的长度超出了我的预期,所以我将在本系列的下一篇文章中保留它。

使用systemd探索Linux启动

GRUB的主要配置文件是/boot/grub2/grub.cfg ,但是,由于更新内核版本时可以覆盖此文件,因此您不想更改它。 而是修改/ etc / default / grub文件,该文件用于修改grub.cfg的默认设置。

首先查看/ etc / default / grub文件的当前未修改版本:


   
   
[ root @ testvm1 ~ ] # cd /etc/default ; cat grub
GRUB_TIMEOUT = 5
GRUB_DISTRIBUTOR = " $(sed 's, release .*$,,g' /etc/system-release) "
GRUB_DEFAULT =saved
GRUB_DISABLE_SUBMENU = true
GRUB_TERMINAL_OUTPUT = "console"
GRUB_CMDLINE_LINUX = "resume=/dev/mapper/fedora_testvm1-swap rd.lvm.
lv=fedora_testvm1/root rd.lvm.lv=fedora_testvm1/swap rd.lvm.lv=fedora_
testvm1/usr rhgb quiet"

GRUB_DISABLE_RECOVERY = "true"
[ root @ testvm1 default ] #

GRUB文档的第6章包含/ etc / default / grub文件中所有可能条目的列表,但我主要关注以下内容:

  • 我改变GRUB_TIMEOUT,秒为GRUB菜单倒数数,从5到10给多一点时间来响应GRUB菜单倒计时降为零之前。
  • 我删除了GRUB_CMDLINE_LINUX的最后两个参数,该参数列出了引导时传递给内核的命令行参数。 其中一个参数rhgb代表Red Hat Graphical Boot,它在内核初始化期间显示Fedora图标动画,而不显示启动时消息。 另一个( 安静参数)可防止显示记录启动过程和发生的任何错误的启动消息。 我删除了rhgbquiet,因为系统管理员需要查看这些消息。 如果在引导过程中出现问题,则屏幕上显示的消息可能会指出问题的原因。

进行这些更改之后,您的GRUB文件将如下所示:


   
   
[ root @ testvm1 default ] # cat grub
GRUB_TIMEOUT = 10
GRUB_DISTRIBUTOR = " $(sed 's, release .*$,,g' /etc/system-release) "
GRUB_DEFAULT =saved
GRUB_DISABLE_SUBMENU = true
GRUB_TERMINAL_OUTPUT = "console"
GRUB_CMDLINE_LINUX = "resume=/dev/mapper/fedora_testvm1-swap rd.lvm.
lv=fedora_testvm1/root rd.lvm.lv=fedora_testvm1/swap rd.lvm.lv=fedora_
testvm1/usr"

GRUB_DISABLE_RECOVERY = "false"
[ root @ testvm1 default ] #

grub2-mkconfig程序使用/ etc / default / grub文件的内容来生成grub.cfg配置文件,以修改某些默认的GRUB设置。 grub2-mkconfig程序将其输出发送到STDOUT 。 它具有-o选项,允许您指定一个文件以将数据流发送到该文件,但是使用重定向同样容易。 运行以下命令以更新/boot/grub2/grub.cfg配置文件:


   
   
[ root @ testvm1 grub2 ] # grub2-mkconfig > /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: / boot / vmlinuz-4.18.9- 200 .fc28.x86_64
Found initrd image: / boot / initramfs-4.18.9- 200 .fc28.x86_64.img
Found linux image: / boot / vmlinuz-4.17.14- 202 .fc28.x86_64
Found initrd image: / boot / initramfs-4.17.14- 202 .fc28.x86_64.img
Found linux image: / boot / vmlinuz-4.16.3- 301 .fc28.x86_64
Found initrd image: / boot / initramfs-4.16.3- 301 .fc28.x86_64.img
Found linux image: / boot / vmlinuz- 0 -rescue-7f12524278bd40e9b10a085bc82dc504
Found initrd image: / boot / initramfs- 0 -rescue-7f12524278bd40e9b10a085bc82dc504.img
done
[ root @ testvm1 grub2 ] #

重新启动测试系统以查看启动消息,否则这些启动消息将隐藏在Plymouth启动动画之后。 但是,如果您需要查看启动消息并且未禁用Plymouth启动动画怎么办? 还是您有,但是消息流以太快的速度无法阅读? (他们这样做。)

有两种选择,它们都涉及日志文件和系统日志,这些都是您的朋友。 您可以使用less命令查看/ var / log / messages文件的内容。 该文件包含启动和启动消息以及操作系统在正常操作期间生成的消息。 您也可以使用不带任何选项的journalctl命令来查看systemd日志,该日志实质上包含相同的信息:


   
   
[ root @ testvm1 grub2 ] # journalctl
-- Logs begin at Sat 2020 -01- 11 21 : 48 :08 EST, end at Fri 2020 -04-03 08: 54 : 30 EDT. --
Jan 11 21 : 48 :08 f31vm.both.org kernel: Linux version 5.3.7- 301 .fc31.x86_64 ( mockbuild @ bkernel03.phx2.fedoraproject.org ) ( gcc version 9.2.1 20190827 ( Red Hat 9.2.1- 1 ) ( GCC ) ) #1 SMP Mon Oct >
Jan 11 21 : 48 :08 f31vm.both.org kernel: Command line: BOOT_IMAGE = ( hd0,msdos1 ) / vmlinuz-5.3.7- 301 .fc31.x86_64 root = / dev / mapper / VG01-root ro resume = / dev / mapper / VG01-swap rd.lvm.lv=VG01 / root rd >
Jan 11 21 : 48 :08 f31vm.both.org kernel: x86 / fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
Jan 11 21 : 48 :08 f31vm.both.org kernel: x86 / fpu: Supporting XSAVE feature 0x002: 'SSE registers'
Jan 11 21 : 48 :08 f31vm.both.org kernel: x86 / fpu: Supporting XSAVE feature 0x004: 'AVX registers'
Jan 11 21 : 48 :08 f31vm.both.org kernel: x86 / fpu: xstate_offset [ 2 ] :   576 , xstate_sizes [ 2 ] :   256
Jan 11 21 : 48 :08 f31vm.both.org kernel: x86 / fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format.
Jan 11 21 : 48 :08 f31vm.both.org kernel: BIOS-provided physical RAM map:
Jan 11 21 : 48 :08 f31vm.both.org kernel: BIOS-e820: [ mem 0x0000000000000000-0x000000000009fbff ] usable
Jan 11 21 : 48 :08 f31vm.both.org kernel: BIOS-e820: [ mem 0x000000000009fc00-0x000000000009ffff ] reserved
Jan 11 21 : 48 :08 f31vm.both.org kernel: BIOS-e820: [ mem 0x00000000000f0000-0x00000000000fffff ] reserved
Jan 11 21 : 48 :08 f31vm.both.org kernel: BIOS-e820: [ mem 0x0000000000100000-0x00000000dffeffff ] usable
Jan 11 21 : 48 :08 f31vm.both.org kernel: BIOS-e820: [ mem 0x00000000dfff0000-0x00000000dfffffff ] ACPI data
Jan 11 21 : 48 :08 f31vm.both.org kernel: BIOS-e820: [ mem 0x00000000fec00000-0x00000000fec00fff ] reserved
Jan 11 21 : 48 :08 f31vm.both.org kernel: BIOS-e820: [ mem 0x00000000fee00000-0x00000000fee00fff ] reserved
Jan 11 21 : 48 :08 f31vm.both.org kernel: BIOS-e820: [ mem 0x00000000fffc0000-0x00000000ffffffff ] reserved
Jan 11 21 : 48 :08 f31vm.both.org kernel: BIOS-e820: [ mem 0x0000000100000000-0x000000041fffffff ] usable
Jan 11 21 : 48 :08 f31vm.both.org kernel: NX ( Execute Disable ) protection: active
Jan 11 21 : 48 :08 f31vm.both.org kernel: SMBIOS 2.5 present.
Jan 11 21 : 48 :08 f31vm.both.org kernel: DMI: innotek GmbH VirtualBox / VirtualBox, BIOS VirtualBox 12 / 01 / 2006
Jan 11 21 : 48 :08 f31vm.both.org kernel: Hypervisor detected: KVM
Jan 11 21 : 48 :08 f31vm.both.org kernel: kvm-clock: Using msrs 4b564d01 and 4b564d00
Jan 11 21 : 48 :08 f31vm.both.org kernel: kvm-clock: cpu 0 , msr 30ae01001, primary cpu clock
Jan 11 21 : 48 :08 f31vm.both.org kernel: kvm-clock: using sched offset of 8250734066 cycles
Jan 11 21 : 48 :08 f31vm.both.org kernel: clocksource: kvm-clock: mask: 0xffffffffffffffff max_cycles: 0x1cd42e4dffb, max_idle_ns: 881590591483 ns
Jan 11 21 : 48 :08 f31vm.both.org kernel: tsc: Detected 2807.992 MHz processor
Jan 11 21 : 48 :08 f31vm.both.org kernel: e820: update [ mem 0x00000000-0x00000fff ] usable == > reserved
Jan 11 21 : 48 :08 f31vm.both.org kernel: e820: remove [ mem 0x000a0000-0x000fffff ] usable
< snip >

我截断了这个数据流,因为它可能长达数十万甚至数百万行。 (我的主工作站上列出的日志长1,188,482行。)请确保在您的测试系统上尝试使用此日志。 如果已经运行了一段时间(即使已多次重新引导),则将显示大量数据。 探索此日记数据,因为它包含许多信息,这些信息在确定问题时可能非常有用。 了解正常启动和启动时这些数据的外观可以帮助您在问题发生时定位问题。

在本系列的后续文章中,我将讨论系统日志, journalctl命令,以及如何对所有数据进行排序以找到所需的内容。

GRUB将内核加载到内存中之后,它必须首先从文件的压缩版本中提取自身,然后才能执行任何有用的工作。 内核提取自身并开始运行后,它将加载systemd并将控制权移交给它。

引导过程到此结束。 此时,Linux内核和systemd正在运行,但由于没有其他运行,因此无法为最终用户执行任何生产性任务,没有外壳程序可提供命令行,没有后台进程来管理网络或其他通信链接,并且没有使计算机能够执行任何生产性功能的功能。

现在,Systemd可以加载使系统进入选定的目标运行状态所需的功能单元。

目标

systemd目标表示Linux系统的当前或期望的运行状态。 与SystemV启动脚本非常相似,目标定义了必须存在的服务才能使系统在该状态下运行并处于活动状态。 图1显示了使用systemd的Linux系统的可能运行状态目标。 从本系列的第一篇文章和systemd引导手册页(man bootup)中可以看出,启用各种必要服务还需要其他中间目标。 这些可以包括swap.targettimers.targetlocal-fs.target等。 一些目标(如basic.target )用作检查点,以确保在继续到下一个更高级别的目标之前,所有必需的服务都已启动并正在运行。

除非在引导时在GRUB菜单中进行了其他更改,否则systemd始终会启动default.targetdefault.target文件是指向真实目标文件的符号链接。 对于台式机工作站,通常将是graphic.target ,等效于SystemV中的运行级别5。 对于服务器,默认值更可能是multi-user.target ,类似于SystemV中的运行级别3。 Emergency.target文件类似于单用户模式。 目标和服务是系统单位。

我在本系列的上一篇文章中包含的下表将systemd目标与旧的SystemV启动运行级别进行了比较。 systemd提供的目标别名是向后兼容的。 目标别名允许脚本(和sysadmins)使用SystemV命令(如init 3)更改运行级别。 当然,SystemV命令将转发给systemd进行解释和执行。

systemd targets SystemV运行级别 目标别名 描述
default.target 这个目标总是与一个符号链接要么multi-user.targetgraphical.target别名。 systemd始终使用default.target启动系统。 default.target绝不应别名为halt.targetpoweroff.targetreboot.target
graphical.target 5 runlevel5.target Multi-user.target使用GUI
  4 runlevel4.target 没用过。 运行级别4与SystemV世界中的运行级别3相同。 可以创建和定制此目标以启动本地服务,而无需更改默认的multi-user.target
multi-user.target 3 runlevel3.target 所有服务正在运行,但仅命令行界面(CLI)
  2 runlevel2.target 多用户,没有NFS,但所有其他非GUI服务正在运行
rescue.target 1个 runlevel1.target 基本系统,包括仅在运行最基本服务的情况下挂载文件系统,并在主控制台上安装急救外壳
emergency.target 小号 单用户模式-没有服务正在运行; 文件系统未挂载。 这是最基本的操作级别,只有在主控制台上运行的紧急外壳供用户与系统交互。
halt.target 在不关闭电源的情况下暂停系统
reboot.target 6 runlevel6.target 重启
poweroff.target 0 runlevel0.target 停止系统并关闭电源

图1:比较SystemV运行级别与systemd目标和目标别名。

每个目标在其配置文件中都有一组依赖性。 systemd启动所需的依赖关系,这些依赖关系是在特定功能级别上运行Linux主机所需的服务。 加载并运行目标配置文件中列出的所有依赖项后,系统将在该目标级别运行。 如果需要,您可以在本系列的第一篇文章学习爱戴systemd中查看systemd的启动顺序和运行时目标。

探索当前目标

许多Linux发行版默认都安装GUI桌面界面,因此可以将已安装的系统用作工作站。 我总是从带有Xfce或LXDE桌面的Fedora Live启动USB驱动器安装。 即使在安装服务器或其他基础结构类型的主机(例如用于路由器和防火墙的主机)时,我也会使用其中一种安装GUI桌面的安装。

我可以安装不带桌面的服务器(这对于数据中心来说是典型的),但这不能满足我的需求。 并不是我需要GUI桌面本身,而是LXDE安装包括我使用的许多其他工具,这些工具不在默认服务器安装中。 初始安装后,这对我来说意味着更少的工作。

但是仅仅因为我有一个GUI桌面并不意味着使用它就有意义。 我有一个16端口KVM,可以用来访问大多数Linux系统的KVM接口,但与它们的绝大多数交互是通过主工作站上的远程SSH连接进行的。 与graphic.target相比,这种方式更安全,使用更少的系统资源来运行multi-user.target

首先,请检查默认目标以确认它是graphic.target


   
   
[ root @ testvm1 ~ ] # systemctl get-default
graphical.target
[ root @ testvm1 ~ ] #

现在,验证当前正在运行的目标。 它应该与默认目标相同。 您仍然可以使用旧方法,该方法显示旧的SystemV运行级别。 注意,先前的运行级别在左侧; 它是N (表示“无”),表示自启动主机以来运行级别未更改。 数字5表示当前目标,如旧SystemV术语中所定义:


   
   
[ root @ testvm1 ~ ] # runlevel
N 5
[ root @ testvm1 ~ ] #

请注意,运行级别手册页指示运行级别已过时,并提供了转换表。

您也可以使用systemd方法。 此处没有单行答案,但确实以系统术语提供了答案:


   
   
[ root @ testvm1 ~ ] # systemctl list-units --type target
UNIT                   LOAD   ACTIVE SUB    DESCRIPTION                
basic.target           loaded active active Basic System              
cryptsetup.target      loaded active active Local Encrypted Volumes    
getty.target           loaded active active Login Prompts              
graphical.target       loaded active active Graphical Interface        
local-fs-pre.target    loaded active active Local File Systems ( Pre )  
local-fs.target        loaded active active Local File Systems        
multi-user.target      loaded active active Multi-User System          
network-online.target  loaded active active Network is Online          
network.target         loaded active active Network                    
nfs-client.target      loaded active active NFS client services        
nss-user-lookup.target loaded active active User and Group Name Lookups
paths.target           loaded active active Paths                      
remote-fs-pre.target   loaded active active Remote File Systems ( Pre )  
remote-fs.target       loaded active active Remote File Systems        
rpc_pipefs.target      loaded active active rpc_pipefs.target          
slices.target          loaded active active Slices                    
sockets.target         loaded active active Sockets                    
sshd-keygen.target     loaded active active sshd-keygen.target        
swap.target            loaded active active Swap                      
sysinit.target         loaded active active System Initialization      
timers.target          loaded active active Timers                    

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

21 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files' .

这显示了所有当前已加载和活动的目标。 您还可以看到graphical.targetmulti-user.target。 可以加载graphical.targetmulti-user.target是必需的。 在此示例中, graphical.target是活动的。

切换到其他目标

切换到multi-user.target很容易:

 [ root @ testvm1 ~ ] # systemctl isolate multi-user.target 

现在,显示应该从GUI桌面或登录屏幕更改为虚拟控制台。 登录并列出当前活动systemd单位验证graphical.target不再运行:

 [ root @ testvm1 ~ ] # systemctl list-units --type target 

确保使用runlevel命令验证它是否同时显示了先前和当前的“运行级别”:


   
   
[ root @ testvm1 ~ ] # runlevel
5 3

更改默认目标

现在,将默认目标更改为multi-user.target,以便它将始终引导至控制台命令行界面而不是GUI桌面界面的multi-user.target 。 以测试主机上的root用户身份,切换到维护systemd配置的目录,并进行快速列出:


   
   
[ root @ testvm1 ~ ] # cd /etc/systemd/system/ ; ll
drwxr-xr-x. 2 root root 4096 Apr 25   2018  basic.target.wants
< snip >
lrwxrwxrwx. 1 root root   36 Aug 13 16 : 23  default.target - > / lib / systemd / system / graphical.target
lrwxrwxrwx. 1 root root   39 Apr 25   2018  display-manager.service - > / usr / lib / systemd / system / lightdm.service
drwxr-xr-x. 2 root root 4096 Apr 25   2018  getty.target.wants
drwxr-xr-x. 2 root root 4096 Aug 18 10 : 16  graphical.target.wants
drwxr-xr-x. 2 root root 4096 Apr 25   2018  local-fs.target.wants
drwxr-xr-x. 2 root root 4096 Oct 30 16 : 54  multi-user.target.wants
< snip >
[ root @ testvm1 system ] #

我缩短了清单,以突出显示一些重要的内容,这些内容将有助于解释systemd如何管理引导过程。 您应该能够看到虚拟机上目录和链接的完整列表。

default.target条目是指向目录/lib/systemd/system/graphical.target的符号链接(符号链接,软链接)。 列出该目录以查看其他目录:

 [ root @ testvm1 system ] # ll /lib/systemd/system/ | less 

你应该看到的文件,目录和更多的链接在此列表,但专门为multi-user.targetgraphical.target期待。 现在显示default.target的内容,该内容是/lib/systemd/system/graphical.target的链接:


   
   
[ root @ testvm1 system ] # cat default.target
#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[ Unit ]
Description =Graphical Interface
Documentation =man:systemd.special ( 7 )
Requires =multi-user.target
Wants =display-manager.service
Conflicts =rescue.service rescue.target
After =multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate = yes
[ root @ testvm1 system ] #

此指向graphic.target文件的链接描述了图形用户界面所需的所有先决条件和要求。 在本系列的下一篇文章中,我将至少探讨其中一些选项。

为了使主机能够引导到多用户模式,您需要删除现有链接并创建一个指向正确目标的新链接。 如果尚未将PWD / etc / systemd / system设置为:


   
   
[ root @ testvm1 system ] # rm -f default.target
[ root @ testvm1 system ] # ln -s /lib/systemd/system/multi-user.target default.target

列出default.target链接以验证它是否链接到正确的文件:


   
   
[ root @ testvm1 system ] # ll default.target
lrwxrwxrwx 1 root root 37 Nov 28 16 :08 default.target - > / lib / systemd / system / multi-user.target
[ root @ testvm1 system ] #

如果您的链接看起来不完全像这样,请将其删除,然后重试。 列出default.target链接的内容:


   
   
[ root @ testvm1 system ] # cat default.target
#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[ Unit ]
Description =Multi-User System
Documentation =man:systemd.special ( 7 )
Requires =basic.target
Conflicts =rescue.service rescue.target
After =basic.target rescue.service rescue.target
AllowIsolate = yes
[ root @ testvm1 system ] #

default.target (实际上是至此multi-user.target的链接)现在在[Unit]部分中具有不同的要求。 它不需要图形显示管理器。

重启。 您的虚拟机应引导至虚拟控制台1的控制台登录名,该登录名在显示屏上标识为tty1。 现在你知道如何更改默认的目标,改变它采用专为目的的命令给graphical.target。

首先,检查当前的默认目标:


   
   
[ root @ testvm1 ~ ] # systemctl get-default
multi-user.target
[ root @ testvm1 ~ ] # systemctl set-default graphical.target
Removed / etc / systemd / system / default.target.
Created symlink / etc / systemd / system / default.target → / usr / lib / systemd / system / graphical.target.
[ root @ testvm1 ~ ] #

输入以下命令,直接进入图形对象和显示管理器登录页面,而无需重新引导:

 [ root @ testvm1 system ] # systemctl isolate default.target 

我不知道为什么systemd的开发人员为此子命令选择了“隔离”一词。 我的研究表明,这可能是指运行指定的目标,但“隔离”并终止不需要支持该目标的所有其他目标。 但是,其效果是将目标从一个运行目标切换到另一个运行目标,在这种情况下,是从多用户目标切换到图形目标。 上面的命令等效于SystemV启动脚本和init程序中的init 5命令。

登录到GUI桌面,并验证它是否可以正常工作。

加起来

本文探讨了Linux systemd启动顺序,并开始探索两个重要的systemd工具systemctljournalctl 。 它还说明了如何从一个目标切换到另一个目标以及如何更改默认目标。

本系列的下一篇文章将创建一个新的systemd单元,并将其配置为在启动期间运行。 它还将查看一些配置选项,例如,在网络启动并运行后,这些配置选项可帮助确定特定单元从何处开始。

资源资源

互联网上有大量有关systemd的信息,但是很多信息简洁,晦涩甚至是误导。 除了本文提到的资源之外,以下网页还提供了有关systemd启动的更详细和可靠的信息。

  • Fedora项目对systemd有很好的实用指南 。 它具有使用systemd配置,管理和维护Fedora计算机所需的几乎所有知识。
  • Fedora项目还有一个很好的备忘单 ,可以将旧的SystemV命令与可比的systemd命令进行交叉引用。
  • 有关systemd及其创建原因的详细技术信息,请查看Freedesktop.org 对systemd描述
  • Linux.com的“更多系统乐趣”提供了更多高级系统信息和技巧

还有systemd的设计师和主要开发者Lennart Poettering撰写的一系列针对Linux sysadmin的技术性文章。 这些文章是在2010年4月至2011年9月之间撰写的,但它们现在和那时一样具有相关性。 关于systemd及其生态系统的许多其他优点都基于这些论文。

翻译自: https://opensource.com/article/20/5/systemd-startup

linux systemd

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值