安装k8s集群

前置要求

  1. 三台物理机或虚拟机,操作系统CentOS-7-x86_64
  2. 2GB或更多RAM,2个CPU或更多,硬盘30GB或更多
  3. 集群中的所有机器可以互通
  4. 能够访问外网,需要拉取镜像
  5. 静止swap分区

基础环境搭建

  1. 安装 VirtualBox-6.0.10-132072-Win.exe并设置网络
    在这里插入图片描述
    在这里插入图片描述
    VirtualBox全局设定虚拟机安装位置(提醒:选择一块比较大的磁盘空间)
    在这里插入图片描述
    在这里插入图片描述
  2. 安装vagrant_2.2.5_x86_64.msi 并使用Vagrantfile脚本快速创建三台虚拟机
    # Vagrantfile文件内容,建议该文件放在非中文无空格的目录下
    Vagrant.configure("2") do |config|
       (1..3).each do |i|
            config.vm.define "k8s-node#{i}" do |node|
                # 设置虚拟机的Box
                # node.vm.box = "centos/7"
                config.vm.box = "my_centos7"
                config.vm.box_url = "http://mirrors.ustc.edu.cn/centos-cloud/centos/7/vagrant/x86_64/images/CentOS-7-x86_64-Vagrant-2001_01.VirtualBox.box"
    
    
                # 设置虚拟机的主机名
                node.vm.hostname="k8s-node#{i}"
    
                # 设置虚拟机的IP
                node.vm.network "private_network", ip: "192.168.56.#{99+i}", netmask: "255.255.255.0"
    
                # 设置主机与虚拟机的共享目录
                # node.vm.synced_folder "~/Documents/vagrant/share", "/home/vagrant/share"
    
                # VirtaulBox相关配置
                node.vm.provider "virtualbox" do |v|
                    # 设置虚拟机的名称
                    v.name = "k8s-node#{i}"
                    # 设置虚拟机的内存大小
                    v.memory = 4096
                    # 设置虚拟机的CPU个数
                    v.cpus = 4
                end
            end
       end
    end
    
    在Vagrantfile文件所在位置,开启cmd窗口
    在这里插入图片描述
    执行命令并等待虚拟机创建完成
    vagrant up
    
    虚拟机创建完成后的结果:
    在这里插入图片描述

虚拟机环境设置

  1. vagrant ssh登录虚拟机,开启root密码访问权限,虚拟机密码是vagrant。确保三台虚拟机都执行如下的操作。
    在这里插入图片描述
    PasswordAuthentication yes
    修改完成,用xshell等连接工具,测试连接。

  2. 设置虚拟机的网络环境【默认创建好的虚拟机,连接方式是:网络地址转换(NAT),默认是虚拟机的22端口,与宿主机建立了端口映射,但是三个虚拟机的eth0网卡的ip地址是一样的】

    1. 全局网络设定
      在这里插入图片描述

    2. 创建NAT网络
      在这里插入图片描述

    3. 点击虚拟机,修改网络设置,重新生成mac地址,并重启虚拟机。查看虚拟机eth0,确保ip不同。三台虚拟都做同样操作。
      在这里插入图片描述
      在这里插入图片描述

    4. 登录三台虚拟机,查看网卡和ip

      ip route show # 查看使用的默认网卡
      ip addr # 查看网卡使用的ip
      
    5. 测试三台虚拟机网络互通情况,以及能否访问公网

      #三台虚拟机互ping
      ping www.baidu.com # ping百度
      
  3. linux环境设置(三台虚拟机都如此设置)

    1. 关闭防火墙
      systemctl stop firewalld
      systemctl disable firewalld
      
    2. 关闭安全策略
      sed -i 's/enforcing/disabled/' /etc/selinux/config
      setenforce 0
      
    3. 关闭swap
      swapoff -a # 临时关闭
      sed -ri 's/.*swap.*/#$/' /etc/fstab # 永久关闭
      
    4. 将桥接的IPv4流量传递到iptables的链
      cat > /etc/sysctl.d/k8s.conf << EOF
      net.bridge.bridge-nf-call-ip6tables = 1
      net.bridge.bridge-nf-call-iptables = 1
      EOF
      sysctl --system
      
    5. 修改hosts文件,添加主机名与ip对应关系,根据实际情况修改
      10.0.2.6 k8s-node1
      10.0.2.4 k8s-node2
      10.0.2.15 k8s-node3
      
    6. 环境安装完成后,使用virtualbox 可以为每个节点,生成一个快照,预防环境丢失。(非必须)

安装k8s环境【所有节点都安装】

  1. 安装安装docker环境
    1. 卸载系统之前的docker环境

      sudo yum remove docker \
      				docker-client \
      				docker-client-latest \
      				docker-common \
      				docker-latest \
      				docker-latest-logrotate \
      				docker-logrotate \
      				docker-engine
      
    2. 安装docker-ce

      # 安装必须的依赖
      sudo yum install -y yum-utils \
      device-mapper-persistent-data \
      lvm2
      
      # 设置docker repo的yum位置
      sudo yum-config-manager \
      	--add-repo \
      	https://download.docker.com/linux/centos/docker-ce.repo
      
      # 安装docker,以及docker-cli
      sudo yum install -y docker-ce docker-ce-cli containerd.io
      
    3. 配置docker加速

      # 登录阿里云,找到自己的docker镜像加速地址
      sudo mkdir -p /etc/docker
      sudo tee /etc/docker/daemon.json <<-'EOF'
      {
      "registry-mirrors": ["https://xxxxxxx.mirror.aliyuncs.com"]
      }
      EOF
      sudo systemctl daemon-reload
      sudo systemctl restart docker
      
    4. 启动 docker 并设置 docker 开机自启

      systemctl enable docker
      
  2. 添加阿里云源,方便镜像下载
    cat > /etc/yum.repos.d/kubernetes.repo << EOF
    [kubernetes]
    name=Kubernetes
    baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
    enabled=1
    gpgcheck=0
    repo_gpgcheck=0
    gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
    https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
    EOF
    
  3. 安装kubeadm,kubelet,kubectl
    yum list|grep kube
    # 指定安装的版本
    yum install -y kubelet-1.17.3 kubeadm-1.17.3 kubectl-1.17.3
    # 确保开机启动kubelet
    systemctl enable kubelet
    # 启动kubelet
    systemctl start kubelet
    # 查看kubelet的启动状态(这一步查看,kubelet启动是失败的,先不管,继续后面的
    systemctl status kubelet
    
  4. 部署k8s-master(选定一个节点,作为master节点,执行如下脚本。我这边选择了10.0.2.6作为master节点)
    1. 执行mster_images.sh脚本,下载镜像【因为在节点初始化时候,需要下载镜像。需要镜像比较多,一旦下载失败,还需重来。所以,先把镜像下来下来】

      #!/bin/bash
      
      images=(
        kube-apiserver:v1.17.3
        kube-proxy:v1.17.3
        kube-controller-manager:v1.17.3
        kube-scheduler:v1.17.3
        coredns:1.6.5
        etcd:3.4.3-0
        pause:3.1
      )
      
      for imageName in ${images[@]} ; do
          docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
      done
      
    2. 初始化master节点

      # master节点初始化,注意ip地址,修改为当前环境的ip地址
      kubeadm init \
      --apiserver-advertise-address=10.0.2.6 \
      --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
      --kubernetes-version v1.17.3 \
      --service-cidr=10.96.0.0/16 \
      --pod-network-cidr=10.244.0.0/16
      

      初始化完成后,根据生成的日志操作,部分日志如下:

      Your Kubernetes control-plane has initialized successfully!
      
      To start using your cluster, you need to run the following as a regular user:
      
        mkdir -p $HOME/.kube
        sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
        sudo chown $(id -u):$(id -g) $HOME/.kube/config
      
      You should now deploy a pod network to the cluster.
      Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
        https://kubernetes.io/docs/concepts/cluster-administration/addons/
      
      Then you can join any number of worker nodes by running the following on each as root:
      
      kubeadm join 10.0.2.6:6443 --token qzmmt5.zyysl5sizb4jh7hc \
          --discovery-token-ca-cert-hash sha256:145e4c113172904f9f34a05fae013469751cc6ad40adfb299ac0f755c7f750f8 
      

      该脚本,可以在另外两个节点执行,使其加入master集群。暂时先不加入集群,等后面网络配置后后,再来执行加入集群的命令。生成的token默认两小时过期:

      kubeadm join 10.0.2.6:6443 --token qzmmt5.zyysl5sizb4jh7hc \
      --discovery-token-ca-cert-hash sha256:145e4c113172904f9f34a05fae013469751cc6ad40adfb299ac0f755c7f750f8 
      

      如果token过期,可以手动再次生成,替换上步骤脚本中的token,让节点加入k8s集群

      kubeadmin token create --print-join-command
      kubeadmin token create --ttl 0 --print-join-command  #生成无过期时间的token
      
  5. 安装Pod网络插件(CNI)并将另外两个节点加入集群中
    1. 执行命令,安装Pod网络插件

      kubectl apply -f kube-flannel.yml
      

      kube-flannel.yml文件内容:

      ---
      apiVersion: policy/v1beta1
      kind: PodSecurityPolicy
      metadata:
        name: psp.flannel.unprivileged
        annotations:
          seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default
          seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default
          apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
          apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
      spec:
        privileged: false
        volumes:
          - configMap
          - secret
          - emptyDir
          - hostPath
        allowedHostPaths:
          - pathPrefix: "/etc/cni/net.d"
          - pathPrefix: "/etc/kube-flannel"
          - pathPrefix: "/run/flannel"
        readOnlyRootFilesystem: false
        # Users and groups
        runAsUser:
          rule: RunAsAny
        supplementalGroups:
          rule: RunAsAny
        fsGroup:
          rule: RunAsAny
        # Privilege Escalation
        allowPrivilegeEscalation: false
        defaultAllowPrivilegeEscalation: false
        # Capabilities
        allowedCapabilities: ['NET_ADMIN']
        defaultAddCapabilities: []
        requiredDropCapabilities: []
        # Host namespaces
        hostPID: false
        hostIPC: false
        hostNetwork: true
        hostPorts:
        - min: 0
          max: 65535
        # SELinux
        seLinux:
          # SELinux is unused in CaaSP
          rule: 'RunAsAny'
      ---
      kind: ClusterRole
      apiVersion: rbac.authorization.k8s.io/v1beta1
      metadata:
        name: flannel
      rules:
        - apiGroups: ['extensions']
          resources: ['podsecuritypolicies']
          verbs: ['use']
          resourceNames: ['psp.flannel.unprivileged']
        - apiGroups:
            - ""
          resources:
            - pods
          verbs:
            - get
        - apiGroups:
            - ""
          resources:
            - nodes
          verbs:
            - list
            - watch
        - apiGroups:
            - ""
          resources:
            - nodes/status
          verbs:
            - patch
      ---
      kind: ClusterRoleBinding
      apiVersion: rbac.authorization.k8s.io/v1beta1
      metadata:
        name: flannel
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: ClusterRole
        name: flannel
      subjects:
      - kind: ServiceAccount
        name: flannel
        namespace: kube-system
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: flannel
        namespace: kube-system
      ---
      kind: ConfigMap
      apiVersion: v1
      metadata:
        name: kube-flannel-cfg
        namespace: kube-system
        labels:
          tier: node
          app: flannel
      data:
        cni-conf.json: |
          {
            "name": "cbr0",
            "cniVersion": "0.3.1",
            "plugins": [
              {
                "type": "flannel",
                "delegate": {
                  "hairpinMode": true,
                  "isDefaultGateway": true
                }
              },
              {
                "type": "portmap",
                "capabilities": {
                  "portMappings": true
                }
              }
            ]
          }
        net-conf.json: |
          {
            "Network": "10.244.0.0/16",
            "Backend": {
              "Type": "vxlan"
            }
          }
      ---
      apiVersion: apps/v1
      kind: DaemonSet
      metadata:
        name: kube-flannel-ds-amd64
        namespace: kube-system
        labels:
          tier: node
          app: flannel
      spec:
        selector:
          matchLabels:
            app: flannel
        template:
          metadata:
            labels:
              tier: node
              app: flannel
          spec:
            affinity:
              nodeAffinity:
                requiredDuringSchedulingIgnoredDuringExecution:
                  nodeSelectorTerms:
                    - matchExpressions:
                        - key: kubernetes.io/os
                          operator: In
                          values:
                            - linux
                        - key: kubernetes.io/arch
                          operator: In
                          values:
                            - amd64
            hostNetwork: true
            tolerations:
            - operator: Exists
              effect: NoSchedule
            serviceAccountName: flannel
            initContainers:
            - name: install-cni
              image: quay.io/coreos/flannel:v0.12.0-amd64
              command:
              - cp
              args:
              - -f
              - /etc/kube-flannel/cni-conf.json
              - /etc/cni/net.d/10-flannel.conflist
              volumeMounts:
              - name: cni
                mountPath: /etc/cni/net.d
              - name: flannel-cfg
                mountPath: /etc/kube-flannel/
            containers:
            - name: kube-flannel
              image: quay.io/coreos/flannel:v0.12.0-amd64
              command:
              - /opt/bin/flanneld
              args:
              - --ip-masq
              - --kube-subnet-mgr
              resources:
                requests:
                  cpu: "100m"
                  memory: "50Mi"
                limits:
                  cpu: "100m"
                  memory: "50Mi"
              securityContext:
                privileged: false
                capabilities:
                  add: ["NET_ADMIN"]
              env:
              - name: POD_NAME
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.name
              - name: POD_NAMESPACE
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.namespace
              volumeMounts:
              - name: run
                mountPath: /run/flannel
              - name: flannel-cfg
                mountPath: /etc/kube-flannel/
            volumes:
              - name: run
                hostPath:
                  path: /run/flannel
              - name: cni
                hostPath:
                  path: /etc/cni/net.d
              - name: flannel-cfg
                configMap:
                  name: kube-flannel-cfg
      ---
      apiVersion: apps/v1
      kind: DaemonSet
      metadata:
        name: kube-flannel-ds-arm64
        namespace: kube-system
        labels:
          tier: node
          app: flannel
      spec:
        selector:
          matchLabels:
            app: flannel
        template:
          metadata:
            labels:
              tier: node
              app: flannel
          spec:
            affinity:
              nodeAffinity:
                requiredDuringSchedulingIgnoredDuringExecution:
                  nodeSelectorTerms:
                    - matchExpressions:
                        - key: kubernetes.io/os
                          operator: In
                          values:
                            - linux
                        - key: kubernetes.io/arch
                          operator: In
                          values:
                            - arm64
            hostNetwork: true
            tolerations:
            - operator: Exists
              effect: NoSchedule
            serviceAccountName: flannel
            initContainers:
            - name: install-cni
              image: quay.io/coreos/flannel:v0.12.0-arm64
              command:
              - cp
              args:
              - -f
              - /etc/kube-flannel/cni-conf.json
              - /etc/cni/net.d/10-flannel.conflist
              volumeMounts:
              - name: cni
                mountPath: /etc/cni/net.d
              - name: flannel-cfg
                mountPath: /etc/kube-flannel/
            containers:
            - name: kube-flannel
              image: quay.io/coreos/flannel:v0.12.0-arm64
              command:
              - /opt/bin/flanneld
              args:
              - --ip-masq
              - --kube-subnet-mgr
              resources:
                requests:
                  cpu: "100m"
                  memory: "50Mi"
                limits:
                  cpu: "100m"
                  memory: "50Mi"
              securityContext:
                privileged: false
                capabilities:
                   add: ["NET_ADMIN"]
              env:
              - name: POD_NAME
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.name
              - name: POD_NAMESPACE
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.namespace
              volumeMounts:
              - name: run
                mountPath: /run/flannel
              - name: flannel-cfg
                mountPath: /etc/kube-flannel/
            volumes:
              - name: run
                hostPath:
                  path: /run/flannel
              - name: cni
                hostPath:
                  path: /etc/cni/net.d
              - name: flannel-cfg
                configMap:
                  name: kube-flannel-cfg
      ---
      apiVersion: apps/v1
      kind: DaemonSet
      metadata:
        name: kube-flannel-ds-arm
        namespace: kube-system
        labels:
          tier: node
          app: flannel
      spec:
        selector:
          matchLabels:
            app: flannel
        template:
          metadata:
            labels:
              tier: node
              app: flannel
          spec:
            affinity:
              nodeAffinity:
                requiredDuringSchedulingIgnoredDuringExecution:
                  nodeSelectorTerms:
                    - matchExpressions:
                        - key: kubernetes.io/os
                          operator: In
                          values:
                            - linux
                        - key: kubernetes.io/arch
                          operator: In
                          values:
                            - arm
            hostNetwork: true
            tolerations:
            - operator: Exists
              effect: NoSchedule
            serviceAccountName: flannel
            initContainers:
            - name: install-cni
              image: quay.io/coreos/flannel:v0.12.0-arm
              command:
              - cp
              args:
              - -f
              - /etc/kube-flannel/cni-conf.json
              - /etc/cni/net.d/10-flannel.conflist
              volumeMounts:
              - name: cni
                mountPath: /etc/cni/net.d
              - name: flannel-cfg
                mountPath: /etc/kube-flannel/
            containers:
            - name: kube-flannel
              image: quay.io/coreos/flannel:v0.12.0-arm
              command:
              - /opt/bin/flanneld
              args:
              - --ip-masq
              - --kube-subnet-mgr
              resources:
                requests:
                  cpu: "100m"
                  memory: "50Mi"
                limits:
                  cpu: "100m"
                  memory: "50Mi"
              securityContext:
                privileged: false
                capabilities:
                   add: ["NET_ADMIN"]
              env:
              - name: POD_NAME
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.name
              - name: POD_NAMESPACE
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.namespace
              volumeMounts:
              - name: run
                mountPath: /run/flannel
              - name: flannel-cfg
                mountPath: /etc/kube-flannel/
            volumes:
              - name: run
                hostPath:
                  path: /run/flannel
              - name: cni
                hostPath:
                  path: /etc/cni/net.d
              - name: flannel-cfg
                configMap:
                  name: kube-flannel-cfg
      ---
      apiVersion: apps/v1
      kind: DaemonSet
      metadata:
        name: kube-flannel-ds-ppc64le
        namespace: kube-system
        labels:
          tier: node
          app: flannel
      spec:
        selector:
          matchLabels:
            app: flannel
        template:
          metadata:
            labels:
              tier: node
              app: flannel
          spec:
            affinity:
              nodeAffinity:
                requiredDuringSchedulingIgnoredDuringExecution:
                  nodeSelectorTerms:
                    - matchExpressions:
                        - key: kubernetes.io/os
                          operator: In
                          values:
                            - linux
                        - key: kubernetes.io/arch
                          operator: In
                          values:
                            - ppc64le
            hostNetwork: true
            tolerations:
            - operator: Exists
              effect: NoSchedule
            serviceAccountName: flannel
            initContainers:
            - name: install-cni
              image: quay.io/coreos/flannel:v0.12.0-ppc64le
              command:
              - cp
              args:
              - -f
              - /etc/kube-flannel/cni-conf.json
              - /etc/cni/net.d/10-flannel.conflist
              volumeMounts:
              - name: cni
                mountPath: /etc/cni/net.d
              - name: flannel-cfg
                mountPath: /etc/kube-flannel/
            containers:
            - name: kube-flannel
              image: quay.io/coreos/flannel:v0.12.0-ppc64le
              command:
              - /opt/bin/flanneld
              args:
              - --ip-masq
              - --kube-subnet-mgr
              resources:
                requests:
                  cpu: "100m"
                  memory: "50Mi"
                limits:
                  cpu: "100m"
                  memory: "50Mi"
              securityContext:
                privileged: false
                capabilities:
                   add: ["NET_ADMIN"]
              env:
              - name: POD_NAME
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.name
              - name: POD_NAMESPACE
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.namespace
              volumeMounts:
              - name: run
                mountPath: /run/flannel
              - name: flannel-cfg
                mountPath: /etc/kube-flannel/
            volumes:
              - name: run
                hostPath:
                  path: /run/flannel
              - name: cni
                hostPath:
                  path: /etc/cni/net.d
              - name: flannel-cfg
                configMap:
                  name: kube-flannel-cfg
      ---
      apiVersion: apps/v1
      kind: DaemonSet
      metadata:
        name: kube-flannel-ds-s390x
        namespace: kube-system
        labels:
          tier: node
          app: flannel
      spec:
        selector:
          matchLabels:
            app: flannel
        template:
          metadata:
            labels:
              tier: node
              app: flannel
          spec:
            affinity:
              nodeAffinity:
                requiredDuringSchedulingIgnoredDuringExecution:
                  nodeSelectorTerms:
                    - matchExpressions:
                        - key: kubernetes.io/os
                          operator: In
                          values:
                            - linux
                        - key: kubernetes.io/arch
                          operator: In
                          values:
                            - s390x
            hostNetwork: true
            tolerations:
            - operator: Exists
              effect: NoSchedule
            serviceAccountName: flannel
            initContainers:
            - name: install-cni
              image: quay.io/coreos/flannel:v0.12.0-s390x
              command:
              - cp
              args:
              - -f
              - /etc/kube-flannel/cni-conf.json
              - /etc/cni/net.d/10-flannel.conflist
              volumeMounts:
              - name: cni
                mountPath: /etc/cni/net.d
              - name: flannel-cfg
                mountPath: /etc/kube-flannel/
            containers:
            - name: kube-flannel
              image: quay.io/coreos/flannel:v0.12.0-s390x
              command:
              - /opt/bin/flanneld
              args:
              - --ip-masq
              - --kube-subnet-mgr
              resources:
                requests:
                  cpu: "100m"
                  memory: "50Mi"
                limits:
                  cpu: "100m"
                  memory: "50Mi"
              securityContext:
                privileged: false
                capabilities:
                   add: ["NET_ADMIN"]
              env:
              - name: POD_NAME
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.name
              - name: POD_NAMESPACE
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.namespace
              volumeMounts:
              - name: run
                mountPath: /run/flannel
              - name: flannel-cfg
                mountPath: /etc/kube-flannel/
            volumes:
              - name: run
                hostPath:
                  path: /run/flannel
              - name: cni
                hostPath:
                  path: /etc/cni/net.d
              - name: flannel-cfg
                configMap:
                  name: kube-flannel-cfg
      

      查看安装的状态,保证flannel组件处于running状态后,再继续

      kubectl get pods -n kube-system 查看指定名称空间的pods
      kubectl get pods –all-namespace 查看所有名称空间的pods
      
    2. flannel安装完成后,执行第4步骤生成的命令,将节点加入k8s集群

      # 加入之前,执行如下命令,确保master节点的状态为ready状态
      kubectl get nodes
      # 执行命令,加入k8s集群
      kubeadm join 10.0.2.6:6443 --token qzmmt5.zyysl5sizb4jh7hc \
      --discovery-token-ca-cert-hash sha256:145e4c113172904f9f34a05fae013469751cc6ad40adfb299ac0f755c7f750f8 
      

      监控pod状态,确保三个节点的状态都ready

      watch kubectl get pod -n kube-system -o wide
      
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值