(第三十九天)

一、回顾
1 、拉取私有仓库镜像
# 配置 docker
docker pull 10.0.0.10:5000/centosnginx:v0
2 、容器网络类型
brideg(net) default
# docker 启动之后会生成新的虚拟网卡,网卡的名称 docker0
# 网段默认是 172.17.0.1
# 所有的容器都桥接 docker0 ,通过桥接共享网络
brctrl show
yum -y install bridge-utils
host
# 使用方便,直接使用宿主机的 ip
# 无法并发运行多个同类的容器
docker run -it --network bridge|host|none centos:latest /bin/bash
none
3 、跨主机容器网络(两台不同主机上的容器的连接)
# A 主机上的 a1 容器可以访问 B 主机上的 b1 容器
# flanneld 技术
# 使用 flanneld 分配网段,被分配的网段都可以 ping
# 步骤
node11
docker
etcd (数据库,被 flanneld 保存网络地址网段等信息)
yum -y install etcd
# 1 、配置文件
/etc/etcd/etcd.conf
# 修改了发布服务的端口和介绍请求的端口 4001 2379
ETCD_LISTEN_CLIENT_URLS = "http://0.0.0.0:2379,http://0.0.0.0:4001"
ETCD_ADVERTISE_CLIENT_URLS = "http://10.0.0.11:2379,http://10.0.0.11:4001"
# 2 、启动服务
systemctl start etcd
# 3 、测试服务
netstat -lntup | grep 2379
netstat -lntup | grep 4001
etcdctl set a 123
etcdctl get a
# 4 、检查安全
etcdctl -C http://10.0.0.10:4001 cluster-health
flanneld
yum -y install flanneld
# 5 、配置连接数据库
vim /etc/sysconfig/flanneld
FLANNEL_ETCD_ENDPOINTS = "http://10.0.0.11:2379"
# 在启动之前要在 etcd 数据库中添加指定网段
172 .20.0.0/16
etcdctl mk /atomic.io/network/config '{ "Network" : "172.20.0.0/16" }'
# 6 、启动服务 , 在启动 flanneld 服务的时候,会先读取 etcd 中的 network 信息,确定要创建的
网段
systemctl start flanneld
# 7 、查看分配的网段
ifconfig|ip a s 查看新的 flannel0 网卡
# 8 、如果不配置 docker daemon.json 文件,那么默认 docker 容器的 IP 地址是
172.17.0.1 ,需要修改 daemon.json 并且重启 docker 服务,让 docker0 这个网卡的网段和 flannel0
网卡的网段一致
cat /run/flannld/subnet.env
vim /etc/docker/daemon.json
{
...,
"bip" : "172.20.x.x" ,
"mtu" : 1472
}
# 9 、重启 docker 服务,查看 docker0 的网段
systemctl restart docker
ifconfig docker0
node22
# 1 、安装 docker
# 2 、安装 flanneld
yum -y install flanneld
# 3 、配置 /etc/sysconfig/flanneld, node11 中的 etcd 数据库中读取网络信息
# 4 、启动 flanneld
# 5 ip a s flannel0 分配了一个新的网段
# 6 、修改 node22 下面的 daemon 添加两个 key bip mtu
# 7 、重启 docker 服务
# 8 docker0 ip 地址和 flannel0 ip 地址保持一致
二、使用 docker-compose 编排容器
Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。
1 Docker-compose 定义
1 docker compose docker 官⽅的开源项⽬,负责实现对 docker 容器集群的快速编排 ( 容器,
依赖,⽹络,挂载。。 )
2 compose docker 公司推出的⼀个⼯具软件,可以管理多个 docker 容器组成的应⽤
3 ) 需要定义⼀个 YAML 格式的配置⽂件 docker-compose.yml ,写 好多个容器之间的调⽤关系
4 )使⽤ compose 的步骤
使⽤ Dockerfile 定义各个微服务应⽤并构建出对应的镜像⽂件 Dockerfile 的使⽤,以便可以在任何
地⽅复制。
使⽤ docker-compose.yml 定义⼀个完整的业务单元,安排好整体应⽤中的各个容器服务。
最后,执⾏ docker-compose up 命令来启动并运⾏整个应⽤程序,完成⼀键部署。
2 Docker-compose 产⽣背景
1 )使⽤ Dockerfile 定义镜像⽂件,再⼿动构建、运⾏容器等操作,⽽微服务架构⼀般包含若⼲个微服务,且每个微服务⼀般都会部署多个实例,所以,若每个微服务都需要⼿动启停,那么维护量会⾮常庞⼤,并且⼯作效率也会很低。
2 )⽽ compose 是⽤于定义和运⾏多容器 docker 应⽤程序的⼯具。通过 compose ,可以使⽤ YML⽂件来配置应⽤程序需要的所有服务。
3 )仅需使⽤⼀个命令,就可以从 YML ⽂件配置中创建并启动所有 服务。
4 Compose 可以基于 Compose ⽂件帮我们快速的部署分布式应 ⽤,⽆需⼿动⼀个个创建和运⾏容器。
5 Compose ⽂件是⼀个⽂本⽂件,通过指令定义集群中的每个容 器如何运⾏。
3 Docker-compose 核⼼概念
Docker-compose 将管理的容器分为三层:⼯程( project )、 服务( service )、容器 (container
1 、⼯程:运⾏ compose 的⽬录下所有的⽂件,包括 docker-compose.yml extends ⽂件、环境
变量⽂件等组成⼀个⼯程, 若⽆特殊指定⼯程,⼯程名即为当前⽬录名。⼯程的默认配置⽂件为 docker-compose.yml,可通过环境变量 COMPOSE_FILE -f 参数⾃定义配置⽂件,其定义了多个有依赖关系的服务及每个服务运⾏的容器。
2 、 服务:⼀个⼯程中包含多个服务,每个服务中定义了容器运⾏的 镜像、参数、依赖等。⼀个服务中可包括多个容器实例。
3 、容器:被 docker-compose 管理或部署的容器集群,调⽤ docker 服务提供的 API 来对容器进⾏管理,只要操作的平台⽀持 docker API ,即可在其上进⾏ compose 的容器编排。
4 YAML ⽂件的格式和语法
1 YAML ⽂件格式
yaml 是⼀种标记语⾔很直观的数据序列化格式,可读性很⾼。 类似于 xml 描述性语⾔,语法⽐ xml简单的很多。
yaml 数据结构通过缩进进⾏表示,连续的项⽬通过减号来表示,键值对⽤冒号分隔,数组⽤中括号括起来,hash ⽤花括号括起来。
yaml ⽂件的基本格式由⼀系列键值对构成。每个键值对都⽤冒号 “: ” 分隔
key value
yaml 中,键和值之间只需要⼀个空格,这是为了保证 yaml ⽂件的可读性和⼀致性
对于字符串值,可以使⽤单引号或者双引号将其括起来,这样可以避免出现特殊字符或空格等问题
name 'Meng Mr'
age: "34"
如果值包含特殊字符(如冒号或短横线),则应该使⽤引号将其括起来
description: "This is a YAML file: good for configuation files."
2 YAML 注意事项
不⽀持制表符 tab 键缩进,需要使⽤空格缩进。
通常开头缩进 2 个空格。
字符后缩进 1 个空格,如:冒号,逗号,横杠。
# 表示注释。
如果包含特殊字符⽤单引号引起来。
布尔值( true false yes no on off )必须使⽤ “” 引号括起来,这样分析器会将它们解释为字符串。
3 )列表和数组
yaml 中,可以使⽤ “-” 符号表示⼀个列表和数组
fruits: # fruits 个键,它对应 个列表,包含三个元素: apple banana orange
- apple # fruits 项,下 项只需要缩进
空格,与其他项 即可
- banana
- orange
4 )嵌套数据结构
yaml ⽀持嵌套数据结构,可以⽤缩进来表示不同层级之间的关系, 可使⽤ # 号表示注释信息。
person:
name: 'Meng Mr' # 两个空格, name age person 节点
age: "34"
address: # address person 节点
street: '123 Main St' # address 节点包含了 street city state zip 四个
city: 'Anytown'
state: 'CA'
zip: '12345'
5 Docker-compose 安装
使用 pip 工具 ------- 安装 docker-compose
pip python 的包管理工具,和 yum redhat 的关系是一样的
# 由于要使用 python 环境运行 docker-compose ,所以需要验证 python
[root@docker1 ~] # python --version
Python 2 .7.5
[root@docker1 ~] # pip
-bash : pip: 未找到命令
# 安装 pip python 的包管理工具(需要使用 pip 下载安装 docker-compose
[root@docker1 ~] # yum -y install python2-pip
# 查看所有已经安装过的 python 第三方库,发现 pip 版本太低
[root@docker1 ~] # pip list
pip (8.1.2)
# 升级 pip 版本
[root@docker1 ~] # pip install --upgrade pip
安装失败
[root@docker1 ~] # pip install --upgrade pip==20.3 -i
https://mirrors.aliyun.com/pypi/simple
Successfully installed pip-20.3
[root@docker1 ~] # pip list
pip 20 .3
# 使用 pip 安装 docker-compose
[root@docker1 ~] # pip install docker-compose --ignore-installed requests -i
https://mirrors.aliyun.com/pypi/simple
[root@docker1 ~] # pip list
docker-compose 1 .26.2
# 配置 docker
[root@docker1 ~] # sh docker.sh
[root@docker1 ~] # docker --version
Docker version 26 .1.4, build 5650f9b
6 docker-compose 命令解析
1 、⽂件内常⽤指令字段
1 version
指定了 Docker compose 编排⽂件的版本 Docker Compose ⽬前有三个版本,分别为 Version1
Version2 Version3
Version1 是较早的版本,它将来会被弃⽤。
Version2 是⽬前的稳定版本,⽀持更多的指令。
Version3 在功能上与 Version2 类似,但进⾏了⼀些改进和 扩展,例如增加了对 Docker BuildKit 的⽀持,可以加速构建过程。
version '3'
2 service
指定了在 docker compose 编排中要运⾏的服务,每个服务都有⼀ 个名称,并指定要使⽤的镜像和容器的配置选项。
services
mysql # 服务名
# 再往下可以对该服务进 定义, 如指定映射端 ,指定使 的镜像等,但要注意缩进格式。
3 image
指定要使用的 docker 镜像
services:
mysql: # 服务名
image: mysql:5.5 # 指定 mysql 镜像,如果主机内不存在该镜像,会从登录的 docker 镜像仓库内
拉取, 般都是从 dockerhub 上拉取
4 build
允许在 docker compose 编排中指定 dockerfile 的位置。
services:
mysql: # 服务名
build: /docker/mysql # 户微服务 件夹, ⾥⾯ 存放的是该服务代码 jar 包和
Dockerfile
5 environment
指定了要设置的环境变量。
services:
mysql: # 服务名
environment: # MySQL 环境变量的例
MYSQL_ROOT_PASSWORD: 000000 # 设置 MySQL root 户的密码
MYSQL_DATABASE: database # 指定要创建的数据库名称
MYSQL_USER: user # 指定要创建的 MySQL 户名
MYSQL_PASSWORD: 123 # 指定要创建的 MySQL 户的密码
6 volumes
挂载宿主机路径或命名卷
1 、指定路径挂载
services:
mysql: # 服务名
volumes:
- ./mysql/data:/var/lib/mysq # 直接指定路径挂载
2 、⽣成 volume 卷挂载
[root@doc ~] # docker volume create mysql # 成名为 mysql volume
[root@doc ~] # vim docker-compose.yml
services:
mysql: # 服务名
volumes:
- mysql:/var/lib/mysq # 指定 volume 卷挂载
3 、共享⽬录挂载
[root@doc ~] # vim docker-compose.yml
version: '2' # 使 共享 录挂载只有 ‘2’ 版本
service :
mysql: # 服务名
volumes:
- /var/lib/mysql # 将这个 录作为共享
nginx:
volumes:
- /usr/local/nginx/html
php:
volumes_from: # 共享 录来
- mysql # 挂载的共享 录,挂载后会在容器内 成与被挂载的 录同名的路径
- nginx # 共享挂载可以是 个列表
7 port
指定了要宿主机映射到容器的端⼝,端⼝不能低于 60 (宿主机端 ⼝:容器端⼝),如果选择的端⼝号低于 60 ,可能会与系统保留的知名端⼝冲突。
services:
mysql: # 服务名
ports:
- 3306 :3306 # 宿主机端 :容器端
8 expose
⽤于在 docker 容器内部暴露端⼝的选项。
services:
mysql: # 服务名
expose:
- 3306
9 networks
加⼊⽹络,引⽤顶级 networks 条⽬ .
networks: # services 同级
dev: # 定义或已存在的 络设备名
driver: bridge # 设备类型:
external: true # 外部存在:是
10 hostname
设定容器主机名
services:
mysql: # 服务名
hostname: mysql
11 command
指定容器启动时要运⾏的命令,覆盖构建时的默认命令
services:
mysql: # 服务名
command: --character-set ·server = utf8
2 docker compose 命令选项
1 build :重新构建服务
2 ps :列出容器
3 up :启动所有 docker-compose 服务
4 up -d :启动所有 docker-compose 服务启动并后台运⾏
5 exec :进⼊容器实例内部
6 scale :指定⼀个服务器启动数量
7 top :显示容器进程
8 logs :查看容器输出⽇志
9 down :停⽌并删除容器、⽹络、卷、镜像
10 stop :停⽌服务
11 start :启动服务
12 restart :重启服务
13 config :检查配置
14 config -q :检查配置,有问题才有输出
15 --version :查看版本
5 docker-compose 实例
# 准备 docker 环境
[root@docker03 ~] # vim /etc/docker/daemon.json
"insecure-registries" : [
"http://10.0.0.52"
],
[root@docker03 test] # vim /usr/lib/systemd/system/docker.service
ExecStart = /usr/bin/dockerd
[root@docker03 test] # systemctl daemon-reload
[root@docker03 test] # systemctl start docker
[root@docker03 ~] # mkdir test
[root@docker03 ~] # cd test
# 创建 docker-compose 实例
[root@docker03 test] # mkdir html
[root@docker03 test] # echo " 我是被编排的 nginx" > ./html/index.html
[root@docker03 test] # ls
docker-compose.yml html
[root@docker03 test] # vim docker-compose.yml
version: "3" # 件版本
services:
nginx: # 服务名
container_name: c1 # 容器名
image: "nginx:latest"
ports:
- "80:80" # 映射
volumes:
- /root/test/html/:/usr/share/nginx/html/ # 挂载
# 启动 compose 集群
# 要在 docker-compose.yml 件所在的 录下才能通过 docker compose 命令启动容器。
[root@docker03 test] # docker compose up -d # 启动 程后会根据指定的容器名称,
对应的容器
WARN[0000] /root/test/docker-compose.yml: `version` is obsolete
[ + ] Running 8 /8
nginx Pulled
30 .4s
e4fff0779e6d Pull complete
9 .5s
2a0cb278fd9f Pull complete
19 .8s
7045d6c32ae2 Pull complete
19 .8s
03de31afb035 Pull complete
19 .8s
0f17be8dcff2 Pull complete
19 .9s
14b7e5e8f394 Pull complete
19 .9s
23fa5a7b99a6 Pull complete
19 .9s
[ + ] Running 2 /2
Network test_default Created
0 .3s
Container c1 Started
0 .8s
# 访问测试
[root@docker03 test] # docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 5ef79149e0ec 2 weeks ago 188MB
[root@docker03 test] # docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
46d8b91c4a5e nginx:latest "/docker-entrypoint.…" 6 minutes ago Up 6
minutes 0 .0.0.0:80->80/tcp, :::80->80/tcp c1
[root@docker03 test] # curl 10.0.0.52
我是被编排的 nginx
# 浏览器访问
三、配置 harbor
Harbor 是一个用于存储和管理 Docker 镜像等容器镜像的企业级 Registry 服务器。
1 、上传 harbor 文件,解压
[root@docker1 ~] # tar zxf harbor-offline-installer-v2.11.1.tgz
[root@docker1 ~] # ls
anaconda-ks.cfg docker.sh harbor harbor-offline-installer-v2.11.1.tgz v
[root@docker1 ~] # cd harbor
[root@docker1 harbor] # ls
common.sh harbor.v2.11.1.tar.gz harbor.yml.tmpl install.sh LICENSE
prepare
2 、修改配置文件
# 配置文件
# harbor 的配置文件是 harbor.yml 但是解压后的目录中只有 harbor.yml.tmpl
# 需要复制一份修改名字即可
[root@docker1 harbor] # cp harbor.yml.tmpl harbor.yml
[root@docker1 harbor] # ls
common.sh harbor.v2.11.1.tar.gz harbor.yml harbor.yml.tmpl install.sh
LICENSE prepare
[root@docker1 harbor] # vim harbor.yml
# 改为本机 ip 地址
5 hostname: 10 .0.0.51
6
7 # http related config
8 http:
9 # port for http, default is 80. If https enabled, this port will
redirect to https port
10 port: 80
11
# 将有关 https 的部分全部注释掉
12 # https related config
13 # https:
14 # https port for harbor, default is 443
15 # port: 443
16 # The path of cert and key files for nginx
17 # certificate: /your/certificate/path
18 # private_key: /your/private/key/path
19 # enable strong ssl ciphers (default: false)
20 # strong_ssl_ciphers: false
43 # The initial password of Harbor admin
# 查看默认的用户名和密码
46 harbor_admin_password: Harbor12345
3 、部署容器环境
# 修改 daemon.json 文件
[root@docker1 harbor] # vim /etc/docker/daemon.json
{
"registry-mirrors" : [
"https://do.nark.eu.org" ,
"https://dc.j8.work" ,
"https://docker.m.daocloud.io" ,
"https://dockerproxy.com" ,
"https://docker.mirrors.ustc.edu.cn" ,
"https://docker.nju.edu.cn"
],
"host" : [
"tcp://0.0.0.0:2375" ,
"unix:///var/run/docker.sock"
],
"insecure-registries" : [
# 本机 ip 地址(仓库),使用 80 端口
"http://10.0.0.51"
],
"bip" : "172.20.13.1/24" ,
"mtu" : 1472
}
# 开启容器
[root@docker1 harbor] # systemctl start docker
# 修改 docker 文件
[root@docker1 harbor] # vim /usr/lib/systemd/system/docker.service
ExecStart = /usr/bin/dockerd
# 重新加载 daemon 文件
[root@docker1 harbor] # systemctl daemon-reload
# 重启 docker
[root@docker1 harbor] # systemctl restart docker
4 、使用自带脚本检查并初始化配置 harbor
# 检查环境是否合适
[root@docker1 harbor] # ./prepare
prepare base dir is set to /root/harbor
Unable to find image 'goharbor/prepare:v2.11.1' locally
Successfully called func: create_root_cert
# 查看端口是否被占用并关闭防火墙
[root@docker1 harbor] # netstat -lntup | grep 5000
[root@docker1 harbor] # netstat -lntup | grep 80
[root@docker1 harbor] # systemctl stop firewalld
# 开始初始化配置 harbor 环境
[root@docker1 harbor] # ./install.sh
[ + ] Running 10 /10
? Network harbor_harbor Created
0 .1s
? Container harbor-log Started
0 .7s
? Container registry Started
3 .3s
? Container harbor-portal Started
3 .3s
? Container redis Started
3 .3s
? Container harbor-db Started
3 .3s
? Container registryctl Started
3 .3s
? Container harbor-core Started
13 .9s
? Container nginx Started
22 .9s
? Container harbor-jobservice Started
22 .8s
----Harbor has been installed and started successfully.----
5 、查看容器运行情况
# 查看被创建的容器,都是正在开启的状态,等一会让他全部开启
[root@docker1 harbor] # docker ps -a
CONTAINER ID IMAGE COMMAND
CREATED STATUS PORTS
NAMES
14b077f4d919 goharbor/nginx-photon:v2.11.1 "nginx -g 'daemon of…"
40 seconds ago Up 14 seconds (health: starting) 0 .0.0.0:80-
>8080/tcp, :::80->8080/tcp nginx
c041eb8edf2b goharbor/harbor-jobservice:v2.11.1 "/harbor/entrypoint.…"
40 seconds ago Restarting (2) Less than a second ago
harbor-jobservice
58f2e1174eb9 goharbor/harbor-core:v2.11.1 "/harbor/entrypoint.…"
40 seconds ago Up 24 seconds (health: starting)
harbor-core
7e6f79dcae20 goharbor/harbor-db:v2.11.1 "/docker-entrypoint.…"
40 seconds ago Up 33 seconds (health: starting)
harbor-db
a7f3235a2bdf goharbor/redis-photon:v2.11.1 "redis-server /etc/r…"
40 seconds ago Up 33 seconds (health: starting)
redis
623e25aff7e5 goharbor/registry-photon:v2.11.1 "/home/harbor/entryp…"
40 seconds ago Up 33 seconds (health: starting)
registry
2577d87bdac0 goharbor/harbor-portal:v2.11.1 "nginx -g 'daemon of…"
40 seconds ago Up 33 seconds (health: starting)
harbor-portal
2bf21b95c413 goharbor/harbor-registryctl:v2.11.1 "/home/harbor/start.…"
40 seconds ago Up 33 seconds (health: starting)
registryctl
201780bb9f41 goharbor/harbor-log:v2.11.1 "/bin/sh -c /usr/loc…"
41 seconds ago Up 35 seconds (healthy) 127 .0.0.1:1514-
>10514/tcp harbor-log
6 、测试
到浏览器中访问本机 ip 地址
输入(用户名: admin 密码: Harbor12345
点击 项目 -------- library
7 、推送镜像到 harbor 的私有仓库中
查看推送命令
# 在命令行中登录页面
[root@docker1 harbor] # docker login http://10.0.0.51
Username: admin
Password: Harbor12345
WARNING! Your password will be stored unencrypted in
/root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/ #credentials-store
Login Succeeded
# 为镜像打标签
[root@docker1 harbor] # docker tag centos:latest 10.0.0.51/library/centos:v0
# 将本地镜像推送到私有仓库中
[root@docker1 harbor] # docker push 10.0.0.51/library/centos:v0
The push refers to repository [10.0.0.51/library/centos]
74ddd0ec08fa: Pushed
v0: digest:
sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c83863037fa3aab063a7fdb9dc size:
529
8 harbor 配置中使用到的 docker-compose 命令
[root@docker1 ~] # ls
anaconda-ks.cfg docker.sh harbor harbor-offline-installer-v2.11.1.tgz v
[root@docker1 ~] # cd harbor
[root@docker1 harbor] # ls
common docker-compose.yml harbor.yml install.sh prepare
common.sh harbor.v2.11.1.tar.gz harbor.yml.tmpl LICENSE
# 一次性关闭所有容器
[root@docker1 harbor] # docker-compose stop
# 开启所有容器
[root@docker1 harbor] # docker-compose start
# 删掉所有容器
[root@docker1 harbor] # docker-compose down
# 重新检查环境
[root@docker1 harbor] # ./prepare
# 重新初始化
[root@docker1 harbor] # ./install.sh
9 、拉取 harbor 的私有仓库中的镜像
复制拉取镜像的命令
# 在其他 docker 主机上配置 daemon 仓库,启动 docker ,使用复制的下载链接,添加共享的镜像
[root@node11 ~] # vim /etc/docker/daemon.json
"insecure-registries" : [
"http://10.0.0.51"
],
[root@node11 ~] # systemctl daemon-reload
[root@node11 ~] # systemctl restart docker
[root@node11 ~] # docker pull
10.0.0.51/library/centos@sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c838630
37fa3aab063a7fdb9dc
10 .0.0.51/library/centos@sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c838630
37fa3aab063a7fdb9dc: Pulling from library/centos
Digest:
sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c83863037fa3aab063a7fdb9dc
Status: Downloaded newer image for
10 .0.0.51/library/centos@sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c838630
37fa3aab063a7fdb9dc
10 .0.0.51/library/centos@sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c838630
37fa3aab063a7fdb9dc
[root@node11 ~] # docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 5d0da3dc9764 2 years ago 231MB
10 .0.0.51/library/centos <none> 5d0da3dc9764 2 years ago 231MB
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值