secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: rbd-secret
type: "kubernetes.io/rbd"
data:
key: QVFBM2IvUmNqQkM2S0JBQVZZL041aFNJSk53algvTDB1eU56Y3c9PQ==
rbd-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: rbd-sc
provisioner: kubernetes.io/rbd
parameters:
monitors: 10.200.112.23:6789
adminId: admin
adminSecretName: rbd-secret
adminSecretNamespace: default
pool: replicapool
userId: admin
userSecretName: rbd-secret
rbd-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: rbd-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
storageClassName: rbd-sc
resources:
requests:
storage: 10G
syncClaim 根据注解 pv.kubernetes.io/bind-completed
--> syncUnboundClaim
--> provisionClaim
--> provisionClaimOperation
--> plugin.NewProvisioner (第 1 章节讲解)
--> provisioner.Provision (第 2 章节讲解)
1. NewProvisioner
实例化 rbdVolumeProvisioner 结构,没啥可说的了
func (plugin *rbdPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
return plugin.newProvisionerInternal(options, &RBDUtil{})
}
func (plugin *rbdPlugin) newProvisionerInternal(options volume.VolumeOptions, manager diskManager) (volume.Provisioner, error) {
return &rbdVolumeProvisioner{
rbdMounter: &rbdMounter{
rbd: newRBD("", "", "", "", false, plugin, manager),
},
options: options,
}, nil
}
2. Provision 函数
验证以及获得 storageclass 参数 parameters,可以参看如上 rbd-class.yaml
if !volutil.AccessModesContainedInAll(r.plugin.GetAccessModes(), r.options.PVC.Spec.AccessModes) {
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", r.options.PVC.Spec.AccessModes, r.plugin.GetAccessModes())
}
if r.options.PVC.Spec.Selector != nil {
return nil, fmt.Errorf("claim Selector is not supported")
}
var err error
adminSecretName := ""
adminSecretNamespace := rbdDefaultAdminSecretNamespace
secret := ""
secretName := ""
secretNamespace := ""
keyring := ""
imageFormat := rbdImageFormat2
fstype := ""
2.1 格式化只能为 1 或者 2,默认为 2
这个格式化,详解看后面ceph pool image format 解析
// sanity check
if imageFormat != rbdImageFormat1 && imageFormat != rbdImageFormat2 {
return nil, fmt.Errorf("invalid ceph imageformat %s, expecting %s or %s",
imageFormat, rbdImageFormat1, rbdImageFormat2)
}
r.imageFormat = imageFormat
2.2 CreateImage 函数
路径 pkg/volume/rbd/rbd_util.go,rbd image是由 kubernetes-dynamic-pv 加上随机UUID生成
rbd create kubernetes-dynamic-pvc-371a0915-859d-11e9-94ca-0800271c9f15 --size xxx --pool xxxx --id xxx -m xxx --key=xxx -image-format xxxx
func (util *RBDUtil) CreateImage(p *rbdVolumeProvisioner) (r *v1.RBDPersistentVolumeSource, size int, err error) {
。。。。。。
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...)
2.3 pv 注解设置 kubernetes.io/createdby: rbd-dynamic-provisioner
metadata:
annotations:
kubernetes.io/createdby: rbd-dynamic-provisioner
pv := new(v1.PersistentVolume)
metav1.SetMetaDataAnnotation(&pv.ObjectMeta, volutil.VolumeDynamicallyCreatedByKey, "rbd-dynamic-provisioner")
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
}
2.4 设置 pv 信息
具体可以查看如下 pv yaml 文件
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
注意: rbd 插件只支持 ReadWriteOnce 以及 ReadOnlyMany
func (plugin *rbdPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
return []v1.PersistentVolumeAccessMode{
v1.ReadWriteOnce,
v1.ReadOnlyMany,
}
}
reconcile()
--> rc.operationExecutor.VerifyControllerAttachedVolume
--> GenerateVerifyControllerAttachedVolumeFunc
--> MountVolume
--> GenerateMountVolumeFunc
--> NewAttacher (第 3 章节讲解)
--> volumeAttacher.WaitForAttach (第 4 章节讲解)
--> AttachDisk
--> deviceMountableVolumePlugin.NewDeviceMounter (第 5 章节讲解)
-- > volumeDeviceMounter.MountDevice (第 6 章节讲解)
--> volumePlugin.NewMounter (第 7 章节讲解)
--> volumeMounter.CanMount()
--> volumeMounter.Setup (第 8 章节讲解)
3. NewAttacher
NewAttacher 实例化,实现了 Attach WaitForAttach 方法,manager 有 rbdUtil实现
// NewAttacher implements AttachableVolumePlugin.NewAttacher.
func (plugin *rbdPlugin) NewAttacher() (volume.Attacher, error) {
return plugin.newAttacherInternal(&RBDUtil{})
}
func (plugin *rbdPlugin) newAttacherInternal(manager diskManager) (volume.Attacher, error) {
return &rbdAttacher{
plugin: plugin,
manager: manager,
mounter: volutil.NewSafeFormatAndMountFromHost(plugin.GetPluginName(), plugin.host),
}, nil
}
4. WaitForAttach 函数
主要实现在 AttachDisk,这个由rbdUtil实现
// WaitForAttach implements Attacher.WaitForAttach. It's called by kublet to
// attach volume onto the node.
// This method is idempotent, callers are responsible for retrying on failure.
func (attacher *rbdAttacher) WaitForAttach(spec *volume.Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error) {
klog.V(4).Infof("rbd: waiting for attach volume (name: %s) for pod (name: %s, uid: %s)", spec.Name(), pod.Name, pod.UID)
mounter, err := attacher.plugin.createMounterFromVolumeSpecAndPod(spec, pod)
if err != nil {
klog.Warningf("failed to create mounter: %v", spec)
return "", err
}
realDevicePath, err := attacher.manager.AttachDisk(*mounter)
if err != nil {
return "", err
}
klog.V(3).Infof("rbd: successfully wait for attach volume (spec: %s, pool: %s, image: %s) at %s", spec.Name(), mounter.Pool, mounter.Image, realDevicePath)
return realDevicePath, nil
}
4.1 AttachDisk
主要功能是attach 到节点,分片段一块块讲解,这个globalPDPath路径格式 kubernetes.io/rbd mounts ${pool} -image ${image}
示例:/var/lib/kubelet/plugins/kubernetes.io/rbd/mounts/replicapool-image-kubernetes-dynamic-pvc-371a0915-859d-11e9-94ca- 0800271c9f15
// AttachDisk attaches the disk on the node.
func (util *RBDUtil) AttachDisk(b rbdMounter) (string, error) {
var output []byte
globalPDPath := util.MakeGlobalPDName(*b.rbd)
if pathExists, pathErr := volutil.PathExists(globalPDPath); pathErr != nil {
return "", fmt.Errorf("Error checking if path exists: %v", pathErr)
} else if !pathExists {
if err := os.MkdirAll(globalPDPath, 0750); err != nil {
return "", err
}
}
4.1.1 waitForPath 函数,不存在路径则试几次创建,rbd 实现在 getRbdDevFromImageAndPool
// Stat a path, if it doesn't exist, retry maxRetries times.
func waitForPath(pool, image string, maxRetries int, useNbdDriver bool) (string, bool) {
for i := 0; i < maxRetries; i++ {
if i != 0 {
time.Sleep(time.Second)
}
if useNbdDriver {
if devicePath, found := getNbdDevFromImageAndPool(pool, image); found {
return devicePath, true
}
} else {
if devicePath, found := getRbdDevFromImageAndPool(pool, image); found {
return devicePath, true
}
}
}
return "", false
}
4.1.1.1 getRbdDevFromImageAndPool
主要是查看 /sys/bus/rbd/devices/X/name 和 /sys/bus/rbd/devices/X/pool 这俩文件,在看看 /dev/rbd/X 是否存在
// Search /sys/bus for rbd device that matches given pool and image.
func getRbdDevFromImageAndPool(pool string, image string) (string, bool) {
// /sys/bus/rbd/devices/X/name and /sys/bus/rbd/devices/X/pool
sys_path := "/sys/bus/rbd/devices"
if dirs, err := ioutil.ReadDir(sys_path); err == nil {
for _, f := range dirs {
name := f.Name()
// First match pool, then match name.
poolFile := path.Join(sys_path, name, "pool")
poolBytes, err := ioutil.ReadFile(poolFile)
if strings.TrimSpace(string(poolBytes)) != pool {
klog.V(4).Infof("device %s is not %q: %q", name, pool, string(poolBytes))
continue
}
imgFile := path.Join(sys_path, name, "name")
if strings.TrimSpace(string(imgBytes)) != image {
klog.V(4).Infof("device %s is not %q: %q", name, image, string(imgBytes))
continue
}
// Found a match, check if device exists.
devicePath := "/dev/rbd" + name
if _, err := os.Lstat(devicePath); err == nil {
return devicePath, true
}
}
}
return "", false
}
4.1.1.2 未发现 /dev/rbd/X 文件情况
再看看 accessModes类型,如果只是 ReadWriteMany 就不需要查验是否多个pod使用
if !mapped {
// Currently, we don't acquire advisory lock on image, but for backward
// compatibility, we need to check if the image is being used by nodes running old kubelet.
// osd_client_watch_timeout defaults to 30 seconds, if the watcher stays active longer than 30 seconds,
// rbd image does not get mounted and failure message gets generated.
backoff := wait.Backoff{
Duration: rbdImageWatcherInitDelay,
Factor: rbdImageWatcherFactor,
Steps: rbdImageWatcherSteps,
}
needValidUsed := true
if b.accessModes != nil {
// If accessModes only contains ReadOnlyMany, we don't need check rbd status of being used.
if len(b.accessModes) == 1 && b.accessModes[0] == v1.ReadOnlyMany {
needValidUsed = false
}
}
4.1.1.3 如果不让多个pod 使用情况,查看rbd 状态,如果有watchers证明被使用了
# rbd status kubernetes-dynamic-pvc-7ca75ce6-85ca-11e9-958a-0800271c9f15 --pool replicapool
Watchers:
watcher=192.168.74.57:0/1080495508 client.14269 cookie=18446462598732840961
if needValidUsed {
err := wait.ExponentialBackoff(backoff, func() (bool, error) {
used, rbdOutput, err := util.rbdStatus(&b)
if err != nil {
return false, fmt.Errorf("fail to check rbd image status with: (%v), rbd output: (%s)", err, rbdOutput)
}
return !used, nil
})
// Return error if rbd image has not become available for the specified timeout.
if err == wait.ErrWaitTimeout {
return "", fmt.Errorf("rbd image %s/%s is still being used", b.Pool, b.Image)
}
// Return error if any other errors were encountered during waiting for the image to become available.
if err != nil {
return "", err
}
}
4.1.1.4 执行 rbd map
rbd map ${pool}/${image}
// Execute command to map a rbd device for mounter.
// rbdCmd is driver dependent and either "rbd" or "rbd-nbd".
func execRbdMap(b rbdMounter, rbdCmd string, mon string) ([]byte, error) {
// Commandline: rbdCmd map imgPath ...
// do not change this format - some tools like rbd-nbd are strict about it.
imgPath := fmt.Sprintf("%s/%s", b.Pool, b.Image)
if b.Secret != "" {
return b.exec.Run(rbdCmd,
"map", imgPath, "--id", b.Id, "-m", mon, "--key="+b.Secret)
} else {
return b.exec.Run(rbdCmd,
"map", imgPath, "--id", b.Id, "-m", mon, "-k", b.Keyring)
}
}
5. NewDeviceMounter
太么懒了,直接使用 Attacher
// NewAttacher implements AttachableVolumePlugin.NewAttacher.
func (plugin *rbdPlugin) NewAttacher() (volume.Attacher, error) {
return plugin.newAttacherInternal(&RBDUtil{})
}
// NewDeviceMounter implements DeviceMountableVolumePlugin.NewDeviceMounter
func (plugin *rbdPlugin) NewDeviceMounter() (volume.DeviceMounter, error) {
return plugin.NewAttacher()
}
6. MountDevice 函数
首先看看是否deviceMountPath已经挂载了,如果已经挂载则不处理
// MountDevice implements Attacher.MountDevice. It is called by the kubelet to
// mount device at the given mount path.
// This method is idempotent, callers are responsible for retrying on failure.
func (attacher *rbdAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error {
klog.V(4).Infof("rbd: mouting device %s to %s", devicePath, deviceMountPath)
notMnt, err := attacher.mounter.IsLikelyNotMountPoint(deviceMountPath)
if err != nil {
if os.IsNotExist(err) {
if err := os.MkdirAll(deviceMountPath, 0750); err != nil {
return err
}
notMnt = true
} else {
return err
}
}
if !notMnt {
return nil
}
6.1 获得挂载参数,调用FormatAndMount格式化并进行 mount操作
其实操作命令就是 mount 以及 mkfs.xxx /dev/rbdX
fstype, err := getVolumeSourceFSType(spec)
if err != nil {
return err
}
ro, err := getVolumeSourceReadOnly(spec)
if err != nil {
return err
}
options := []string{}
if ro {
options = append(options, "ro")
}
mountOptions := volutil.MountOptionFromSpec(spec, options...)
err = attacher.mounter.FormatAndMount(devicePath, deviceMountPath, fstype, mountOptions)
7. NewMounter 函数
主要是获得secret,主要函数在newMounterInternal
func (plugin *rbdPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
if err != nil {
return nil, err
}
secret := ""
if len(secretName) > 0 && len(secretNs) > 0 {
// if secret is provideded, retrieve it
kubeClient := plugin.host.GetKubeClient()
if kubeClient == nil {
return nil, fmt.Errorf("Cannot get kube client")
}
secrets, err := kubeClient.CoreV1().Secrets(secretNs).Get(secretName, metav1.GetOptions{})
if err != nil {
err = fmt.Errorf("Couldn't get secret %v/%v err: %v", secretNs, secretName, err)
return nil, err
}
for _, data := range secrets.Data {
secret = string(data)
}
}
// Inject real implementations here, test through the internal function.
return plugin.newMounterInternal(spec, pod.UID, &RBDUtil{}, secret)
}
7.1 newMounterInternal
实例化 rbdMounter,包括rbd 信息
func (plugin *rbdPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, secret string) (volume.Mounter, error) {
mon, err := getVolumeSourceMonitors(spec)
return &rbdMounter{
rbd: newRBD(podUID, spec.Name(), img, pool, ro, plugin, manager),
Mon: mon,
Id: id,
Keyring: keyring,
Secret: secret,
fsType: fstype,
mountOptions: volutil.MountOptionFromSpec(spec),
accessModes: ams,
}, nil
}
8. SetUp 函数
主要在 diskSetUp这个主要函数中
func (b *rbdMounter) SetUpAt(dir string, fsGroup *int64) error {
// diskSetUp checks mountpoints and prevent repeated calls
klog.V(4).Infof("rbd: attempting to setup at %s", dir)
err := diskSetUp(b.manager, *b, dir, b.mounter, fsGroup)
if err != nil {
klog.Errorf("rbd: failed to setup at %s %v", dir, err)
}
klog.V(3).Infof("rbd: successfully setup at %s", dir)
return err
}
8.1 diskSetUp 函数
查看目录是否已经被挂载了,路径根据 image,
kubernetes.io/rbd mounts ${pool} -image ${image}
// utility to mount a disk based filesystem
func diskSetUp(manager diskManager, b rbdMounter, volPath string, mounter mount.Interface, fsGroup *int64) error {
globalPDPath := manager.MakeGlobalPDName(*b.rbd)
notMnt, err := mounter.IsLikelyNotMountPoint(globalPDPath)
if err != nil && !os.IsNotExist(err) {
klog.Errorf("cannot validate mountpoint: %s", globalPDPath)
return err
}
if notMnt {
return fmt.Errorf("no device is mounted at %s", globalPDPath)
}
8.1.1 主要是获得路径,如下格式
/var/lib/kubelet/plugins/kubernetes.io/rbd/mounts/replicapool-image-kubernetes-dynamic-pvc-371a0915-859d-11e9-94ca- 0800271c9f15
// Make a directory like /var/lib/kubelet/plugins/kubernetes.io/rbd/mounts/pool-image-image.
func makePDNameInternal(host volume.VolumeHost, pool string, image string) string {
// Backward compatibility for the deprecated format: /var/lib/kubelet/plugins/kubernetes.io/rbd/rbd/pool-image-image.
deprecatedDir := path.Join(host.GetPluginDir(rbdPluginName), "rbd", pool+"-image-"+image)
info, err := os.Stat(deprecatedDir)
if err == nil && info.IsDir() {
// The device mount path has already been created with the deprecated format, return it.
klog.V(5).Infof("Deprecated format path %s found", deprecatedDir)
return deprecatedDir
}
// Return the canonical format path.
return path.Join(host.GetPluginDir(rbdPluginName), mount.MountsInGlobalPDPath, pool+"-image-"+image)
}
8.1.2 如果 volPath 没有被挂载,则创建该目录,进行mount 操作
notMnt, err = mounter.IsLikelyNotMountPoint(volPath)
if err != nil && !os.IsNotExist(err) {
klog.Errorf("cannot validate mountpoint: %s", volPath)
return err
}
if !notMnt {
return nil
}
if err := os.MkdirAll(volPath, 0750); err != nil {
klog.Errorf("failed to mkdir:%s", volPath)
return err
}
// Perform a bind mount to the full path to allow duplicate mounts of the same disk.
options := []string{"bind"}
if (&b).GetAttributes().ReadOnly {
options = append(options, "ro")
}
mountOptions := util.JoinMountOptions(b.mountOptions, options)
err = mounter.Mount(globalPDPath, volPath, "", mountOptions)
if err != nil {
klog.Errorf("failed to bind mount:%s", globalPDPath)
return err
}
8.1.3 如果不是只读模式,则设置所有权
if !b.ReadOnly {
volume.SetVolumeOwnership(&b, fsGroup)
}
总结:
Provision 这个主要是 rbd create 操作
Attach 主要是 rbd map
MountDevice, mount /dev/rbdX /var/lib/kubelet/plugins/XXXX
SetUp 这个是 mount 操作
pvc.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
annotations:
kubernetes.io/createdby: rbd-dynamic-provisioner
pv.kubernetes.io/bound-by-controller: "yes"
pv.kubernetes.io/provisioned-by: kubernetes.io/rbd
creationTimestamp: "2019-06-03T01:16:31Z"
finalizers:
- kubernetes.io/pv-protection
name: pvc-306f0fd8-859d-11e9-b873-0800271c9f15
resourceVersion: "316160"
selfLink: /api/v1/persistentvolumes/pvc-306f0fd8-859d-11e9-b873-0800271c9f15
uid: 3889cdb2-859d-11e9-b873-0800271c9f15
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 9537Mi
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: rbd-pvc
namespace: default
resourceVersion: "316146"
uid: 306f0fd8-859d-11e9-b873-0800271c9f15
persistentVolumeReclaimPolicy: Delete
rbd:
image: kubernetes-dynamic-pvc-371a0915-859d-11e9-94ca-0800271c9f15
keyring: /etc/ceph/keyring
monitors:
- 10.200.112.23:6789
pool: replicapool
secretRef:
name: rbd-secret
user: admin
storageClassName: rbd-sc
volumeMode: Filesystem
status:
phase: Bound
ceph的rbd 理解
Ceph支持的特性,以COW(写时复制)的方式从RBD快照创建克隆,在Ceph中被称为快照分层。分层特性允许用户创建多个CEPH RBD克隆实例。这些特性应用于OpenStack等云平台中,使用快照形式保护ceph RBD 镜像,快照是只读的,但COW克隆是完全可以写 ,可以多次来孵化实例,对云平台来说是非常有用的。
Ceph RBD镜像有format-1 和 format-2两种类型,RBD支持这两种类型,但是分层特性COW克隆特性只支持format-2镜像,默认RBD创建的镜像是format-1。(这个在克隆的时候特别重要)
- Linux内核支不支持rbd块设备: modprobe rbd
- rbd create (pool_name)/(rbd_name) --size xxxxxMB就可以创建一个块设备
- 映射块设备到你的机器 rbd map (pool_name)/(rbd_name)
ceph pool image format 解析
一个rbd image实际上包含了多个对象(默认情况下是image_size/4M)
# rbd info replicapool/kubernetes-dynamic-pvc-371a0915-859d-11e9-94ca-0800271c9f15
rbd image 'kubernetes-dynamic-pvc-371a0915-859d-11e9-94ca-0800271c9f15':
size 9.3 GiB in 2385 objects
order 22 (4 MiB objects)
snapshot_count: 0
id: 10dd6b8b4567
block_name_prefix: rbd_data.10dd6b8b4567
format: 2
features:
op_features:
flags:
create_timestamp: Mon Jun 3 01:16:31 2019
如果image-format = 2,如上格式 rbd_data.xxxxxx,如果image-format = 1,格式为 rb.0.xxxxxxx
如下一个image对象是由多个object组成的,他们每一个的存储位置可能都不一样
# rados -p replicapool ls | grep rbd_data.10dd6b8b4567
rbd_data.10dd6b8b4567.0000000000000427
rbd_data.10dd6b8b4567.000000000000043b
rbd_data.10dd6b8b4567.000000000000042f
rbd_data.10dd6b8b4567.000000000000042a
rbd_data.10dd6b8b4567.0000000000000420
rbd_data.10dd6b8b4567.0000000000000438
rbd_data.10dd6b8b4567.0000000000000432
rbd_data.10dd6b8b4567.0000000000000320
rbd_data.10dd6b8b4567.000000000000043c
rbd_data.10dd6b8b4567.0000000000000433
rbd_data.10dd6b8b4567.0000000000000620
rbd_data.10dd6b8b4567.0000000000000435
rbd_data.10dd6b8b4567.00000000000000e0
rbd_data.10dd6b8b4567.000000000000042b
rbd_data.10dd6b8b4567.0000000000000422
rbd_data.10dd6b8b4567.000000000000042d
rbd_data.10dd6b8b4567.0000000000000434
rbd_data.10dd6b8b4567.0000000000000421
rbd_data.10dd6b8b4567.0000000000000437
rbd_data.10dd6b8b4567.000000000000043d
rbd_data.10dd6b8b4567.0000000000000436
rbd_data.10dd6b8b4567.0000000000000430
rbd_data.10dd6b8b4567.000000000000042c
rbd_data.10dd6b8b4567.0000000000000429
rbd_data.10dd6b8b4567.0000000000000428
rbd_data.10dd6b8b4567.0000000000000950
rbd_data.10dd6b8b4567.0000000000000000
rbd_data.10dd6b8b4567.0000000000000360
rbd_data.10dd6b8b4567.0000000000000060
rbd_data.10dd6b8b4567.0000000000000400
rbd_data.10dd6b8b4567.00000000000000a0
rbd_data.10dd6b8b4567.0000000000000600
rbd_data.10dd6b8b4567.0000000000000120
rbd_data.10dd6b8b4567.0000000000000800
rbd_data.10dd6b8b4567.0000000000000020
rbd_data.10dd6b8b4567.0000000000000439
rbd_data.10dd6b8b4567.0000000000000425
rbd_data.10dd6b8b4567.0000000000000424
rbd_data.10dd6b8b4567.0000000000000008
rbd_data.10dd6b8b4567.000000000000043a
rbd_data.10dd6b8b4567.0000000000000426
rbd_data.10dd6b8b4567.000000000000042e
rbd_data.10dd6b8b4567.000000000000043e
rbd_data.10dd6b8b4567.0000000000000423
rbd_data.10dd6b8b4567.0000000000000001
rbd_data.10dd6b8b4567.0000000000000200
rbd_data.10dd6b8b4567.0000000000000431
rbd_data.10dd6b8b4567.000000000000043f
# ceph osd map replicapool rbd_data.10dd6b8b4567.000000000000043f
osdmap e19 pool 'replicapool' (1) object 'rbd_data.10dd6b8b4567.000000000000043f' -> pg 1.309ade3f (1.3f) -> up ([1,0], p1) acting ([1,0], p1)
这代表在pool rbd中的 rbd_data.10dd6b8b4567.000000000000043f 这个对象位于 1.3f 这个pg中,并且位于osd1和osd0上(两个副本)
如下为 osd 中 pg 里面的数据内容
[root@node1 1.3f_head]# ll
总用量 4100
-rw-r--r-- 1 root root 0 6月 3 08:53 __head_0000003F__1
-rw-r--r-- 1 root root 4194304 6月 3 09:39 rbd\udata.10dd6b8b4567.000000000000043f__head_309ADE3F__1
[root@node1 1.3f_head]# pwd
/var/lib/rook/osd0/current/1.3f_head