当前位置:   article > 正文

Docker超详细版教程通俗易懂 -之- 进阶篇_1075308026

1075308026

此刻的你,已成功入门Docker。让我们一起继续深造(内容不难,很有意思)

容器数据卷

什么是容器数据卷

docker的理念回顾:将应用和环境打包成一个镜像!

数据?如果数据都在容器中,那么我们容器删除,数据就会丢失! ==> 需求:数据可以持久化

比如说MySQL,容器删除了 = 删库跑路! ==> 需求:MySQL数据可以存储在本地!

需求解决方案:容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地! 这就是卷技术!其实就是目录的挂载,将我们容器内的目录,挂载到Linux上面!

总结:容器的持久化和同步操作!容器间也是可以数据共享的!

使用数据卷

方式一 :直接使用命令挂载 -v(volume)

  1. $ docker run -it -v 主机目录:容器内目录 -p 主机端口:容器内端口
  2. $ docker run -it -v /home/ceshi:/home centos /bin/bash
  3. #启动之后 通过 docker inspect 容器id 查看

 测试文件的同步:容器到主机

  1. # 容器内:
  2. [root@3ec5cc8602f0 home]# ls
  3. [root@3ec5cc8602f0 home]# touch test.java # 容器内touch一个test.java
  4. [root@3ec5cc8602f0 home]# ls
  5. test.java
  6. [root@3ec5cc8602f0 home]#
  7. # 主机
  8. $ cd /home
  9. $ ls
  10. ceshi test.java
  11. $ cd ceshi/
  12. [root@iZbp14hqhlaba6gliuurxtZ ceshi]# ls
  13. [root@iZbp14hqhlaba6gliuurxtZ ceshi]# ls
  14. test.java # 主机上自动同步
  15. [root@iZbp14hqhlaba6gliuurxtZ ceshi]#
  16. # 同步的过程 双向绑定

再来测试文件的同步:主机到容器

  1. #1、停止容器
  2. #2、宿主机修改文件
  3. #3、启动容器
  4. #4、容器内的数据依旧是同步的
  5. # 主机
  6. [root@iZbp14hqhlaba6gliuurxtZ ceshi]# ls
  7. test.java zhuji.java
  8. [root@iZbp14hqhlaba6gliuurxtZ ceshi]# vim test.java
  9. [root@iZbp14hqhlaba6gliuurxtZ ceshi]# cat test.java
  10. hello,linux update!
  11. # 容器内
  12. [root@iZbp14hqhlaba6gliuurxtZ ceshi]# ls
  13. test.java zhuji.java
  14. [root@iZbp14hqhlaba6gliuurxtZ ceshi]# cat test.java
  15. hello,linux update

好处:我们以后修改只需要在本地修改即可,容器内会自动同步!

实战演练

MySQL

思考:MySQL的数据持久化的问题

  1. # 1. 搜索mysql
  2. $ docker search mysql
  3. # 2. 获取mysql镜像
  4. $ docker pull mysql:8.0
  5. # 3. 运行容器,需要做数据挂载 # 安装启动mysql,需要配置密码的,这是要注意点!
  6. # 官方hub启动:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
  7. #启动我们得
  8. -d 后台运行
  9. -p 端口映射
  10. -v 卷挂载
  11. -e 环境配置
  12. -- name 容器名字
  13. $ docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=12345678 --name mysql mysql:8.0
  14. # 启动成功之后,我们在本地使用navicat来测试一下
  15. # navicat--连接到服务器的3306--服务器的3306和容器内的3306映射,连接成功。
  16. # 使用navicat创建一个数据库,查看一下我们主机服务器映射的路径是否ok!(如下图)

假设我们将容器删除,发现,我们挂载到本地的数据卷依旧没有丢失,这就实现了容器数据持久化功能。 

具名挂载和匿名挂载

  1. # 匿名挂载
  2. -v 容器内路径
  3. $ docker run -d -P --name nginx -v /etc/nginx nginx
  4. 5ddab046a7cec5439db1a4c6f6f8c6fb7684edb7265be01ae804bc71729017ed
  5. # 查看所有的volume的情况
  6. $ docker volume ls
  7. DRIVER VOLUME NAME
  8. local 34c19cc6a21d4887f20c0087eabe5c5a4dec68c624120ab94d8b0d72f61bb1b5
  9. local 7788c8a710268524d8c5510cc6b1b4cd33772f4af1d4e609515c8c86dc76d1ff
  10. local 26869f42a943f077387967eeb7c7b64dce8812b797da482343e1f21a1af7039e
  11. local a1f00efa0c67081feda7e8503a10a748fa0c0350a770c085dcf1889573f41b2b
  12. # 这里发现,这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路径!
  1. # 具名挂载
  2. -v 卷名:容器内路径
  3. $ docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
  4. ab97eaaab89f1be8c49595389a31caf3f2de1dede1971b2905da0da4027f6ef6
  5. # 查看所有的volume的情况
  6. $ docker volume ls
  7. DRIVER VOLUME NAME
  8. local juming-nginx
  9. # 这里发现,这种就是具名挂载!
  10. # 查看一下这个卷
  11. $ docker volume inspect juming-nginx

所有的docker容器内的卷,没有指定目录的情况下都是在
/var/lib/docker/volumes/xxxx/_data
 

我们通过具名挂载,可以很方便的找到卷,一般推荐使用具名挂载

  1. # 三种挂载: 匿名挂载、具名挂载、指定路径挂载
  2. -v 容器内路径 # 匿名挂载
  3. -v 卷名:容器内路径 # 具名挂载
  4. -v /宿主机路径:容器内路径 # 指定路径挂载 ==> docker volume ls 是查看不到的

拓展

  1. # 通过 -v 容器内路径: ro rw 改变读写权限
  2. ro #readonly 只读
  3. rw #readwrite 可读可写
  4. # 一旦设置了容器权限,容器对我们挂载出来的内容就有限定了!
  5. $ docker run -d -P --name nginx05 -v juming:/etc/nginx:ro nginx
  6. $ docker run -d -P --name nginx05 -v juming:/etc/nginx:rw nginx
  7. # ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作!

初始Dockerfile

Dockerfile 就是用来构建docker镜像的构建文件!就是一段命令脚本!先体验一下!
通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个一个的命令,一个命令就是一层!

  1. # 创建一个dockerfile文件:vim dockerfile
  2. # 文件中的内容 指令(大写) 参数
  3. FROM centos
  4. VOLUME ["volume01","volume02"]
  5. CMD echo "----end----"
  6. CMD /bin/bash
  7. # 这里的每个命令就是镜像的一层!
  8. # 构建自己写的镜像
  9. $ docker build -f dockerfile -t xiao/centos:1.0 .

  1. # 运行自己写的镜像
  2. $ docker run -it 604b842ccb1a /bin/bash

  1. # 在volume01中创建 container.txt
  2. # 这个卷和外部一定有一个同步的目录,查看一下卷挂载
  3. $ docker ps
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. dc3b45ed32dc xiao/centos:1.0 "/bin/bash" About a minute ago Up About a minute boring_jennings
  6. $ docker inspect dc3b45ed32dc

测试一下刚才的文件是否同步出去了!

 这种方式使用的十分多,因为我们通常会构建自己的镜像!

假设构建镜像时候没有挂载卷,要手动镜像挂载 ==> -v 卷名:容器内路径

数据卷容器

多个MySQL同步数据!

  1. #命令:--volumes-from 只要通过--volumes-from运行的容器,数据都是相互备份的
  2. # 测试,我们通过刚才启动的
  3. $ docker run -it --name docker01 604b842ccb1a /bin/bash
  4. $ docker run -it --name docker02 --volumes-from docker01 604b842ccb1a

 测试:在创建docker03,删除docker01,查看一下docker02和docker03中文件是否依旧存在,可访问 ==>  测试依旧可以访问

多个mysql实现数据共享

  1. $ docker run -d -p 3306:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
  2. $ docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
  3. # 这个时候,可以实现两个容器数据同步!

结论

容器之间的配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
但是一旦你持久化到了本地(-v),这个时候,本地的数据是不会删除的!

DockerFile

DcokerFile介绍

dockerfile是用来构建docker镜像的文件!命令参数脚本!

构建步骤:

  1. 编写一个dockerfile文件

  2. docker build 构建称为一个镜像

  3. docker run运行镜像

  4. docker push发布镜像(DockerHub 、阿里云仓库)

查看官方是怎么做的:DockerHub上搜索镜像,点击版本跳转到GitHub仓库。比如centos

很多官方镜像都是基础包,很多功能没有,我们通常会自己搭建自己的镜像!

官方既然可以制作镜像,那我们也可以!

DockerFile构建过程

基础知识:

1. 每个保留关键字(指令)都是必须是大写字母
2. 执行从上到下顺序
3. #表示注释
4. 每一个指令都会创建提交一个新的镜像,并提交!

Dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!

Docker镜像逐渐成企业交付的标准,必须要掌握!

Docker三部曲:开发 ==> 部署 ==> 运维

DockerFile:构建文件,定义了一切的步骤,源代码

DockerImages:通过DockerFile构建生成的镜像,最终发布和运行产品。

Docker容器:容器就是镜像运行起来提供服务。 

DockerFile的指令

  1. FROM # 基础镜像,一切从这里开始构建
  2. MAINTAINER # 镜像是谁写的, 姓名+邮箱
  3. RUN # 镜像构建的时候需要运行的命令
  4. ADD # 步骤,tomcat镜像,这个tomcat压缩包!添加内容 添加同目录
  5. WORKDIR # 镜像的工作目录
  6. VOLUME # 挂载的目录
  7. EXPOSE # 保留端口配置 -p
  8. CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
  9. ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
  10. ONBUILD # 当构建一个被继承 DockerFile 这个时候就会运行ONBUILD的指令,触发指令
  11. COPY # 类似ADD,将我们文件拷贝到镜像中
  12. ENV # 构建的时候设置环境变量! -e

实战演练

centos

Docker Hub中99%的镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行构建!

创建一个自己的centos

  1. # 1. 编写Dockerfile文件
  2. $ cat mydockerfile-centos
  3. # Dockerfile脚本
  4. FROM centos
  5. MAINTAINER shen<1075308026@qq.com>
  6. ENV MYPATH /usr/local
  7. WORKDIR $MYPATH
  8. # 新的centos镜像加上vim命令
  9. RUN yum -y install vim
  10. # 新的centos镜像加上ipcongig命令
  11. RUN yum -y install net-tools
  12. EXPOSE 80
  13. CMD echo $MYPATH
  14. CMD echo "----end----"
  15. CMD /bin/bash
  16. # 2. 通过这个文件构建镜像
  17. # 命令 docker build -f dockerfile文件路径 -t 镜像名:[tag] .
  18. $ docker build -f mydockerfile-centos -t mycentos:0.1 .

  1. # 3. 测试运行 对比之前原生的centos
  2. $ docker run -it mycentos:0.1

  1. # 命令:docker history 镜像id 查看镜像的变更历史
  2. $ docker history 容器id

 我们平时拿到一个镜像,通过 docker history 可以研究一下是什么做的!

 CMD 和 ENTRYPOINT区别

  1. CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代。
  2. ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令

Tomcat

1、准备镜像文件
准备 apache-tomcat-xxx.tar.gz 和 jdk-xxx-linux-aarch64.tar.gz到当前目录,编写好README

2、编写dokerfile

  1. FROM centos
  2. MAINTAINER xiao<1075308026@qq.com>
  3. COPY README.txt /usr/local/README.txt
  4. # 添加JDK和Tomcat
  5. ADD jdk-8u301-linux-x64.tar.gz /usr/local/
  6. ADD apache-tomcat-9.0.56.tar.gz /usr/local/
  7. RUN yum -y install vim
  8. # 设置工作目录
  9. ENV MYPATH /usr/local
  10. WORKDIR $MYPATH
  11. # 配置JDK环境变量
  12. ENV JAVA_HOME /usr/local/jdk1.8.0_301
  13. ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
  14. # 配置Tomcat环境变量
  15. ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.56
  16. ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.56
  17. # 设置环境变量
  18. ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME.lib:$CATALINA_HOME.bin
  19. # 开放端口
  20. EXPOSE 8080
  21. CMD /usr/local/apache-tomcat-9.0.56/bin/startup.sh && tail -f /usr/local/apache-tomcat-9.0.56/logs/catalina.out
  22. # 此处我犯的错:1. JDK压缩包下载版本错误 2. tomcat日志记录的路径配错

3、构建镜像

  1. # 因为dockerfile命名使用默认命名 因此不用使用-f 指定文件
  2. $ docker build -t shentomcat .

4、run镜像

  1. [root@iZbp14hqhlaba6gliuurxtZ xiaotomcat]# docker run -d -p 8080:8080 --name mytomcat -v /home/shen/tomcat/project-test:/usr/local/apache-tomcat-9.0.56/webapps/project-test -v /home/shen/tomcat/logs/:/usr/local/apache-tomcat-9.0.56/logs shentomcat:latest
  2. # 注意项目的挂载映射project-test <==> webapps/project-test

5、访问测试

6、发布项目(由于做了卷挂载,我们直接在本地编写项目就可以发布了!)

7、测试项目

我们以后开发的步骤:需要掌握Dockerfile的编写!我们之后的一切都是使用docker镜像来发布运行!

发布自己的镜像

Dockerhub

1、地址 Docker Hub (需要注册账号)

2、确定这个账号可以登录

  1. # 服务器登陆上个人账户
  2. $ docker login -u 0312520
  3. Password:
  4. WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
  5. Configure a credential helper to remove this warning. See
  6. https://docs.docker.com/engine/reference/commandline/login/#credentials-store
  7. Login Succeeded

3、提交镜像 docker push

  1. # 会发现push不上去,因为如果没有前缀的话默认是push到 官方的library
  2. # 解决方法
  3. # 第一种 build的时候添加你的dockerhub用户名,然后在push就可以放到自己的仓库了
  4. $ $ docker build -t 0312520/shentomcat:1.0 .
  5. # 第二种 使用docker tag #然后再次push
  6. $ $ docker tag 容器id 0312520/shentomcat:1.0
  7. #然后再次push

阿里云镜像服务上

  1. 登陆阿里云-容器镜像服务

  2. 创建命名空间

  3. 创建容器镜像(本地仓库)

  4. 查看容器镜像,操作参考操作指南即可

小结

Docker网络原理

准备:
关闭所有容器,清空所有镜像

理解Docker 0

查看docker网络 -- 三个网络,Docker0网络Docker自带

问题: docker 是如果处理容器网络访问的?

  1. # 启动tomcat容器后,如果没有ip和ping指令,进入容器执行
  2. $ apt update && apt install -y iproute2   # 添加ip指令
  3. $ apt update && apt install iputils-ping && apt install net-tools # 添加ping指令
  1. # 1. 启动一个容器(tomcat01)
  2. $ docker run -d -P --name tomcat01 tomcat
  3. $ docker exec -it tomcat01 ip addr

  1. # 2. 再启动一个容器(tomcat02)
  2. $ docker run -d -P --name tomcat02 tomcat
  3. $ docker exec -it tomcat02 ip addr

发现

我们发现这个容器的网卡,都是一对对的,也就是veth-pair。
veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
正因为有这个特性 veth-pair 充当一个桥梁,连接各种虚拟网络设备的
OpenStac,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术

  1. 3. 我们来测试下tomcat01和tomcat02是否可以ping通 ==> 可以Ping通!
  2. $ docker exec -it tomcat01 ping 172.17.0.3

原理

tomcat01和tomcat02公用一个路由器,docker0。所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用ip。

小结

Docker使用的是Linux的桥接,宿主机是一个Docker容器的网桥 docker0

Docker中所有网络接口都是虚拟的,虚拟的转发效率高(内网传递文件非常快!)

只要容器删除,对应的网桥一对就没了!

思考一个场景:我们编写了一个微服务,database url=ip: 项目不重启,数据ip换了,我们希望可以处理这个问题,可以通过名字来进行访问容器?

  1. $ docker exec -it tomcat02 ping tomca01
  2. ping: tomca01: Name or service not known
  3. # 可以如何解决呢? ==> 通过--link解决
  4. # 运行一个tomcat03 --link tomcat02
  5. $ docker run -d -P --name tomcat03 --link tomcat02 tomcat
  6. 5f9331566980a9e92bc54681caaac14e9fc993f14ad13d98534026c08c0a9aef
  7. $ docker exec -it tomcat03 ping tomcat02
  8. PING tomcat02 (172.17.0.3) 56(84) bytes of data.
  9. 64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.127 ms
  10. 64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.081 ms
  11. 64 bytes from tomcat02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.085 ms
  12. # 用tomcat02 ping tomcat03 ping不通

探究:

  1. [root@iZbp14hqhlaba6gliuurxtZ ~]# docker network ls
  2. NETWORK ID NAME DRIVER SCOPE
  3. 10f2bc28fc11 bridge bridge local
  4. c748c5881a3b host host local
  5. 9e2af451b635 none null local
  6. [root@iZbp14hqhlaba6gliuurxtZ ~]# docker network inspect 10f2bc28fc11

$ docker inspect tomcat03

  1. # 查看tomcat03里面的/etc/hosts发现有tomcat02的配置
  2. $ docker exec tomcat03 cat /etc/hosts

–link 本质就是在hosts配置中添加映射(现在使用Docker已经不建议使用–link)!

要使用自定义网络!不适用docker0!
docker0问题:不支持容器名连接访问!

自定义网络

查看所有的docker网络

网络模式
bridge :桥接 docker(默认,自己创建也是用bridge模式)
none :不配置网络,一般不用
host :和宿主共享网络
container :容器网络连通(用得少!局限很大)

 测试

  1. # 我们直接启动的命令 --net bridge,而这个就是我们得docker0
  2. $ docker run -d -P --name tomcat01 tomcat 等价于 docker run -d -P --name tomcat01 --net bridge tomcat
  3. # docker0,特点:默认,域名不能访问。 --link可以打通连接,但是很麻烦!
  4. # 我们可以 自定义一个网络
  5. # --driver bridge
  6. # --subnet 192.168.0.0/16(192.168.0.2-192.168.255.255)
  7. # --gateway 192.168.0.1
  8. $ docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
  9. 95e026d87c5887bc174f21884d87b77377502f1be54c8c9f7312613a56ec39ed
  10. $ docker network ls
  11. NETWORK ID NAME DRIVER SCOPE
  12. 10f2bc28fc11 bridge bridge local
  13. c748c5881a3b host host local
  14. 95e026d87c58 mynet bridge local
  15. 9e2af451b635 none null local

自己的网络就创建好了

  1. # 启动两个tomcat,使用自己创建的网络,再次查看网络情况
  2. $ docker run -d -P --name tomcat-mynet-01 --net mynet tomcat
  3. $ docker run -d -P --name tomcat-mynet-02 --net mynet tomcat

在自定义的网络下,服务可以互相ping通,而不用使用–link 
自定义网络docker已经维护好了对应的关系,建议平时这样使用!
 

网络连通

  1. # 使用默认的Docker0启动两个tomcat
  2. $ docker run -d -P --name tomcat-net-01 tomcat
  3. 401337d745d413b72722e21d64a4844da801820effcc36100cc3a82453107ee3
  4. $ docker run -d -P --name tomcat-net-02 tomcat
  5. 6b368d02e0c225b625594d94ced2c9b641b2299ba05d5cbe7f63d3ed42e9cbbc
  6. # 使用network connect打通tomcat-net-01和mynet
  7. $ docker network connect mynet tomcat-net-01
  8. # 观察mynet的变化
  9. $ docker network inspect mynet

 发现:打通就是将 tomcat-net-01 放到了 mynet 网络下(一个容器 两个IP)

实战

Redis集群

  1. # 创建网卡
  2. $ docker network create redis --subnet 172.38.0.0/16
  3. # 通过脚本创建六个redis配置
  4. $ for port in $(seq 1 6);
  5. do
  6. echo "Hello, welcome $port times "
  7. mkdir -p /mydata/redis/node-${port}/conf
  8. touch /mydata/redis/node-${port}/conf/redis.conf
  9. cat << EOF >> /mydata/redis/node-${port}/conf/redis.conf
  10. port 6379
  11. bind 0.0.0.0
  12. cluster-enabled yes
  13. cluster-config-file nodes.conf
  14. cluster-node-timeout 5000
  15. cluster-announce-ip 172.38.0.1${port}
  16. cluster-announce-port 6379
  17. cluster-announce-bus-port 16379
  18. appendonly yes
  19. EOF
  20. done
  21. # 通过脚本运行六个redis
  22. $ for port in $(seq 1 6);
  23. do
  24. docker run -p 637${port}:6379 -p 1667${port}:16379 --name redis-${port} -v /mydata/redis/node-${port}/data:/data -v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.1${port} redis redis-server /etc/redis/redis.conf
  25. done
  26. # redis默认没有bash
  27. $ docker exec -it redis-1 /bin/sh
  28. # 集群部署
  29. $ redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1

  1. $ redis-cli -c # 连接集群
  2. $ cluster info # 查看集群信息
  3. $ cluster nodes # 查看节点

IDEA整合Docker

  1. 构建SpringBoot项目

  2. 打包应用(jar包)

  3. 编写Dockerfile文件

    1. FROM java:8
    2. COPY *.jar /app.jar
    3. CMD ["--server.port=8080"]
    4. EXPOSE 8080
    5. ENTRYPOINT ["java","-jar","app.jar"]
  4. 构建镜像

    $ docker build -t --name hello-word-app hello-word-app .
  5. 运行镜像

    $ docker run -d -p 8080:80 hello-word-app

Docker学到这里,自己很牛了,为自己鼓掌!!!

特别感谢哔哩哔哩狂神:【狂神说Java】Docker最新超详细版教程通俗易懂_哔哩哔哩_bilibili
特别感谢哔哩哔哩狂神:【狂神说Java】Docker最新超详细版教程通俗易懂_哔哩哔哩_bilibili
特别感谢哔哩哔哩狂神:【狂神说Java】Docker最新超详细版教程通俗易懂_哔哩哔哩_bilibili

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/73490
推荐阅读
相关标签
  

闽ICP备14008679号