如何使用 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变了

预期行为:

我的 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 时,它会经历几个步骤:

  1. 具有旧 pod 规格的现有 Pod 仍然是 运行ning。
  2. Deployment 控制器使用新的 pod 规范启动一个新的 pod。
  3. 它等待 Pod 达到“运行”状态。
  4. 它终止了旧的 Pod。
  5. 如果有多个副本,重复直到每个 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会先被删除。这将打破零停机升级,但它将允许这个特定案例继续进行。