【问题标题】:How to perform helm update on deployment with pvc and initContainer?如何使用 pvc 和 initContainer 对部署执行 helm update?
【发布时间】:2020-10-13 15:26:37
【问题描述】:

我对 helm 和 kubernetes 还很陌生,所以我不确定这是一个错误还是我做错了什么。在发布之前,我到处寻找答案,但找不到任何可以回答我问题的东西。

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

可能相关但可能不相关:我需要为一系列 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 }}

helm version 的输出:version.BuildInfo{Version:"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:"clean", BuildDate:"2020-03 -18T04:24:17Z", GoVersion:"go1.12.12", 编译器:"gc", 平台:"linux/amd64"}

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

有谁知道这是一个错误还是我以某种方式误用了 helm/kubernetes?

谢谢

【问题讨论】:

    标签: kubernetes-helm kubernetes-pvc kubernetes-deployment


    【解决方案1】:

    当您更新部署时,它会经过几个步骤:

    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 卷。持久卷具有access mode。如果您可以将卷声明为ReadWriteMany,那么多个 pod 可以挂载它,这种情况将起作用。但是,许多更常见的卷类型不支持这种访问模式(AWSElasticBlockStore 和 HostPath 显然只有 ReadWriteOne)。

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

        apiVersion: apps/v1
        kind: Deployment
        spec:
          strategy:
            type: Recreate
      

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

    【讨论】:

    • 谢谢大卫。不幸的是,远程数据库对我不起作用,因为它太慢了(我需要每秒约 2k 次查询,所以我在本地使用 leveldb)而且我在 AWSElasticBlockStore 上,所以我被困在 ReadWriteOnce 上。不过,您的第三个选项听起来很有趣。你能解释一下它和 StatefulSet 之间的技术差异吗?谢谢
    • StatefulSet 将为每个副本创建一个 PersistentVolumeClaim,因此如果您有一个合理的分片方案并且可以在副本之间路由请求,这将有助于您在一个副本之上进行扩展。 StatefulSet 还为各个 pod 提供了可预测的名称。如果这些对您来说并不重要,那么 Deployment 会更“正常”一些。
    猜你喜欢
    • 2021-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-21
    • 2020-12-20
    相关资源
    最近更新 更多