如何使用 pvc 和 initContainer 对部署执行 helm 更新?

Tom*_*ood 6 kubernetes-helm kubernetes-pvc kubernetes-deployment

我对 helm 和 kubernetes 相当陌生,所以我不确定这是一个错误还是我做错了什么。然而,在发帖之前,我到处寻找答案,但找不到任何可以回答我的问题的内容。

我有一个使用持久卷和初始化容器的部署。我传递它的值是为了让 helm 知道 init 容器的映像是否已更改,或者主应用程序容器是否已更改。

可能相关,但可能不相关:我需要为一系列 Web 源(我称之为收集器)部署一个部署。我不知道最后一部分是否相关,但如果我这样做,我可能就不会在这里了。

当我跑步时

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,因为 init 容器没有改变
  • 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 }}
Run Code Online (Sandbox Code Playgroud)

输出helm version:version.BuildInfo{版本:“v3.2.0-rc.1”,GitCommit:“7bffac813db894e06d17bac91d14ea819b5c2310”,GitTreeState:“clean”,GoVersion:“go1.13.10”}

输出kubectl version:客户端版本:version.Info{Major:“1”,Minor:“17”,GitVersion:“v1.17.3”,GitCommit:“06ad960bfd03b39c8310aaf92d1e7c12ce618213”,GitTreeState:“clean”,BuildDate:“2020-02-11T18 :14:22Z", GoVersion:"go1.13.6", 编译器:"gc", 平台:"linux/amd64"} 服务器版本: version.Info{Major:"1", Minor:"14+", GitVersion: “v1.14.9-eks-f459c0”,GitCommit:“f459c0672169dd35e77af56c24556530a05e9ab1”,GitTreeState:“干净”,BuildDate:“2020-03-18T04:24:17Z”,GoVersion:“go1.12.12”,编译器:“gc”,平台:“linux/amd64”}

云提供商/平台(AKS、GKE、Minikube 等):EKS

有谁知道这是否是一个错误,或者我是否以某种方式错误地使用了 helm/kubernetes?

谢谢

Dav*_*aze 12

当您更新 Deployment 时,它会经历几个步骤:

  1. 具有旧 Pod 规格的现有 Pod 仍在运行。
  2. 部署控制器使用新的 Pod 规范启动一个新的 Pod。
  3. 它等待该 Pod 达到“正在运行”状态。
  4. 它终止一个旧的 Pod。
  5. 如果有多个副本,则重复此操作,直到每个 Pod 都被替换。

这里重要的细节是(故意)存在一种新旧 Pod 都在运行的状态。

在您显示的示例中,您安装了具有 ReadWriteOnce 访问模式的 PersistentVolumeClaim。这对于部署来说并不能很好地工作。当旧 Pod 运行时,它拥有 PVC 挂载,这将阻止新 Pod 启动,从而阻止 Deployment 进行。(这并不是 Helm 特有的,也与是否有 initContainer 无关。)

这里有几个选项:

  • 不要将数据存储在本地卷中。 这是最好的路径,尽管它涉及重新架构您的应用程序。如果数据是关系型数据,则将数据存储在单独的数据库容器中(例如,更喜欢使用 PostgreSQL 容器而不是卷中的 SQLite);或者,如果您可以访问 Amazon S3 等网络存储,请将数据保留在那里。这完全避免了这个问题,并且可以让您根据需要运行任意数量的副本。

  • 使用ReadWriteMany音量。 持久卷具有访问模式。如果您可以声明该卷,ReadWriteMany那么多个 Pod 就可以挂载它,并且此方案将起作用。不过,许多更常见的卷类型不支持这种访问模式(尤其是 AWSElasticBlockStore 和 HostPath ReadWriteOnce)。

  • 将部署策略设置为Recreate 您可以配置部署管理更新的方式。如果你改变Recreate策略

      apiVersion: apps/v1
      kind: Deployment
      spec:
        strategy:
          type: Recreate
    
    Run Code Online (Sandbox Code Playgroud)

    那么旧的 Pod 将首先被删除。这将打破零停机升级,但它将允许这种特定情况继续进行。