k8s的ceph-rbd的volumes的源码阅读


k8s的ceph-rbd的volumes的源码阅读

ceph的rbd的扩容分析

源代码文件:https://github.com/kubernetes/kubernetes/blob/4e7fd98763aa38551941b46ee0ff16f29f19e525/pkg/volume/rbd/rbd_util.go

改源码为kubernetes官方提供的ceph的rbd代码。

线上采用的是ceph.com官方的rbd部署。2种有些不同

kubernetes的rbd的Provision

func (r *rbdVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (*v1.PersistentVolume, error) {

...

创建pv名称为kubernetes-dynamic-pvc-后面接一个随机的UUID

// create random image name
    image := fmt.Sprintf("kubernetes-dynamic-pvc-%s", uuid.NewUUID())
    r.rbdMounter.Image = image

创建pv

rbd, sizeMB, err := r.manager.CreateImage(r)
    if err != nil {
        klog.Errorf("rbd: create volume failed, err: %v", err)
        return nil, err
    }
    klog.Infof("successfully created rbd image %q", image)

具体的pv创建,调用rbd的manage中的接口createimage来创建镜像

func (util *RBDUtil) CreateImage(p *rbdVolumeProvisioner) (r *v1.RBDPersistentVolumeSource, size int, err error) {
    var output []byte
    capacity := p.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
    // Convert to MB that rbd defaults on.
    sz, err := volumehelpers.RoundUpToMiBInt(capacity)
    if err != nil {
        return nil, 0, err
    }
    volSz := fmt.Sprintf("%d", sz)
    mon := util.kernelRBDMonitorsOpt(p.Mon)
    if p.rbdMounter.imageFormat == rbdImageFormat2 {
        klog.V(4).Infof("rbd: create %s size %s format %s (features: %s) using mon %s, pool %s id %s key %s", p.rbdMounter.Image, volSz, p.rbdMounter.imageFormat, p.rbdMounter.imageFeatures, mon, p.rbdMounter.Pool, p.rbdMounter.adminId, p.rbdMounter.adminSecret)
    } else {
        klog.V(4).Infof("rbd: create %s size %s format %s using mon %s, pool %s id %s key %s", p.rbdMounter.Image, volSz, p.rbdMounter.imageFormat, mon, p.rbdMounter.Pool, p.rbdMounter.adminId, p.rbdMounter.adminSecret)
    }
    args := []string{"create", p.rbdMounter.Image, "--size", volSz, "--pool", p.rbdMounter.Pool, "--id", p.rbdMounter.adminId, "-m", mon, "--key=" + p.rbdMounter.adminSecret, "--image-format", p.rbdMounter.imageFormat}
    if p.rbdMounter.imageFormat == rbdImageFormat2 {
        // If no image features is provided, it results in empty string
        // which disable all RBD image format 2 features as expected.
        features := strings.Join(p.rbdMounter.imageFeatures, ",")
        args = append(args, "--image-feature", features)
    }
    output, err = p.exec.Run("rbd", args...)

    if err != nil {
        klog.Warningf("failed to create rbd image, output %v", string(output))
        return nil, 0, fmt.Errorf("failed to create rbd image: %v, command output: %s", err, string(output))
    }

    return &v1.RBDPersistentVolumeSource{
        CephMonitors: p.rbdMounter.Mon,
        RBDImage:     p.rbdMounter.Image,
        RBDPool:      p.rbdMounter.Pool,
    }, sz, nil
}
在镜像中采用rbd命令:
rbd crete $imagename --size $size --pool $pool --id $id -m $mon --key=$secret --image-format $image-format

添加注解

pv := new(v1.PersistentVolume)
    metav1.SetMetaDataAnnotation(&pv.ObjectMeta, volutil.VolumeDynamicallyCreatedByKey, "rbd-dynamic-provisioner")

给pv添加属性

if secretName != "" {
        rbd.SecretRef = new(v1.SecretReference)
        rbd.SecretRef.Name = secretName
        rbd.SecretRef.Namespace = secretNamespace
    } else {
        var filePathRegex = regexp.MustCompile(`^(?:/[^/!;` + "`" + ` ]+)+$`)
        if keyring != "" && !filePathRegex.MatchString(keyring) {
            return nil, fmt.Errorf("keyring field must contain a path to a file")
        }
        rbd.Keyring = keyring
    }

    var volumeMode *v1.PersistentVolumeMode
    if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
        volumeMode = r.options.PVC.Spec.VolumeMode
        if volumeMode != nil && *volumeMode == v1.PersistentVolumeBlock {
            // Block volumes should not have any FSType
            fstype = ""
        }
    }

    rbd.RadosUser = r.Id
    rbd.FSType = fstype
    pv.Spec.PersistentVolumeSource.RBD = rbd
    pv.Spec.PersistentVolumeReclaimPolicy = r.options.PersistentVolumeReclaimPolicy
    pv.Spec.AccessModes = r.options.PVC.Spec.AccessModes
    if len(pv.Spec.AccessModes) == 0 {
        pv.Spec.AccessModes = r.plugin.GetAccessModes()
    }
    pv.Spec.Capacity = v1.ResourceList{
        v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dMi", sizeMB)),
    }
    pv.Spec.MountOptions = r.options.MountOptions
    pv.Spec.VolumeMode = volumeMode

    return pv, nil
}

rbd扩容

rbd的扩容在rbd_util.go中

func (expander *rbdVolumeExpander) ResizeImage(oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
    return expander.manager.ExpandImage(expander, oldSize, newSize)
}

然后调用函数ExpandImage,查看info信息

// ExpandImage runs rbd resize command to resize the specified image.
func (util *RBDUtil) ExpandImage(rbdExpander *rbdVolumeExpander, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) {
    var output []byte
    var err error

    // Convert to MB that rbd defaults on.
    sz := int(volumehelpers.RoundUpToMiB(newSize))
    newVolSz := fmt.Sprintf("%d", sz)
    newSizeQuant := resource.MustParse(fmt.Sprintf("%dMi", sz))

    // Check the current size of rbd image, if equals to or greater that the new request size, do nothing.
    curSize, infoErr := util.rbdInfo(rbdExpander.rbdMounter)
    if infoErr != nil {
        return oldSize, fmt.Errorf("rbd info failed, error: %v", infoErr)
    }
    if curSize >= sz {
        return newSizeQuant, nil
    }
调用函数info进行消息查询,进行判断

rbdInfo函数

// rbdInfo runs `rbd info` command to get the current image size in MB.
func (util *RBDUtil) rbdInfo(b *rbdMounter) (int, error) {
    var err error
    var output []byte

    // If we don't have admin id/secret (e.g. attaching), fallback to user id/secret.
    id := b.adminId
    secret := b.adminSecret
    if id == "" {
        id = b.Id
        secret = b.Secret
    }

    mon := util.kernelRBDMonitorsOpt(b.Mon)

    klog.V(4).Infof("rbd: info %s using mon %s, pool %s id %s key %s", b.Image, mon, b.Pool, id, secret)
    output, err = b.exec.Run("rbd",
        "info", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret, "--format=json")

    if err, ok := err.(*exec.Error); ok {
        if err.Err == exec.ErrNotFound {
            klog.Errorf("rbd cmd not found")
            // fail fast if rbd command is not found.
            return 0, err
        }
    }

    // If command never succeed, returns its last error.
    if err != nil {
        return 0, err
    }

    if len(output) == 0 {
        return 0, fmt.Errorf("can not get image size info %s: %s", b.Image, string(output))
    }

    return getRbdImageSize(output)
}

通过rbd命令获取相关信息
rbd info $image --pool $pool -m $mon --id $id --key=$secrte --format=json
然后格式化输出返回镜像大小

在函数ExpandImage进行扩容

// rbd resize.
    mon := util.kernelRBDMonitorsOpt(rbdExpander.rbdMounter.Mon)
    klog.V(4).Infof("rbd: resize %s using mon %s, pool %s id %s key %s", rbdExpander.rbdMounter.Image, mon, rbdExpander.rbdMounter.Pool, rbdExpander.rbdMounter.adminId, rbdExpander.rbdMounter.adminSecret)
    output, err = rbdExpander.exec.Run("rbd",
        "resize", rbdExpander.rbdMounter.Image, "--size", newVolSz, "--pool", rbdExpander.rbdMounter.Pool, "--id", rbdExpander.rbdMounter.adminId, "-m", mon, "--key="+rbdExpander.rbdMounter.adminSecret)
    if err == nil {
        return newSizeQuant, nil
    }

    klog.Errorf("failed to resize rbd image: %v, command output: %s", err, string(output))
    return oldSize, err
}

在改函数中先调用rbd resize $image --size $newsize --pool $pool --id $id --m $mon --key=$secret_key,完成扩容

扩展: rbd的命令的使用

  • 查看info信息

    # rbd info kubernetes-dynamic-pvc-376331bd-ddb6-11e9-86f1-d2ff46c62203 -m 10.0.7.52 --key=AQBRRgNduPgTIxAAp9KLXRxjFYLLXwiENdGvFw== --pool kube --format=json 
    {"name":"kubernetes-dynamic-pvc-376331bd-ddb6-11e9-86f1-d2ff46c62203","id":"ac726b8b4567","size":3221225472,"objects":768,"order":22,"object_size":4194304,"block_name_prefix":"rbd_data.ac726b8b4567","format":2,"features":["layering"],"op_features":[],"flags":[],"create_timestamp":"Mon Sep 23 11:57:12 2019"}
  • 删除image

    [root@k8s-ceshi-01.novalocal 16:46 ~/k8s/ceph/rbd/deploy/rbac]
    # rbd remove kubernetes-dynamic-pvc-376331bd-ddb6-11e9-86f1-d2ff46c62203 -m 10.0.7.52 --key=AQBRRgNduPgTIxAAp9KLXRxjFYLLXwiENdGvFw==  --pool kube         
    Removing image: 100% complete...done.
  • 列出images

    # rbd list -m 10.0.7.52 --key=AQBRRgNduPgTIxAAp9KLXRxjFYLLXwiENdGvFw==  --pool kube                                 kubernetes-dynamic-pvc-50444df4-d9f9-11e9-94f6-12f1cfd47f5e
  • 扩容images

    # rbd resize --image kubernetes-dynamic-pvc-376331bd-ddb6-11e9-86f1-d2ff46c62203 --size 51200 -m 10.0.7.52 --key=AQBRRgNduPgTIxAAp9KLXRxjFYLLXwiENdGvFw==  --pool kube     
    Resizing image: 100% complete...done.