Docker数据卷和网络管理 下

 容器和物理机直接运行相比缺点

1性能
2隔离性,管理不方便 docker exec 
3排错方法:docker logs;docker exec; docker 前台运行;docker ps -a ;cat /var/log/syslog;message

上期·总览

FROM     指定
LABEL     标签
ENV        变量
COPY      复制 解压打包在可
ADD        复制
RUN       运行Linux命令 
ENTRYPOINT ["init.sh"]       和CMD相似金蝉推敲 ,通常用于初始化环境 脚本
CMD ["app"]          第2遍运行
EXPOSE 80 声明 docker  run -P xxxxx:80 docker run -p xxx:yyy   端口声明,P默认引用p盖

  

目录

 FROM: 指定基础镜像

VOLUME: 匿名卷

 WORKDIR: 指定工作目录

 ONBUILD: 子镜像引用父镜像的指令

USER: 指定当前用户

HEALTHCHECK: 健康检查

 .dockerignore文件

构建镜像docker build 命令

查看镜像的构建历史: 

 docker命令用法总结图

哪些数据需要持久化

数据卷使用方法     永久保存挂在  挂在:覆盖

 实战案例:实现 wordpress 持久化

数据卷容器读写共享

利用数据卷容器备份将指定匿名容器的数据卷实现备份

Docker安装后默认的网络设置 

同一个宿主机的不同容器可相互通信

 修改默认docker0(172.17.0.1)网桥的网络配置

改默认网络设置使用自定义网桥

 通过容器名称互联 

 通过自定义容器产生多个别名

Docker 网络连接模式  默认bridge#桥接模式

bridge网络模式

Host 模式   和主机共享网络

none 模式    就是没有网单机

 Container 模式      和别的容器共享网络 

 自定义网络模式

 同一个宿主机之间不同网络的容器通信

 无聊小知识:修改iptables实现同一宿主机上的不同网络的容器间通信 

 实现跨宿主机的容器之间网络互联

方式1: 利用桥接实现跨宿主机的容器间互联 

 添加静态路由和iptables规则  (生产中没法用讲原理而已)


 

 FROM: 指定基础镜像

定制镜像,需要先有一个基础镜像,在这个基础镜像上进行定制。

FROM 就是指定基础镜像,此指令通常必需放在Dockerfile文件第一个非注释行。后续的指令都是运行于此基准镜像所提供的运行环境

ARG CODE=22.04-20221017-v1.0
FROM  ubuntu:${CODE}
ENV VERSTON="1.22.0"
ENV NGINX_INSTALL_DIR="/web/nginx"
LABEL Author=weizhaohui  version=nginx-${VERSTON}

VOLUME: 匿名卷

在容器中创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等,默认会将宿主机上的目录挂载至VOLUME 指令指定的容器目录。即使容器后期被删除,此宿主机的目录仍会保留,从而实现容器数据的持久保存

名字乱码没啥用,有比没有好

/var/lib/docker/volumes/<volume_id>/_data

 没运行时 

  • 重新运行后,多了一个备份,名字为随机乱码,再次创建只会生成新的 docker rm -vf xx  加v就可以把他删了

 WORKDIR: 指定工作目录

为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录,当容器运行后,进入容器内WORKDIR指定的默认目录
WORKDIR 指定工作目录(或称当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会自行创建

WORKDIR 来代替cd的效果 在目录中切换文件是没法子集体的 他切换后,后面的文件就是基于他的基础上了   

   和CMD他俩在一起用,文件调转转换没法自用,如果我做错了,欢迎指点

 

 

 ONBUILD: 子镜像引用父镜像的指令

可以用来配置当构建当前镜像的子镜像时,会自动触发执行的指令,但在当前镜像构建时,并不会执行,即延迟到子镜像构建时才执行

这玩意简单来说,你创建一个镜像在里面写入ONBUILD RUN  rm -rf /*,别人引用你的镜像来做他自己的镜像的时候就会在电脑上执行 删根!!!或者别的命令随你怎么写~~~~

                                                                                                                     本人就是打比喻~~~

USER: 指定当前用户

  • 指定运行容器的用户名或 UID,在后续dockerfile中的 RUN ,CMD和ENTRYPOINT指令时使用此用户
  • 当服务不需要管理员权限时,可以通过该命令指定运行用户
  • 这个用户必须是事先建立好的,否则无法切换
  • 如果没有指定 USER,默认是 root 身份执行

 

 

 总结:docker需要root的权限才能起来

HEALTHCHECK: 健康检查

检查容器的健康性

 -fs的理解

在里面输入命令 

 重新启动查看 

 把首页删了就报错了,然后没了,后期在K8S博客中会有用到,欢迎关注

 .dockerignore文件

官方文档: https://docs.docker.com/engine/reference/builder/#dockerignore-file
与.gitignore文件类似,生成构建上下文时Docker客户端应忽略的文件和文件夹指定模式
.dockerignore 使用 Go 的文件路径规则 filepath.Match
参考链接: https://golang.org/pkg/path/filepath/#Match

# #以#开头的行为注释
* #匹配任何非分隔符字符序列
? #匹配任何单个非分隔符
\\ #表示 \
** #匹配任意数量的目录(包括零)例如,**/*.go将排除在所有目录中以.go结尾的所有文件,包括构
建上下文的根。
! #表示取反,可用于排除例外情况

范例:

#排除 test 目录下的所有文件
test/*
#排除 md 目录下的 xttblog.md 文件
md/xttblog.md
#排除 xttblog 目录下的所有 .md 的文件
xttblog/*.md
#排除以 xttblog 为前缀的文件和文件夹
xttblog?
#排除所有目录下的 .sql 文件夹
**/*.sql

#除了README的md不排外,排除所有md文件,但不排除README-secret.md
*.md
!README*.md
README-secret.md
#除了所有README的md文件以外的md都排除
*.md
README-secret.md
!README*.md

data 是指的镜像文件里面的,别绕就去

 

 在当前页面创建文件

 

 排除什么不考文件

 

 卷里面的东西 ,有些已经排除,有些没有

构建镜像docker build 命令

docker build命令使用Dockerfile文件创建镜像

docker build [OPTIONS] PATH | URL | -
说明:
PATH | URL | - #可以使是本地路径,也可以是URL路径。若设置为 - ,则从标准输入获取
Dockerfile的内容
-f, --file string #Dockerfile文件名,默认为 PATH/Dockerfile
--force-rm #总是删除中间层容器,创建镜像失败时,删除临时容器
--no-cache #不使用之前构建中创建的缓存
-q --quiet=false #不显示Dockerfile的RUN运行的输出结果
--rm=true #创建镜像成功时,删除临时容器
-t --tag list #设置注册名称、镜像名称、标签。格式为 <注册名称>/<镜像名称>:<标签>(标签
默认为latest)

查看镜像的构建历史: 

docker history 镜像ID

 docker命令用法总结图

 

哪些数据需要持久化

有状态的协议

有状态协议就是就通信双方要记住双方,并且共享一些信息。而无状态协议的通信每次都是独立的,与上一次的通信没什么关系。
"状态”可以理解为“记忆”,有状态对应有记忆,无状态对应无记忆

  • 左侧是无状态的http请求服务,右侧为有状态
  • 下层为不需要存储的服务,上层为需要存储的部分服务 

数据卷简单来说就是一种挂在 

据卷分类
启动容器时,可以指定使用数据卷实现容器数据的持久化,数据卷有三种

  • 指定宿主机目录或文件: 指定宿主机的具体路径和容器路径的挂载关系,此方式不会创建数据卷
  • 匿名卷: 不指定数据名称,只指定容器内目录路径充当挂载点,docker自动指定宿主机的路径进行挂载,此方式会创建匿名数据卷,Dockerfile中VOLUME指定的卷即为此种
  • 命名卷: 指定数据卷的名称和容器路径的挂载关系,此方式会创建命名数据卷 

数据卷使用方法     永久保存挂在  挂在:覆盖

docker run 命令的以下格式可以实现数据卷 

-v, --volume=[host-src:]container-dest[:<options>]
<options>
ro 从容器内对此数据卷是只读,不写此项默认为可读可写
rw 从容器内对此数据卷可读可写,此为默认值

 方式1指定宿主机目录或文件格式         两个目录数据会同步      支持多个挂载

#指定宿主机目录或文件格式:
-v <宿主机绝对路径的目录或文件>:<容器目录或文件>[:ro] #将宿主机目录挂载容器目录,两个目录
都可自动创建

方式2匿名卷  挂在会生成匿名卷,几乎没啥用 谁闲着没事记这个 

#匿名卷,只指定容器内路径,没有指定宿主机路径信息,宿主机自动生成/var/lib/docker/volumes/<卷
ID>/_data目录,并挂载至容器指定路径
-v <容器内路径>
#示例:
docker run --name nginx -v /etc/nginx nginx

方式3 命名卷将固定    docker volume ls 查看所有     删除容器数据也不丢失  可以自己创

docker volume prune #用此命令清理会把卷也清了   docker system ptune #他不会清楚

#命名卷将固定的存放在/var/lib/docker/volumes/<卷名>/_data
-v <卷名>:<容器目录路径>
#可以通过以下命令事先创建,如可没有事先创建卷名,docker run时也会自动创建卷
docker volume create <卷名>
#示例:
docker volume create vol1 #也可以事先不创建
docker run -d -p 80:80 --name nginx01 -v vol1:/usr/share/nginx/html nginx

docker rm 的 -v 选项可以删除容器时,同时删除相关联的匿名卷

 ro给其权限让其不能写(容器里面不能i写,外边宿主机可以写)

 实战案例:实现 wordpress 持久化

两条命令一执行就好好了

docker run -d -p 80:80 --name wordpress  -v /data/wordpess:/var/www/html --restart=always  wordpress:php7.4-apache

docker run --network container:wordpress  -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=123456 --name mysql -d  -v /data/mysql:/var/lib/mysql --restart=always mysql:8.0.29-oracle

数据卷容器读写共享

 之前那种方法需要创建一次输入一遍,这次这种只需要输入一次,后续继承之前创建的就可以了

 --volumes-from nginx01   继承nginx01创建的容器,他就是创建的时候依赖一下,创建之后就不依赖了,你把nginx01删了,对于之后创建完的没影响,都是共享内容

如果nginx01被你删了,你基于nginx02也是可以创建的 效果都是一样的

docker run -d --name nginx01 -p 80:80  -v volume1:/apps/nginx/html/ -v /data1:/data1 -v /data2:/data2 nginx:v1.22.0-1

docker run -d --name nginx02 -p 81:80  --volumes-from nginx01 nginx:v1.22.0-1
docker run -d --name nginx03 -p 82:80  --volumes-from nginx01 nginx:v1.22.0-1

总结: 目前只支持固定IP,K8S不适用,在K8S章节会有跳转固定访问的办法

利用数据卷容器备份将指定匿名容器的数据卷实现备份

由于匿名数据卷在宿主机中的存储位置不确定,所以为了方便的备份匿名数据卷,可以利用数据卷容器实现数据卷的备份

 A是匿名卷不知道路径,B复制用 --volumes-from继承关联一下,在B上创建另一个指定挂载文件

接着进去用备份命令在里面打个包,备份到B创建的挂载目录上,创建之前加上--rm,退出后直接删除,这样就完成了

#在执行备份命令容器上执行备份方式
docker run -it --rm --volumes-from [container name] -v $(pwd):/backup ubuntu
root@ca5bb2c1f877:/#tar cvf /backup/backup.tar [container data volume]

#说明
[container name] #表示需要备份的容器
[container data volume] #表示容器内的需要备份的数据卷对应的目录

#还原方式
docker run -it --rm --volumes-from [container name] -V $(pwd):/backup ubuntu
root@ca5bb2c1f877:/#tar xvf /backup/backup.tar -C [container data volume]

  

创建需要备份的匿名数据卷容器
[root@ubuntu1804 ~]#docker run -it -v /datavolume1 --name volume-server centos
bash

[root@88bbc22a3072 /]# ls
bin dev home lib64 media opt root sbin sys usr
datavolume1 etc lib lost+found mnt proc run srv tmp var

[root@88bbc22a3072 /]# touch /datavolume1/centos.txt
[root@88bbc22a3072 /]# exit
exit

[root@ubuntu1804 ~]#docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES

#可以看到数据卷对应的宿主机目录
[root@ubuntu1804 ~]#docker inspect --format="{{.Mounts}}" volume-server
[{volume 21199be9bff7ce98926f673d2250d64d75aaa00c5d375a2528b2b47f0ec4cb93
/var/lib/docker/volumes/21199be9bff7ce98926f673d2250d64d75aaa00c5d375a2528b2b47f
0ec4cb93/_data /datavolume1 local true }]

#基于前面的匿名数据卷容器创建执行备份操作的容器
[root@ubuntu1804 ~]#docker run -it --rm --volumes-from volume-server -v
~/backup:/backup --name backup-server ubuntu
root@9ad8be4b5810:/# ls
backup boot dev home lib32 libx32 mnt proc run srv tmp var
bin datavolume1 etc lib lib64 media opt root sbin sys usr

root@9ad8be4b5810:/# ls /backup/
root@9ad8be4b5810:/# ls /datavolume1/
centos.txt

root@9ad8be4b5810:/# cd /datavolume1/
root@9ad8be4b5810:/datavolume1# tar cvf /backup/data.tar .
./
./centos.txt
root@9ad8be4b5810:/datavolume1# exit
exit

[root@ubuntu1804 ~]#ls ~/backup/
data.tar

#删除容器的数据
[root@ubuntu1804 ~]#docker start -i volume-server
[root@88bbc22a3072 /]# rm -rf /datavolume1/*
[root@88bbc22a3072 /]# ls /datavolume1/
[root@88bbc22a3072 /]# exit
exit

#进行还原
[root@ubuntu1804 ~]#docker run --rm --volumes-from volume-server -v
~/backup:/backup --name backup-server ubuntu tar xvf /backup/data.tar -C
/datavolume1/
./
./centos.txt

#验证是否还原
[root@ubuntu1804 ~]#docker start -i volume-server
[root@88bbc22a3072 /]# ls /datavolume1/
centos.txt

范例: 利用数据卷容器备份MySQL数据库

#MySQL容器默认使用了匿名卷
[root@ubuntu1804 ~]#docker run -d --name mysql -p 3306:3306 -e
MYSQL_ROOT_PASSWORD=123456 mysql:5.7.30

[root@ubuntu1804 ~]#docker volume ls
DRIVER VOLUME NAME
local
897bd48c5c5e2067627d5c6d10dad17d4793132a638986c16f36820663728ee1

#备份数据库
[root@ubuntu1804 ~]#docker run -it --rm --volumes-from mysql -v $(pwd):/backup
centos tar xvf /backup/mysql.tar -C /var/lib/mysql

#删除数据库文件
[root@ubuntu1804 ~]#rm -rf
/var/lib/docker/volumes/897bd48c5c5e2067627d5c6d10dad17d4793132a638986c16f368206
63728ee1/_data/

#还原数据库
[root@ubuntu1804 ~]#docker run -it --rm --volumes-from mysql -v $(pwd):/backup
centos tar xvf /backup/mysql.tar -C /

Docker安装后默认的网络设置 

同一个宿主机的不同容器可相互通信

默认情况下

  • 同一个宿主机的不同容器之间可以相互通信

dockerd --icc Enable inter-container communication (default true)
--icc=false #此配置可以禁止同一个宿主机的容器之间通 

  • 不同宿主机之间的容器IP地址重复,默认不能相互通信

  daemon-reload: 重新加载某个服务的配置文件

因为更改了service文件所以要冲印加载一下,外加重启

 ping别人就ping不通了,ping自己就可以server

 

 修改默认docker0(172.17.0.1)网桥的网络配置

默认docker后会自动生成一个docker0的网桥,使用的IP是172.17.0.1/16,可能和宿主机的网段发生冲突,可以将其修改为其它网段的地址,避免冲突

注释:在service文件里也可以改,两个地方改了会打架,所以最好改一个地方

删除修改那段后他不会重新恢复到172网段,而是修改后的网段

范例: 将docker0的IP修改为指定IP

 重启后查看

 因为docker重启了,所以容器也会默认关闭,起来之后会变成修改后的ip

改默认网络设置使用自定义网桥

注意:此做法无法保存,电脑重启后docker就会起不来,需要把加的去掉重启配置就可以了

新建容器默认使用docker0的网络配置,可以修改默认指向自定义的网桥网络
范例: 用自定义的网桥代替默认的docker1

创建网桥docker1 让docker桥接到docker1 

 加上-b docker1后  执行systectl daemon-reload ;systemctl restart docker

 通过容器名称互联 

 docker run 创建容器,可使用--link选项实现容器名称的引用,其本质就是在容器内的/etc/hosts中添加- -link后指定的容器的IP和主机名的对应关系,从而实现名称解析

--link list                                  #Add link to another container
格式:
docker run --name <容器名称>                  #先创建指定名称的容器
docker run --link <目标通信的容器ID或容器名称>  #再创建容器时引用上面容器的名称

 在启动的瞬间会在web02上会考到web01的 地址解析

 通过自定义容器产生多个别名

命令格式:

docker run --name <容器名称>
#先创建指定名称的容器
docker run --name <容器名称> --link <目标容器名称>:"<容器别名1> <容器别名2> ..."
#给上面创建的容器起别名,来创建新容器

Docker 网络连接模式  默认bridge#桥接模式

Docker 的网络支持5种网络模式: 

  • none          #就是没有网单机
  • bridge        #桥接模式,默认桥接在网桥上,默认docker0
  • host            #主机模式 和主机共享网络等
  • container    
  • network-name

范例: 查看默认的网络模式有三个 

[root@ubuntu2004 ~]#docker network ls
NETWORK ID         NAME       DRIVER     SCOPE
fe08e6d23c4c       bridge     bridge   local
cb64aa83626c       host       host     local
10619d45dcd4       none       null     local

网络模式指定

默认新建的容器使用Bridge模式,创建容器时,docker run 命令使用以下选项指定网络模式

格式;      一共有五种,本质上有三种none bridge host哪两种就是桥接在默认网桥上

docker run --network <mode>
docker run --net=<mode>
<mode>: 可是以下值
none
bridge
host
container:<容器名或容器ID>
<自定义网络名称>

bridge网络模式

在docker上开启一个NAT转换,用docker容器访问外网的时候做了一个转换把172这个网段通过SNAT源地址装换成外网 他需要ip-forward 这个docker是自动打开的

 上面有修改IP地址的那个

修改桥接地址
[root@ubuntu1804 ~]#vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
--bip=10.100.0.1/24

[root@ubuntu1804 ~]#systemctl daemon-reload
[root@ubuntu1804 ~]#systemctl restart docker

Host 模式   和主机共享网络

此模式由于直接使用宿主机的网络无需转换,网络性能最高,但是各容器内使用的端口不能相同,适用于运行容器端口比较固定的业务        

简单来讲就是和你宿主机共享网络,宿主机的网络,网口等就是我的 
Host 网络模式特点:

  • 使用参数 --network host 指定
  • 共享宿主机网络
  • 网络性能无损耗
  • 网络故障排除相对简单
  • 各容器网络无隔离
  • 网络资源无法分别统计
  • 端口管理困难: 容易产生端口冲突
  • 不支持端口映射

 因为和端口共享网络所以哪怕映射端口也没用,都是默认80,第一个容器起得来第二个就起不来

因为80端口起冲突

none 模式    就是没有网单机

在使用none 模式后,Docker 容器不会进行任何网络配置,没有网卡、没有IP也没有路由,因此默认无法与外界通信,需要手动添加网卡配置IP等,所以极少使用
none模式特点
使用参数 --network none 指定
默认无网络功能,无法和外部通信
无法实现端口映射
适用于测试环境 

 Container 模式      和别的容器共享网络 

使用此模式创建的容器需指定和一个已经存在的容器共享一个网络,而不是和宿主机共享网络,

使用此模式创建的容器需指定和一个已经存在的容器共享一个网络,而不是和宿主机共享网络,新创建的容器不会创建自己的网卡也不会配置自己的IP,而是和一个被指定的已经存在的容器共享IP和端口范围,因此这个容器的端口不能和被指定容器的端口冲突,除了网络之外的文件系统、进程信息等仍然保持相互隔离,两个容器的进程可以通过lo网卡进行通信

Container 模式特点

  • 使用参数 –-network container:名称或ID 指定
  • 与宿主机网络空间隔离
  • 空器间共享网络空间
  • 适合频繁的容器间的网络通信
  • 直接使用对方的网络,较少使用

 因为web02和web01共享一个网络所以如果在一个程序的话会起冲突,需要在另一个不同的镜像里起来

你依附人家就不用做端口暴露了,没用,都是同一个网络

因为数据库授权账号问题(和权限没关)·你有localhost解析也没法子在里面用,只能写端口号

docker run -d -p 80:80 --name wordpress  -v /data/wordpess:/var/www/html --restart=always  wordpress:php7.4-apache

docker run --network container:wordpress  -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=123456 --name mysql -d  -v /data/mysql:/var/lib/mysql --restart=always mysql:8.0.29-oracle

%是不能写localhost,只能写ip 

 

 自定义网络模式

除了以上的网络模式,也可以自定义网络,使用自定义的网段地址,网关等信息

注意: 自定义网络内的容器可以直接通过容器名进行相互的访问,而无需使用 --link
可以使用自定义网络模式,实现不同集群应用的独立网络管理,而互不影响,而且在网一个网络内,可以直接利用容器名相互访问,非常便利

创建自定义网络:

docker network create -d <mode> --subnet <CIDR> --gateway <网关> <自定义网络名称>
#注意mode不支持host和none,默认是bridge模式 

查看自定义网络信息

 docker network inspect <自定义网络名称或网络ID>

引用自定义网络

docker run --network <自定义网络名称> <镜像名称>
docker run --net <自定义网络名称> --ip <指定静态IP> <镜像名称>
#注意:静态IP只支持自定义网络模型 

删除自定义网络   内置的三个网络无法删除

doccker network rm <自定义网络名称或网络ID> 

范例:默认网络模式就不需要-d 指定了,可以连接外网的

 同一样网络不需要加hosts解析就可以域名访问

 同一个宿主机之间不同网络的容器通信

开两个容器,一个使用自定义网络容器,一个使用默认brideg网络的容器,默认因iptables规则导致无法通信

 无聊小知识:修改iptables实现同一宿主机上的不同网络的容器间通信 

  把宿主机的nginx01加到专属网络中,这样Nginx01能ping通nginx02,2通不了1

 这哥们很聪明的加了一个地址,这是我最无语的

双通 

 

把他踢了 

 

 实现跨宿主机的容器之间网络互联

在后期K8S中会很容易解决。现在主要是还是说的方法理解

同一个宿主机之间的各个容器之间是可以直接通信的,但是如果访问到另外一台宿主机的容器呢?

方式1: 利用桥接实现跨宿主机的容器间互联 

两台不一样的主机和ip

在两边执行这条命令使他们做成网络桥接 #brctl addif docker0 eth0

执行完之后网络会断

 添加静态路由和iptables规则  (生产中没法用讲原理而已)

 把一个网换改掉

[root@rocky8 ~]#vim /etc/docker/daemon.json 
{
      "registry-mirrors": ["https://si7y70hh.mirror.aliyuncs.com"],
      "bip": "172.27.0.1/24"
     }

 

 在两边创建镜像名字是否一样都可以

[root@ubuntu2004 ~]#docker run -d -p 80:80 --name nginx02 nginx:1.0
8be7661a035007907bd6ee4199e215a2efe95078006376883ed2b55507cfbd41

两边地址错开不一样

 有去有回

 

 数据过来了,有来无回  

 在两边加上这个命令

 #修改iptables规则 
[root@ubuntu 2004~]#iptables -A FORWARD -s 10.0.0.0/24 -j ACCEPT

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值