Kubernetes ReadWriteOnce Multi-Attach 部署死锁 reload/restart
Kubernetes ReadWriteOnce Multi-Attach deadlock on deployment reload/restart
考虑下面的 PersistentVolumeClaim,以及使用它的 Deployment。
PVC为ReadWriteOnce,一次只能被一个节点挂载。由于我的部署只有一个副本,我认为这应该没问题。但是,在 restarts/reloads 之后,两个 Pods 将在切换期间共存。
如果 Kubernetes 决定在与原始 pod 相同的节点上启动后继 pod,它们都将能够访问该卷并且切换顺利进行。但是 - 如果它决定在它似乎更喜欢的新节点上启动它,我的部署就会陷入僵局:
Multi-Attach error for volume "pvc-c474dfa2-9531-4168-8195-6d0a08f5df34" Volume is already used by pod(s) test-cache-5bb9b5d568-d9pmd
后继 pod 无法启动,因为卷挂载在另一个节点上,而原来的 pod/node 当然,在 pod 停止服务之前不会释放卷。直到继任者就位。
我在这里错过了什么?
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: vol-test
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: do-block-storage
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-cache
spec:
selector:
matchLabels:
app: test-cache-deployment
replicas: 1
template:
metadata:
labels:
app: test-cache-deployment
spec:
containers:
- name: test-cache
image: myrepo/test-cache:1.0-SNAPSHOT
volumeMounts:
- mountPath: "/test"
name: vol-mount
ports:
- containerPort: 8080
imagePullPolicy: Always
volumes:
- name: vol-mount
persistentVolumeClaim:
claimName: vol-name
imagePullSecrets:
- name: regcred
如果您使用 ReadWriteOnce
,这是预期的行为。如果您查看手册,您会遇到以下信息:
- ReadWriteOnce – the volume can be mounted as read-write by a single node
Kubernetes 文档有 table 显示哪些 PV 支持 ReadWriteMany
(即同时在多个节点上进行写入访问,例如 NFS)
如果你仍然坚持使用 ReadWriteOnce
你可以使用 NodeAffinity
并确保 2 个副本将被调度到同一个节点,但这被认为是不好的做法,因为它错过了 Kubernetes 的全部要点.请注意,如果特定节点出现故障,您的所有副本都将出现故障。
您在评论中提到的理想状态可以通过 pod affinity
实现:
Pod affinity and pod anti-affinity allow you to specify rules about
how pods should be placed relative to other pods. The rules are
defined using custom labels on nodes and label selectors specified in
pods. Pod affinity/anti-affinity allows a pod to specify an affinity
(or anti-affinity) towards a group of pods it can be placed with. The
node does not have control over the placement.
从 Kubernetes 文档中查看 this example 关于 pods affinity。
我找到了解决方法:
虽然远非理想,但在我的特定情况下这是一个可以接受的折衷方案。
ReadWriteOnce 卷显然不能很好地配合 Kubernetes 默认升级策略:"Rolling"(即使在单副本部署的情况下)。相反,如果我使用 "Recreate" 升级策略,Kubernetes 将在启动后继者之前销毁原始 pod,从而在再次安装之前分离该卷。
...
spec:
selector:
matchLabels:
app: test-cache-deployment
replicas: 1
strategy:
type: Recreate
...
这个解决方案显然有一个主要缺点:部署将在关闭和成功启动之间脱机 - 这可能需要几秒钟到永恒。
考虑下面的 PersistentVolumeClaim,以及使用它的 Deployment。
PVC为ReadWriteOnce,一次只能被一个节点挂载。由于我的部署只有一个副本,我认为这应该没问题。但是,在 restarts/reloads 之后,两个 Pods 将在切换期间共存。
如果 Kubernetes 决定在与原始 pod 相同的节点上启动后继 pod,它们都将能够访问该卷并且切换顺利进行。但是 - 如果它决定在它似乎更喜欢的新节点上启动它,我的部署就会陷入僵局:
Multi-Attach error for volume "pvc-c474dfa2-9531-4168-8195-6d0a08f5df34" Volume is already used by pod(s) test-cache-5bb9b5d568-d9pmd
后继 pod 无法启动,因为卷挂载在另一个节点上,而原来的 pod/node 当然,在 pod 停止服务之前不会释放卷。直到继任者就位。
我在这里错过了什么?
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: vol-test
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: do-block-storage
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-cache
spec:
selector:
matchLabels:
app: test-cache-deployment
replicas: 1
template:
metadata:
labels:
app: test-cache-deployment
spec:
containers:
- name: test-cache
image: myrepo/test-cache:1.0-SNAPSHOT
volumeMounts:
- mountPath: "/test"
name: vol-mount
ports:
- containerPort: 8080
imagePullPolicy: Always
volumes:
- name: vol-mount
persistentVolumeClaim:
claimName: vol-name
imagePullSecrets:
- name: regcred
如果您使用 ReadWriteOnce
,这是预期的行为。如果您查看手册,您会遇到以下信息:
- ReadWriteOnce – the volume can be mounted as read-write by a single node
Kubernetes 文档有 table 显示哪些 PV 支持 ReadWriteMany
(即同时在多个节点上进行写入访问,例如 NFS)
如果你仍然坚持使用 ReadWriteOnce
你可以使用 NodeAffinity
并确保 2 个副本将被调度到同一个节点,但这被认为是不好的做法,因为它错过了 Kubernetes 的全部要点.请注意,如果特定节点出现故障,您的所有副本都将出现故障。
您在评论中提到的理想状态可以通过 pod affinity
实现:
Pod affinity and pod anti-affinity allow you to specify rules about how pods should be placed relative to other pods. The rules are defined using custom labels on nodes and label selectors specified in pods. Pod affinity/anti-affinity allows a pod to specify an affinity (or anti-affinity) towards a group of pods it can be placed with. The node does not have control over the placement.
从 Kubernetes 文档中查看 this example 关于 pods affinity。
我找到了解决方法:
虽然远非理想,但在我的特定情况下这是一个可以接受的折衷方案。
ReadWriteOnce 卷显然不能很好地配合 Kubernetes 默认升级策略:"Rolling"(即使在单副本部署的情况下)。相反,如果我使用 "Recreate" 升级策略,Kubernetes 将在启动后继者之前销毁原始 pod,从而在再次安装之前分离该卷。
...
spec:
selector:
matchLabels:
app: test-cache-deployment
replicas: 1
strategy:
type: Recreate
...
这个解决方案显然有一个主要缺点:部署将在关闭和成功启动之间脱机 - 这可能需要几秒钟到永恒。