docker&k8s初探笔记

docker&k8s初探

基础资料

Ubuntu18.04快速安装docker和Harbor仓库

Ubuntu18.04安装docker

# 更新依赖
sudo apt-get update
# 安装 apt 依赖包,用于通过HTTPS来获取仓库
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
# 添加 Docker 的官方 GPG 密钥
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 设置稳定版仓库
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# 安装dockerce
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
# 测试运行
sudo docker run hello-world

配置阿里云镜像加速器用于更快速的访问Docker hub

# 编辑docker的daemon.json文件,如果没有,则新增
vim /etc/docker/daemon.json

  • 添加镜像地址,提高下载速度
{
  "registry-mirrors":["https://da0il1c2.mirror.aliyuncs.com"]
}

  • 修改docker配置能够被外网push和pull
vim /usr/lib/systemd/system/docker.service
# 修改ExecStart内容,后面添加-H后内容
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
# 加载配置内容
sudo systemctl daemon-reload
# 重启docker
sudo systemctl restart docker

Ubuntu18安装Harbor仓库–docker镜像仓库

  1. harbor官方地址
  2. 安装参考链接
  3. 安装参考链接2
  4. harbor的安装需要docker-compose的使用docker-compose的网站
#1. 下载docker-compose,安装docker-compose
https://github.com/docker/compose/releases
# 配置到/usr/local/bin并赋予权限
chmod +x /usr/local/bin/docker-compose
# 进行验证
docker-compose --version
#2. 安装docker
# docker-compose安装,先安装docker,然后去官网下载harbor的jar包。注意版本
# 解压
tar zxvf harbor-offline-installer-v1.9.4.tgz
# 编写harbor.yml配置 
cd harbor/
vim harbor.yml
# 安装harbor
./prepare
./install.sh
# 访问使用http://xx.xx.xxx

  1. 如果修改harbor配置
# 停止docker-compose
sudo docker-compose down -v
# 修改配置
vi harbor.yml
# 应用配置
./prepare
# 启动服务
sudo docker-compose up -d

  1. 启动、关闭docker-compose
 # 停止docker-compose
 docker-compose stop
 # 启动docker-compose
 docker-compose start
  • 配置harbor.yml

harbor配置

docker镜像推送

三步走:1、登录harbor。2、给镜像打标签。3、推送到远程docker仓库

  1. 生成镜像。
# 生成镜像命令
mvn clean package -Dmaven.test.skip=true dockerfile:build
  1. 登录harbor
sudo docker login ip --username=xxx
  1. 给镜像打tag
sudo docker tag [ImageId] :[镜像版本号]
  1. 推送到远程私有仓库
 sudo docker push xxx:[镜像版本号]

远程操控docker配置

  1. 参考链接docker 2375 入侵服务器
  2. docker remote Api中说明了:2375是docker的远程操控端口。通过这个端口,我们可以直接对远程的docker daemon进行操作。目前暂时不考虑安全配置
sudo vi /lib/systemd/system/docker.service
#修改参数
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
# 应用配置,重启服务
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo docker-compose stop
sudo docker-compose start
# 开启防火墙,开启安全组

harbor配置http访问

  • 原因:docker访问镜像时需要使用https访问,这里需要进行设置。insecure-registries中的ip是仓库地址。仓库docker需要配置,本地也要配置。
# 编辑daemon.json
vim /etc/docker/daemon.json
# 添加http配置
#重启
sudo systemctl daemon-reload && systemctl restart docker
{ 
 "registry-mirrors": ["xxx"], 
 "insecure-registries":["192.168.186.129"]
}

docker-compose使用

docker-compose解决的问题

  1. 参考文档docker-compose
  2. docker-compose是:docker编排工具

好处:
(1)一个项目可能有多个容器,容器之间启动有时候存在一定的依赖关系,比如A启动的要求是B先启动。
(2)如果一个项目要启动很多容器,一个一个启动太麻烦,可以使用docker-compose对所有容器统一启动。
(3)如果想增加一个容器,可以使用docker-compose up -d 更新启动。
(4)docker-compose可以配置容器的容器启动虚拟的ip,有利于集群部署。

docker-compose启动三部曲:
(1)Dockerfile定义应用的运行环境。
(2)docker-compose.yml 定义组成应用的各个服务。
(3)docker-compose up 启动整个应用。
(4)定义内网地址,实现服务之间通信

安装docker-compose

  1. 直接官网下载docker-composedocker-compose下载
  2. 下载完毕后,将文件放入/usr/local/bin目录下,并改名字为docker-compose
  3. 授予docker-compose可执行权限
sudo chmod +x /usr/local/bin/docker-compose
  1. 验证是否安装成功
docker-compose --version

案例:部署业务中台核心定位API服务

  • 准备工作:配置maven的setting.xml,添加插件

配置maven

  • 添加镜像标签,以及推送地址等信息

配置镜像版本

  1. 所有服务生成docker
# 分别进入服务根目录,根据dockerfile生成镜像
mvn clean package -Dmaven.test.skip=true dockerfile:build
# 登录仓库地址,推送镜像
docker login xxx
docker push Repository:tag
  1. 195服务器拉取镜像
docker pull 47.xx.xx.xx/zkf1995/aiwen-districtapi:v1
  1. 写docker-compose.yaml文件
version: '3'
# 服务配置
services:
  blade-log:
    image: "47.xxx.176.159/zkf/blade-log:v1"
    environment:
      - TZ=Asia/Shanghai
    privileged: true
    ports:
      - 8103:8103
    restart: always
    networks:
      cloud1:
        ipv4_address: 172.17.0.103

# 配置网段
networks:
  cloud1:
    driver: bridge
    ipam:
      config:
      - subnet: 172.17.0.0/16
  1. 通过启动docker-compose,启动所有服务。

docker-compose常用命令

  1. docker-compose常用命令参考链接
  2. 常用命令
# 后台启动
docker-compose up -d
#-f  指定使用的 Compose 模板文件,默认为 docker-compose.yml,可以多次指定,指定多个yml
docker-compose -f docker-compose.yml up -d 
# 验证(docker-compose.yml)文件配置,当配置正确时,不输出任何内容,当文件配置错误,输出错误信息。
docker-compose config  -q
# 查看启动的服务
docker-compose ps 
# 停止服务,停止已经处于运行状态的服务,但是不删除它
docker-compose stop
# 启动已经存在的服务容器
docker-compose start
# 重启
docker-compose restart
# 停用并移除所有容器以及网络相关
docker-compose down
# 删除所有停止状态的服务容器。推荐先执行docker-compose stop停止容器
docker-compose rm

# 查看日志
docker-compose logs xxx(或者没有)
# 查看实时日志
docker-compose logs -f xxx(或者没有)
# 等等命令很多

docker-compose启动服务可能遇见的问题

  1. 报错:Creating network “v2_dev” with driver "bridge"ERROR: Pool overlaps with other one on this address space
  2. 网段重叠报错解决方案
  3. 解决方案一:
# 查看docker 网卡
docker network ls
# 查看docker 网卡的相关信息,确认是自己创建的ip段,然后删除相应的网卡
docker network inspect [network ID]
# 删除docker网卡
docker network rm [network id]
  1. 方案二:重新写自定义一个网段地址。

docker部署方案

docker部署方案

k8s研究

  1. 安装k8s参考文档:k8s安装参考文档

k8s三驾马车

  1. kubelet:运行在cluster所有节点上,负责启动pod和容器。个人认为不对外的内部管家
  2. kubeadm:Kubeadm 是一个工具,它提供了 kubeadm init 以及 kubeadm join 这两个命令作为快速创建 kubernetes 集群的最佳实践。
  3. kubectl:kubectl是kubenetes命令行工具,通过kubectl可以部署和管理应用,查看各种资源,创建,删除和更新组件等。

科研组安装命令解析

安装 docker
# apt-transport-https一种https通信工具软件,docker模式使用https
sudo apt-get update && sudo apt-get install -y apt-transport-https gnupg2
# 添加阿里云秘钥
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# 添加阿里云安装源
add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# 安装最新版docker
apt update
apt install docker-ce
安装kubelet,kubeadm,kubectl三驾马车
  1. 添加阿里云安装源
cat <<EOF > /etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
  1. 更新安装源,报错解决方案:update报错解决
apt-get update
  1. 安装三驾马车
# socat 是端口转发功能和“包管理器” Helm 的依赖,如果不需要可以不装
sudo apt-get install -y kubectl kubeadm kubelet socat
  1. 查看安装版本
kubectl version
安装k8s
  1. 关闭swap交换空间关闭swap原因
# 临时关闭
swapoff -a
# 永久关闭,关闭原因:提升k8s性能。
vim /etc/fstab
# 然后注释掉/swapfile那一行
  1. 查看该k8s版本下所需的镜像
kubeadm config images list --kubernetes-version v1.19.2

此时本来到这步可以直接运行kubeadm init --kubernetes-version=v1.18.0 --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.0.188,但是由于被墙的原因,需要再走一步

  1. docker拉取所需的镜像
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.19.2
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.19.2
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.19.2
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.19.2
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2 
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.4.13-0 
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.7.0
  1. 对拉取的镜像打标签
docker tag registry.aliyuncs.com/google_containers/kube-apiserver:v1.19.2 k8s.gcr.io/kube-apiserver:v1.19.2
docker tag registry.aliyuncs.com/google_containers/kube-controller-manager:v1.19.2 k8s.gcr.io/kube-controller-manager:v1.19.2
docker tag registry.aliyuncs.com/google_containers/kube-scheduler:v1.19.2 k8s.gcr.io/kube-scheduler:v1.19.2
docker tag registry.aliyuncs.com/google_containers/kube-proxy:v1.19.2 k8s.gcr.io/kube-proxy:v1.19.2

docker tag registry.aliyuncs.com/google_containers/pause:3.2 k8s.gcr.io/pause:3.2
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.4.13-0 k8s.gcr.io/etcd:3.4.13-0
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.7.0 k8s.gcr.io/coredns:1.7.0
  1. 删除旧的镜像
docker rmi registry.aliyuncs.com/google_containers/kube-apiserver:v1.19.2
docker rmi registry.aliyuncs.com/google_containers/kube-controller-manager:v1.19.2
docker rmi registry.aliyuncs.com/google_containers/kube-scheduler:v1.19.2
docker rmi registry.aliyuncs.com/google_containers/kube-proxy:v1.19.2
docker rmi registry.aliyuncs.com/google_containers/pause:3.2
docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.4.13-0
docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.7.0
启动k8s
  1. 启动pod-network-cidr参数的作用
# 启动命令
kubeadm init --kubernetes-version=v1.19.2 --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.28.131
# --apiserver-advertise-address 指定master地址,kubeadm 使用 eth0 的默认网络接口(通常是内网IP)做为 Master 节点的 advertise address ,如果我们想使用不同的网络接口,可以使用 --apiserver-advertise-address=<ip-address> 参数来设置
# --pod-network-cidr=10.10.0.0/16 指定节点网络指定pod网络的IP地址范围,它的值取决于你在下一步选择的哪个网络网络插件,比如我在本文中使用的是Calico网络,需要指定为192.168.0.0/16。
# 停止容器命令
kubeadm reset
# reset操作需要删除该内容,否则下次启动会失败
rm -rf $HOME/.kube
  • 注意点:如果使用kubeadm reset后下次启动后需要有以下操作
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
  • 查看节点信息
kubectl get nodes

安装k8s的控制盘dashboard

  1. 参考链接k8s控制盘安装
  2. dashboard下载地址
  3. 解压后进入/aio/deploy/编辑recommended.yaml。增加内容和注释内容如下
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  type: NodePort   # 增加内容1
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30001  # 增加内容2
  selector:
    k8s-app: kubernetes-dashboard
    
# 注释内容主要是关于https访问的信任证书内容。
#apiVersion: v1
#kind: Secret
#metadata:
#  labels:
#    k8s-app: kubernetes-dashboard
#  name: kubernetes-dashboard-certs
#  namespace: kubernetes-dashboard
#type: Opaque

  1. 启动dashboard
# 运行dashboard
kubectl create -f recommended.yaml
# 查看dashboard运行状态
kubectl get pods -n kubernetes-dashboard
===============================================================================
# 查看dashboard暴露的端口
kubectl get svc -n kubernetes-dashboard
# 查看某个namespace中某个Name的状态
kubectl describe pod -n  NAME --namespace=xxx
# 删除pod下某个Name
kubectl delete pod  NAME1 NAME2 -n kube-system
# 查看Node中所有命名空间的容器
kubectl get pod --all-namespaces
  • 测试图片

测试1

测试2

测试3

  • 这个pod可以用Nacos来理解,一个Pod下可以有多个命名空间,例如nacos中的dev,prod,test命名空间。每个命名空间内又有多个容器。一个pod可以包含多个命名空间,一个命名空间里面又包含多个容器。
  1. 访问dashboard:https://ip+端口 。使用Token登录方式。token获取
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep dashboard-admin | awk '{print $1}')
  1. 修改token过期时长:修改token过期时长

kubectl常见命令

kubectl常见命令

遇见报错情况

报错情况一:CoreDns镜像启动失败
  1. 通过命令查看发现有coredns启动失败,可以通过下面命令查看
kubectl get pod --all-namespaces
  1. 通过命令发现k8s中一个组件coredns启动失败。原因是:CoreDns需要一个网络管理镜像,Flannel,目的:其目的在于帮助每一个使用 Kuberentes 的 CoreOS 主机拥有一个完整的子网。也就是实现集群内仍然能够互联互通。
  2. 解决方案启动失败解决方案解决方案2
  3. 下载kube-flannel.ymlflannel下载网址
  4. 使用kubectl执行
kubectl create -f ./kube-flannel.yml
报错情况二:kubernetes-dashboard启动失败
  1. 启动失败原因是上面安装recommond.yaml时注释掉了k8s自带的证书。所以需要自定义一个证书
  2. 问题解决参考文档:创建自定义证书
  3. 创建自定义证书
mkdir dashboard-certs
cd dashboard-certs/
#创建命名空间
kubectl create namespace kubernetes-dashboard
# 创建key文件
openssl genrsa -out dashboard.key 2048
#证书请求
openssl req -days 36000 -new -out dashboard.csr -key dashboard.key -subj '/CN=dashboard-cert'
#自签证书
openssl x509 -req -in dashboard.csr -signkey dashboard.key -out dashboard.crt
#创建kubernetes-dashboard-certs对象
kubectl create secret generic kubernetes-dashboard-certs --from-file=/usr/local/dashboard-certs/dashboard.key --from-file=/usr/local/dashboard-certs/dashboard.crt -n kubernetes-dashboard

# 获取tokens
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep dashboard-admin | awk '{print $1}')
  • 注意最后一个创建对象,一定要写对路径。我就在此大眼瞪小眼无数次,此外kubeadm reset后 再次执行dashboard后,一定不要忘记执行创建kubernetes-dashboard-cert对象这个命令。超级坑。

总结dashboard安装步骤

  1. 下载dashboard的recommond.yaml。
  2. 修改recommond.yaml的配置,一个是给dashboard添加访问端口,一个是注释掉k8s提供的https安全证书,因为k8s提供的安全正书有问题,很多浏览器无法使用。
  3. 自己创建连接dashboard的证书。 并让该证书生效
  4. 添加kube-flannel.yml的网络管理镜像
  5. 访问dashboard

部署Docker镜像

k8s部署docker镜像的步骤

  1. 编写代码
  2. 编写DockerFile
  3. 生成Docker镜像,并推送到私有仓库
  4. 编写K8sDeployment部署文件
  5. 发布测试

K8s部署微服务项目

  1. 参考链接k8s部署微服务项目
  2. 常用命令
# 获取deployment
kubectl get deployment <name>
# 删除deployment
kubectl delete deployment <name>

k8s集群部署

  1. 参考链接
  2. https://blog.csdn.net/weixin_43224068/article/details/104060320(单机版)
  3. 集群token重新生成
# 生成token
kubeadm token create
# 获取ca证书sha256编码hash值
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

# 集群搭建
kubeadm join node主机ip地址:6443 --token wbekm9.d7m4p57rro7xuwzw \
    --discovery-token-ca-cert-hash sha256:9db128fe4c68b0e65c19bb49226fc717e64e790d23816c5615ad6e21fbe92020

集群步骤

  1. 通过kubeadm init 启动一个服务后。在从节点执行主节点的kubeadm join 操作。 从节点会自动加入到集群中。
  2. 通过kubectl get nodes可以查看,也可以通过仪表盘查看

k8s集群

K8s集群报错问题

  1. kubeadm join报错
[preflight] Running pre-flight checks
        [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
error execution phase preflight: [preflight] Some fatal errors occurred:
        [ERROR DirAvailable--etc-kubernetes-manifests]: /etc/kubernetes/manifests is not empty
        [ERROR FileAvailable--etc-kubernetes-kubelet.conf]: /etc/kubernetes/kubelet.conf already exists
        [ERROR Port-10250]: Port 10250 is in use
        [ERROR FileAvailable--etc-kubernetes-pki-ca.crt]: /etc/kubernetes/pki/ca.crt already exists
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher

  1. 解决方案:报错解决方案
  2. 注意问题:集群的时候,主机名不能相同。
  3. 集群后node节点的role角色为none

报错解决

# 举例
kubectl label nodes aiwen4 node-role.kubernetes.io/node1=

k8s部署项目

  1. 参考链接k8s拉取私有仓库并部署

部署业务中台API项目:

  1. 配置连接私服仓库的秘钥Secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: login
type: kubernetes.io/dockerconfigjson
data: 
  .dockerconfigjson:   ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjI4LjEzMSI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0sCgkJIjE5Mi4xNjguMjguMTMxOjIwMjMiOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9LAoJCSI0Ny4xMDUuMTc2LjE1OSI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy4xMiAobGludXgpIgoJfQp9
  1. 后面的密码是通过base64加密得到的
cat ~/.docker/config.json | base64 -w 0
  1. 创建私服秘钥对象
kubectl create -f secret.yaml
  1. 编写deployment.yaml
  • 举例:aiwen-pay.yaml
apiVersion: apps/v1
kind: Deployment # 资源类型
metadata:
  name: aiwen-pay # 名称
spec:
  replicas: 1 # pod实例数
  selector:
   matchLabels:
      app: aiwen-pay   # 标签
  template: # 模板
    metadata:
      labels:
        app: aiwen-pay  #标签 上下两个标签需要对应,表示template里面创建的这个pod属于这个dep资源里面的
    spec: #详细信息
      containers:  # 容器
      - name: aiwen-pay
        image: 47.xxx.xxx.xxx/zkf1995/aiwen-pay:v1 # image镜像
        imagePullPolicy: IfNotPresent # image拉取策略,如果本地有就不拉取,这里注意啊,这个本地不光是master节点,node节点也都需要有这个镜像
        ports:
        - containerPort: 9121 # 容器端口
          name: site
          protocol: TCP
      imagePullSecrets:
      - name: login
    #    - containerPort: 81
    #      name: grpc
    #      protocol: TCP

    #     env: # 环境变量,也可以通过configmap实现,其实就是配置文件
    #    - name: ASPNETCORE_ENVIRONMENT
    #      value: "Development"
    #    - name: ConnectionString
    #      value: "Server=mssql;Database=product_db;User Id=sa;Password=Pass@word"
  1. 使用k8s的dashboard直接上传执行

运行

  1. 其他暴露对外访问端口以blade-gateway.yaml为例,参考链接
apiVersion: apps/v1
kind: Deployment  # 资源类型
metadata:
  name: blade-gateway # 名称
spec:
  replicas: 1 # pod实例数
  selector:
   matchLabels:
      app: blade-gateway   # 标签
  template: # 模板
    metadata:
      labels:
        app: blade-gateway  #标签 上下两个标签需要对应,表示template里面创建的这个pod属于这个dep资源里面的
    spec: #详细信息
      containers:  # 容器
      - name: blade-gateway
        image: 47.xxx.xxx.xxx/zkf1995/blade-gateway:v1 # image镜像
        imagePullPolicy: IfNotPresent # image拉取策略,如果本地有就不拉取,这里注意啊,这个本地不光是master节点,node节点也都需要有这个镜像
        ports:
        - containerPort: 1180 # 容器端口
          name: site
          protocol: TCP
          nodePort: 32600
        type: NodePort
      imagePullSecrets:
      - name: login
    #    - containerPort: 81
    #      name: grpc
    #      protocol: TCP

    #     env: # 环境变量,也可以通过configmap实现,其实就是配置文件
    #    - name: ASPNETCORE_ENVIRONMENT
    #      value: "Development"
    #    - name: ConnectionString
    #      value: "Server=mssql;Database=product_db;User Id=sa;Password=Pass@word"

课外话题

  1. VMware虚拟机克隆后如何修改主机名

克隆虚拟机ubuntu18.04修改主机名

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值