我们的设想:
我们使用ceph存储一些机器学习培训数据集,工作流如下所示:
使用AccessMode: ReadWriteOnce创建一个ceph pvc pvc培训数据。
创建一个用1脚安装pvc培训数据的写作业,并将培训数据写入pvc培训数据。
将培训数据写入pvc培训数据后,容器将退出,pvc培训数据pvc由k8s卸载,完成写入工作。
创建一个带有n个n >= 1的读取作业,在其中安装pvc-培训-数据和readOnly: true来使用培训数据。顺便说一句:我们使用k8s 1.6.1
到目前为止,工作流在我们的使用场景中运行良好,但是我有一些关于PVC AccessMode和ceph与AccessMode: ReadWriteOnce有关的问题。
发布于 2017-05-25 19:45:59
关于你的第一个问题:
文档明确指出:
Important! A volume can only be mounted using one access mode at a
time, even if it supports many.我不太清楚你的第二个问题。但考虑到第一个问题的答案,我认为这可能是无效的吗?
发布于 2019-10-18 07:58:53
要回答这个问题,不妨看一下源代码。正如我在集群迁移中遇到的一个问题一样,下面是这样的情况:我们有一个具有v1.9的集群,还有一个具有accessMode: ReadWriteMany (RWX)的PV和accessMode: ReadWriteOnce的PVC,这两个集群都可以绑定而不会出现任何错误。
我们将一些应用程序迁移到新集群(v1.12),在新集群中,PVC绑定给出了一个错误:
无法绑定到请求的卷“卷名”:不兼容的accessMode
我在v1.12的源代码中搜索了错误,并看到了以下几行:
第1.12节:
//checkVolumeSatisfyClaim checks if the volume requested by the claim satisfies the requirements of the claim
func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) error {
requestedQty := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
requestedSize := requestedQty.Value()
// check if PV's DeletionTimeStamp is set, if so, return error.
if utilfeature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection) {
if volume.ObjectMeta.DeletionTimestamp != nil {
return fmt.Errorf("the volume is marked for deletion")
}
}
volumeQty := volume.Spec.Capacity[v1.ResourceStorage]
volumeSize := volumeQty.Value()
if volumeSize < requestedSize {
return fmt.Errorf("requested PV is too small")
}
requestedClass := v1helper.GetPersistentVolumeClaimClass(claim)
if v1helper.GetPersistentVolumeClass(volume) != requestedClass {
return fmt.Errorf("storageClassName does not match")
}
isMisMatch, err := checkVolumeModeMisMatches(&claim.Spec, &volume.Spec)
if err != nil {
return fmt.Errorf("error checking volumeMode: %v", err)
}
if isMisMatch {
return fmt.Errorf("incompatible volumeMode")
}
if !checkAccessModes(claim, volume) {
return fmt.Errorf("incompatible accessMode")
}
return nil
}
// Returns true if PV satisfies all the PVC's requested AccessModes
func checkAccessModes(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) bool {
pvModesMap := map[v1.PersistentVolumeAccessMode]bool{}
for _, mode := range volume.Spec.AccessModes {
pvModesMap[mode] = true
}
for _, mode := range claim.Spec.AccessModes {
_, ok := pvModesMap[mode]
if !ok {
return false
}
}
return true
}五.9:
//checkVolumeSatisfyClaim checks if the volume requested by the claim satisfies the requirements of the claim
func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) error {
requestedQty := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
requestedSize := requestedQty.Value()
isMisMatch, err := checkVolumeModeMisMatches(&claim.Spec, &volume.Spec)
if err != nil {
return fmt.Errorf("error checking if volumeMode was a mismatch: %v", err)
}
volumeQty := volume.Spec.Capacity[v1.ResourceStorage]
volumeSize := volumeQty.Value()
if volumeSize < requestedSize {
return fmt.Errorf("Storage capacity of volume[%s] requested by claim[%v] is not enough", volume.Name, claimToClaimKey(claim))
}
requestedClass := v1helper.GetPersistentVolumeClaimClass(claim)
if v1helper.GetPersistentVolumeClass(volume) != requestedClass {
return fmt.Errorf("Class of volume[%s] is not the same as claim[%v]", volume.Name, claimToClaimKey(claim))
}
if isMisMatch {
return fmt.Errorf("VolumeMode[%v] of volume[%s] is incompatible with VolumeMode[%v] of claim[%v]", volume.Spec.VolumeMode, volume.Name, claim.Spec.VolumeMode, claim.Name)
}
return nil
}
// checkVolumeModeMatches is a convenience method that checks volumeMode for PersistentVolume
// and PersistentVolumeClaims along with making sure that the Alpha feature gate BlockVolume is
// enabled.
// This is Alpha and could change in the future.
func checkVolumeModeMisMatches(pvcSpec *v1.PersistentVolumeClaimSpec, pvSpec *v1.PersistentVolumeSpec) (bool, error) {
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
if pvSpec.VolumeMode != nil && pvcSpec.VolumeMode != nil {
requestedVolumeMode := *pvcSpec.VolumeMode
pvVolumeMode := *pvSpec.VolumeMode
return requestedVolumeMode != pvVolumeMode, nil
} else {
// This also should retrun an error, this means that
// the defaulting has failed.
return true, fmt.Errorf("api defaulting for volumeMode failed")
}
} else {
// feature gate is disabled
return false, nil
}
}当您查看checkAccessModes函数中的v1.12代码时,它将卷accessModes放入 map 并在该映射中搜索PVC accessModes,如果在该映射中找不到PVC accessMode,则返回false,这将导致不兼容的accessMode错误。
那么为什么我们在1.9版中没有得到这个错误呢?因为它在checkVolumeModeMisMatches函数中有不同的控件。它检查一个默认为假的alpha特性,名为BlockVolume. 。因为它是假的,它不会碰到
if isMisMatch {
return fmt.Errorf("VolumeMode[%v] of volume[%s] is incompatible with VolumeMode[%v] of claim[%v]", volume.Spec.VolumeMode, volume.Name, claim.Spec.VolumeMode, claim.Name)
}代码块。
您可以使用以下方法检查主节点上的BlockVolume功能:
ps aux | grep apiserver | grep feature-gates我希望这能澄清你的问题。特别是v1.12中的checkAccessModes函数,目前也在主支路中进行PVC控制。
https://stackoverflow.com/questions/44173653
复制相似问题