如何使用 pvc 和 initContainer 对部署执行 helm update?
How to perform helm update on deployment with pvc and initContainer?
我对 helm 和 kubernetes 还很陌生,所以我不确定这是一个错误还是我做错了什么。然而,在发布之前,我到处寻找答案,但找不到任何能回答我问题的东西。
我有一个使用持久卷和初始化容器的部署。我传递给它的值让 helm 知道初始容器的图像是否发生了变化,或者主应用程序容器是否发生了变化。
可能相关但可能不相关:我需要为一系列网络资源(我称之为收集器)部署一个部署。我不知道这最后一部分是否相关,但如果相关,我可能不会在这里。
当我运行
helm upgrade --install my-release helm_chart/ --values values.yaml --set init_image_tag=$INIT_IMAGE_TAG --set image_tag=$IMAGE_TAG
第一次一切正常。但是,当我第二次运行时,跟INIT_IMAGE_TAG一样,但是IMAGE_TAG变了
- a) 它尝试重新初始化 pod
- b) 它无法重新初始化 pod,因为它无法安装卷
预期行为:
- a) 不要重新初始化 pod,因为初始化容器没有改变
- b) 安装卷
我的 values.yaml 只包含一个名为 collectors
的列表
我的模板是:
{{ $env := .Release.Namespace }}
{{ $image_tag := .Values.image_tag }}
{{ $init_image_tag := .Values.init_image_tag }}
{{- range $colname := .Values.collectors }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ $colname }}-claim
spec:
accessModes:
- ReadWriteOnce
storageClassName: ebs-sc
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $colname }}-ingest
labels:
app: {{ $colname }}-ingest
spec:
replicas: 1
selector:
matchLabels:
app: {{ $colname }}-ingest
template:
metadata:
labels:
app: {{ $colname }}-ingest
spec:
fsGroup: 1000
containers:
- name: {{ $colname }}-main
image: xxxxxxx.dkr.ecr.eu-west-1.amazonaws.com/main_image:{{ $image_tag }}
env:
- name: COLLECTOR
value: {{ $colname }}
volumeMounts:
- name: storage
mountPath: /home/my/dir
initContainers:
- name: {{ $colname }}-init
image: xxxxxxx.dkr.ecr.eu-west-1.amazonaws.com/init_image:{{ $init_image_tag }}
volumeMounts:
- name: storage
mountPath: /home/my/dir
env:
- name: COLLECTOR
value: {{ $colname }}
volumes:
- name: storage
persistentVolumeClaim:
claimName: {{ $colname }}-claim
---
{{ end }}
helm version
的输出:version.BuildInfo{版本:“v3.2.0-rc.1”,GitCommit:“7bffac813db894e06d17bac91d14ea819b5c2310”,GitTreeState:“clean”,GoVersion:“go1.13.10” }
kubectl version
的输出:客户端版本:version.Info{主要:“1”,次要:“17”,GitVersion:“v1.17.3”,GitCommit:“06ad960bfd03b39c8310aaf92d1e7c12ce618213”,GitTreeState: “干净”,构建日期:“2020-02-11T18:14:22Z”,GoVersion:“go1.13.6”,编译器:“gc”,平台:“linux/amd64”}
服务器版本:version.Info{主要:“1”,次要:“14+”,GitVersion:“v1.14.9-eks-f459c0”,GitCommit:“f459c0672169dd35e77af56c24556530a05e9ab1”,GitTreeState:“clean”,BuildDate:“2020 -03-18T04:24:17Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}
云Provider/Platform(AKS、GKE、Minikube 等):EKS
有谁知道这是一个错误还是我误用了 helm/kubernetes?
谢谢
当您更新 Deployment 时,它会经历几个步骤:
- 具有旧 pod 规格的现有 Pod 仍然是 运行ning。
- Deployment 控制器使用新的 pod 规范启动一个新的 pod。
- 它等待 Pod 达到“运行”状态。
- 它终止了旧的 Pod。
- 如果有多个副本,重复直到每个 Pod 都被替换。
这里的重要细节是(有意地)存在一种状态,其中新旧 pods 都是 运行ning。
在您展示的示例中,您使用 ReadWriteOnce 访问模式装载 PersistentVolumeClaim。这在部署中效果不佳。当旧的 Pod 处于 运行ning 时,它拥有 PVC 挂载,这将阻止新的 Pod 启动,这将阻止 Deployment 的进行。 (这并不是真正特定于 Helm,也与是否拥有 initContainer 无关。)
这里有几个选项:
不要将数据存储在本地卷中。这是最好的方法,尽管它涉及到重新设计您的应用程序。将数据存储在单独的数据库容器中,如果它是关系型数据(例如,更喜欢 PostgreSQL 容器而不是卷中的 SQLite);或者,如果您可以访问 Amazon S3 等网络存储,请将其保存在那里。这完全避免了这个问题,并且可以让你 运行 你需要多少副本。
使用 ReadWriteMany
卷。 永久卷具有 access mode。如果您可以将卷声明为 ReadWriteMany
,那么多个 pods 可以挂载它,并且这种情况会起作用。但是,许多更常见的卷类型不支持这种访问模式(AWSElasticBlockStore 和 HostPath 特别是只有 ReadWriteOne
)。
将 Deployment 策略设置为 Recreate
。 您可以配置 Deployment 如何管理更新。如果你change to a Recreate
strategy
apiVersion: apps/v1
kind: Deployment
spec:
strategy:
type: Recreate
那么旧的Pods会先被删除。这将打破零停机升级,但它将允许这个特定案例继续进行。
我对 helm 和 kubernetes 还很陌生,所以我不确定这是一个错误还是我做错了什么。然而,在发布之前,我到处寻找答案,但找不到任何能回答我问题的东西。
我有一个使用持久卷和初始化容器的部署。我传递给它的值让 helm 知道初始容器的图像是否发生了变化,或者主应用程序容器是否发生了变化。
可能相关但可能不相关:我需要为一系列网络资源(我称之为收集器)部署一个部署。我不知道这最后一部分是否相关,但如果相关,我可能不会在这里。
当我运行
helm upgrade --install my-release helm_chart/ --values values.yaml --set init_image_tag=$INIT_IMAGE_TAG --set image_tag=$IMAGE_TAG
第一次一切正常。但是,当我第二次运行时,跟INIT_IMAGE_TAG一样,但是IMAGE_TAG变了
- a) 它尝试重新初始化 pod
- b) 它无法重新初始化 pod,因为它无法安装卷
预期行为:
- a) 不要重新初始化 pod,因为初始化容器没有改变
- b) 安装卷
我的 values.yaml 只包含一个名为 collectors
我的模板是:
{{ $env := .Release.Namespace }}
{{ $image_tag := .Values.image_tag }}
{{ $init_image_tag := .Values.init_image_tag }}
{{- range $colname := .Values.collectors }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ $colname }}-claim
spec:
accessModes:
- ReadWriteOnce
storageClassName: ebs-sc
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $colname }}-ingest
labels:
app: {{ $colname }}-ingest
spec:
replicas: 1
selector:
matchLabels:
app: {{ $colname }}-ingest
template:
metadata:
labels:
app: {{ $colname }}-ingest
spec:
fsGroup: 1000
containers:
- name: {{ $colname }}-main
image: xxxxxxx.dkr.ecr.eu-west-1.amazonaws.com/main_image:{{ $image_tag }}
env:
- name: COLLECTOR
value: {{ $colname }}
volumeMounts:
- name: storage
mountPath: /home/my/dir
initContainers:
- name: {{ $colname }}-init
image: xxxxxxx.dkr.ecr.eu-west-1.amazonaws.com/init_image:{{ $init_image_tag }}
volumeMounts:
- name: storage
mountPath: /home/my/dir
env:
- name: COLLECTOR
value: {{ $colname }}
volumes:
- name: storage
persistentVolumeClaim:
claimName: {{ $colname }}-claim
---
{{ end }}
helm version
的输出:version.BuildInfo{版本:“v3.2.0-rc.1”,GitCommit:“7bffac813db894e06d17bac91d14ea819b5c2310”,GitTreeState:“clean”,GoVersion:“go1.13.10” }
kubectl version
的输出:客户端版本:version.Info{主要:“1”,次要:“17”,GitVersion:“v1.17.3”,GitCommit:“06ad960bfd03b39c8310aaf92d1e7c12ce618213”,GitTreeState: “干净”,构建日期:“2020-02-11T18:14:22Z”,GoVersion:“go1.13.6”,编译器:“gc”,平台:“linux/amd64”}
服务器版本:version.Info{主要:“1”,次要:“14+”,GitVersion:“v1.14.9-eks-f459c0”,GitCommit:“f459c0672169dd35e77af56c24556530a05e9ab1”,GitTreeState:“clean”,BuildDate:“2020 -03-18T04:24:17Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}
云Provider/Platform(AKS、GKE、Minikube 等):EKS
有谁知道这是一个错误还是我误用了 helm/kubernetes?
谢谢
当您更新 Deployment 时,它会经历几个步骤:
- 具有旧 pod 规格的现有 Pod 仍然是 运行ning。
- Deployment 控制器使用新的 pod 规范启动一个新的 pod。
- 它等待 Pod 达到“运行”状态。
- 它终止了旧的 Pod。
- 如果有多个副本,重复直到每个 Pod 都被替换。
这里的重要细节是(有意地)存在一种状态,其中新旧 pods 都是 运行ning。
在您展示的示例中,您使用 ReadWriteOnce 访问模式装载 PersistentVolumeClaim。这在部署中效果不佳。当旧的 Pod 处于 运行ning 时,它拥有 PVC 挂载,这将阻止新的 Pod 启动,这将阻止 Deployment 的进行。 (这并不是真正特定于 Helm,也与是否拥有 initContainer 无关。)
这里有几个选项:
不要将数据存储在本地卷中。这是最好的方法,尽管它涉及到重新设计您的应用程序。将数据存储在单独的数据库容器中,如果它是关系型数据(例如,更喜欢 PostgreSQL 容器而不是卷中的 SQLite);或者,如果您可以访问 Amazon S3 等网络存储,请将其保存在那里。这完全避免了这个问题,并且可以让你 运行 你需要多少副本。
使用
ReadWriteMany
卷。 永久卷具有 access mode。如果您可以将卷声明为ReadWriteMany
,那么多个 pods 可以挂载它,并且这种情况会起作用。但是,许多更常见的卷类型不支持这种访问模式(AWSElasticBlockStore 和 HostPath 特别是只有ReadWriteOne
)。将 Deployment 策略设置为
Recreate
。 您可以配置 Deployment 如何管理更新。如果你change to aRecreate
strategyapiVersion: apps/v1 kind: Deployment spec: strategy: type: Recreate
那么旧的Pods会先被删除。这将打破零停机升级,但它将允许这个特定案例继续进行。