更新使用 ReadWriteOnce 卷的部署将在安装时失败
Updating a deployment that uses a ReadWriteOnce volume will fail on mount
我的部署使用了几个卷,全部定义为 ReadWriteOnce
。
将部署应用到干净的集群时,pod 创建成功。
但是,如果我更新我的部署(即更新容器映像),当为我的部署创建新的 pod 时,它总是会在卷装载上失败:
/Mugen$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-app-556c8d646b-4s2kg 5/5 Running 1 2d
my-app-6dbbd99cc4-h442r 0/5 ContainerCreating 0 39m
/Mugen$ kubectl describe pod my-app-6dbbd99cc4-h442r
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 9m default-scheduler Successfully assigned my-app-6dbbd99cc4-h442r to gke-my-test-default-pool-671c9db5-k71l
Warning FailedAttachVolume 9m attachdetach-controller Multi-Attach error for volume "pvc-b57e8a7f-1ca9-11e9-ae03-42010a8400a8" Volume is already used by pod(s) my-app-556c8d646b-4s2kg
Normal SuccessfulMountVolume 9m kubelet, gke-my-test-default-pool-671c9db5-k71l MountVolume.SetUp succeeded for volume "default-token-ksrbf"
Normal SuccessfulAttachVolume 9m attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-2cc1955a-1cb2-11e9-ae03-42010a8400a8"
Normal SuccessfulAttachVolume 9m attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-2c8dae3e-1cb2-11e9-ae03-42010a8400a8"
Normal SuccessfulMountVolume 9m kubelet, gke-my-test-default-pool-671c9db5-k71l MountVolume.SetUp succeeded for volume "pvc-2cc1955a-1cb2-11e9-ae03-42010a8400a8"
Normal SuccessfulMountVolume 9m kubelet, gke-my-test-default-pool-671c9db5-k71l MountVolume.SetUp succeeded for volume "pvc-2c8dae3e-1cb2-11e9-ae03-42010a8400a8"
Warning FailedMount 52s (x4 over 7m) kubelet, gke-my-test-default-pool-671c9db5-k71l Unable to mount volumes for pod "my-app-6dbbd99cc4-h442r_default(affe75e0-1edd-11e9-bb45-42010a840094)": timeout expired waiting for volumes to attach or mount for pod "default"/"my-app-6dbbd99cc4-h442r". list of unmounted volumes=[...]. list of unattached volumes=[...]
那么,将更改应用于此类部署的最佳策略是什么?为了使用相同的持久卷,是否必须有一些服务中断? (我不想创建新卷 - 数据应该保留)
由于 ReadWriteOnce 访问模式,这似乎是一个错误。请记住,当您更新部署时,会创建新的 pods,然后旧的会被杀死。所以,也许新的 pod 尝试安装一个已经安装的卷,这就是您收到该消息的原因。
您是否尝试过使用允许多个 readers/writers 的卷?您可以在 Kubernetes Volumes documentation.
中查看当前卷列表
由于访问模式,您将需要容忍此处出现中断。这将在创建新卷之前删除现有的 Pods(卸载卷)。
“重新创建”的部署策略 - .spec.strategy.type
- 将有助于实现这一目标:https://github.com/ContainerSolutions/k8s-deployment-strategies/blob/master/recreate/README.md
我以一个更好的解决方案结束,其中我所有的客户 pods 只是内容的读者,并且我有一个独立的 CI 过程来编写内容,我执行以下操作:
- 来自 CI:将内容写入 Google Cloud Storage 存储桶:
gs://my-storage
,然后重新启动所有前端 pods
- 在部署定义上,我将整个存储桶同步(下载)到 pod 易失性存储,并从具有最佳性能的文件系统提供服务。
如何实现:
在前端 docker 图像上,我添加了来自 https://github.com/GoogleCloudPlatform/cloud-sdk-docker/blob/master/debian_slim/Dockerfile 的 gcloud 安装块:
ARG CLOUD_SDK_VERSION=249.0.0
ENV CLOUD_SDK_VERSION=$CLOUD_SDK_VERSION
ARG INSTALL_COMPONENTS
ENV PATH "$PATH:/opt/google-cloud-sdk/bin/"
RUN apt-get update -qqy && apt-get install -qqy \
curl \
gcc \
python-dev \
python-setuptools \
apt-transport-https \
lsb-release \
openssh-client \
git \
gnupg \
&& easy_install -U pip && \
pip install -U crcmod && \
export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
echo "deb https://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" > /etc/apt/sources.list.d/google-cloud-sdk.list && \
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
apt-get update && apt-get install -y google-cloud-sdk=${CLOUD_SDK_VERSION}-0 $INSTALL_COMPONENTS && \
gcloud config set core/disable_usage_reporting true && \
gcloud config set component_manager/disable_update_check true && \
gcloud config set metrics/environment github_docker_image && \
gcloud --version
VOLUME ["/root/.config"]
并且在 pod 部署中 frontend.yaml
我添加了以下 lifecycle
事件:
...
spec:
...
containers:
...
lifecycle:
postStart:
exec:
command: ["gsutil", "-m", "rsync", "-r", "gs://my-storage", "/usr/share/nginx/html"]
对于 "refresh" 前端 pods 当存储桶内容更新时,我只是 运行 我的 CI 中的以下内容:
kubectl set env deployment/frontend K8S_FORCE=
日期 +%s``
我的部署使用了几个卷,全部定义为 ReadWriteOnce
。
将部署应用到干净的集群时,pod 创建成功。
但是,如果我更新我的部署(即更新容器映像),当为我的部署创建新的 pod 时,它总是会在卷装载上失败:
/Mugen$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-app-556c8d646b-4s2kg 5/5 Running 1 2d
my-app-6dbbd99cc4-h442r 0/5 ContainerCreating 0 39m
/Mugen$ kubectl describe pod my-app-6dbbd99cc4-h442r
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 9m default-scheduler Successfully assigned my-app-6dbbd99cc4-h442r to gke-my-test-default-pool-671c9db5-k71l
Warning FailedAttachVolume 9m attachdetach-controller Multi-Attach error for volume "pvc-b57e8a7f-1ca9-11e9-ae03-42010a8400a8" Volume is already used by pod(s) my-app-556c8d646b-4s2kg
Normal SuccessfulMountVolume 9m kubelet, gke-my-test-default-pool-671c9db5-k71l MountVolume.SetUp succeeded for volume "default-token-ksrbf"
Normal SuccessfulAttachVolume 9m attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-2cc1955a-1cb2-11e9-ae03-42010a8400a8"
Normal SuccessfulAttachVolume 9m attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-2c8dae3e-1cb2-11e9-ae03-42010a8400a8"
Normal SuccessfulMountVolume 9m kubelet, gke-my-test-default-pool-671c9db5-k71l MountVolume.SetUp succeeded for volume "pvc-2cc1955a-1cb2-11e9-ae03-42010a8400a8"
Normal SuccessfulMountVolume 9m kubelet, gke-my-test-default-pool-671c9db5-k71l MountVolume.SetUp succeeded for volume "pvc-2c8dae3e-1cb2-11e9-ae03-42010a8400a8"
Warning FailedMount 52s (x4 over 7m) kubelet, gke-my-test-default-pool-671c9db5-k71l Unable to mount volumes for pod "my-app-6dbbd99cc4-h442r_default(affe75e0-1edd-11e9-bb45-42010a840094)": timeout expired waiting for volumes to attach or mount for pod "default"/"my-app-6dbbd99cc4-h442r". list of unmounted volumes=[...]. list of unattached volumes=[...]
那么,将更改应用于此类部署的最佳策略是什么?为了使用相同的持久卷,是否必须有一些服务中断? (我不想创建新卷 - 数据应该保留)
由于 ReadWriteOnce 访问模式,这似乎是一个错误。请记住,当您更新部署时,会创建新的 pods,然后旧的会被杀死。所以,也许新的 pod 尝试安装一个已经安装的卷,这就是您收到该消息的原因。
您是否尝试过使用允许多个 readers/writers 的卷?您可以在 Kubernetes Volumes documentation.
中查看当前卷列表由于访问模式,您将需要容忍此处出现中断。这将在创建新卷之前删除现有的 Pods(卸载卷)。
“重新创建”的部署策略 - .spec.strategy.type
- 将有助于实现这一目标:https://github.com/ContainerSolutions/k8s-deployment-strategies/blob/master/recreate/README.md
我以一个更好的解决方案结束,其中我所有的客户 pods 只是内容的读者,并且我有一个独立的 CI 过程来编写内容,我执行以下操作:
- 来自 CI:将内容写入 Google Cloud Storage 存储桶:
gs://my-storage
,然后重新启动所有前端 pods - 在部署定义上,我将整个存储桶同步(下载)到 pod 易失性存储,并从具有最佳性能的文件系统提供服务。
如何实现: 在前端 docker 图像上,我添加了来自 https://github.com/GoogleCloudPlatform/cloud-sdk-docker/blob/master/debian_slim/Dockerfile 的 gcloud 安装块:
ARG CLOUD_SDK_VERSION=249.0.0
ENV CLOUD_SDK_VERSION=$CLOUD_SDK_VERSION
ARG INSTALL_COMPONENTS
ENV PATH "$PATH:/opt/google-cloud-sdk/bin/"
RUN apt-get update -qqy && apt-get install -qqy \
curl \
gcc \
python-dev \
python-setuptools \
apt-transport-https \
lsb-release \
openssh-client \
git \
gnupg \
&& easy_install -U pip && \
pip install -U crcmod && \
export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
echo "deb https://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" > /etc/apt/sources.list.d/google-cloud-sdk.list && \
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
apt-get update && apt-get install -y google-cloud-sdk=${CLOUD_SDK_VERSION}-0 $INSTALL_COMPONENTS && \
gcloud config set core/disable_usage_reporting true && \
gcloud config set component_manager/disable_update_check true && \
gcloud config set metrics/environment github_docker_image && \
gcloud --version
VOLUME ["/root/.config"]
并且在 pod 部署中 frontend.yaml
我添加了以下 lifecycle
事件:
...
spec:
...
containers:
...
lifecycle:
postStart:
exec:
command: ["gsutil", "-m", "rsync", "-r", "gs://my-storage", "/usr/share/nginx/html"]
对于 "refresh" 前端 pods 当存储桶内容更新时,我只是 运行 我的 CI 中的以下内容:
kubectl set env deployment/frontend K8S_FORCE=
日期 +%s``