Как выполнить обновление helm при развертывании с помощью pvc и 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 {Major: 1, Minor: 17, GitVersion: v1.17.3, GitCommit: 06ad960bfd03b39c8310aaf92d1e7c12ce618213, GitTreeState: clean, BuildDate: 2020-02-11T18: 14: 22Z: go1.6.13, GoVersion , Компилятор: gc, Платформа: linux / amd64} Версия сервера: version.Info {Major: 1, Minor: 14+, GitVersion: v1.14.9-eks-f459c0, GitCommit: f459c0672169dd35e77af56c24556530a05e9ab1, GitTreeDate: clean -18T04: 24: 17Z, GoVersion: go1.12.12, компилятор: gc, платформа: linux / amd64}

Облачный провайдер / платформа (AKS, GKE, Minikube и т. Д.): EKS

Кто-нибудь знает, является ли это ошибкой или я как-то неправильно использую helm / kubernetes?

Спасибо


person Tom Greenwood    schedule 23.06.2020    source источник


Ответы (1)


Когда вы обновляете развертывание, оно проходит через пару шагов:

  1. Существующие модули со старой спецификацией модулей все еще работают.
  2. Контроллер развертывания запускает новый модуль с новой спецификацией модуля.
  3. Он ожидает, пока этот модуль не достигнет статуса «Работает».
  4. Это завершает старый Pod.
  5. Если имеется несколько реплик, повторяйте, пока не будут заменены все модули.

Важной деталью здесь является то, что существует (намеренно) состояние, в котором работают как старые, так и новые модули.

В показанном вами примере вы монтируете PersistentVolumeClaim с режимом доступа ReadWriteOnce. Это не очень хорошо работает с развертываниями. Пока старый модуль работает, ему принадлежит крепление PVC, которое не позволяет запускать новый модуль, что не позволяет разворачиванию разворачиваться. (На самом деле это не относится к Helm и не связано с наличием initContainer или нет.)

Здесь есть несколько вариантов:

  • Не храните данные на локальном томе. Это лучший вариант, хотя он предполагает изменение архитектуры вашего приложения. Хранить данные в отдельном контейнере базы данных, если это данные реляционного типа (например, предпочитать контейнер PostgreSQL SQLite в томе); или, если у вас есть доступ к сетевому хранилищу, например Amazon S3, храните вещи там. Это полностью устраняет эту проблему и позволяет запускать столько реплик, сколько вам нужно.

  • Используйте том ReadWriteMany. Постоянный том имеет режим доступа. Если вы можете объявить том как ReadWriteMany, то его можно будет подключить к нескольким модулям, и этот сценарий будет работать. Однако многие из наиболее распространенных типов томов не поддерживают этот режим доступа (особенно AWSElasticBlockStore и HostPath только ReadWriteOne).

  • Установите для стратегии развертывания значение Recreate. Вы можете настроить способ управления обновлениями при развертывании. Если вы измените стратегию Recreate

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

    то сначала будут удалены старые модули. Это приведет к прерыванию обновлений с нулевым временем простоя, но позволит продолжить этот конкретный случай.

person David Maze    schedule 23.06.2020
comment
Спасибо, Дэвид. К сожалению, удаленная база данных не будет работать для меня, так как она будет слишком медленной (мне нужно ~ 2k запросов в секунду, поэтому я использую leveldb локально), и я использую AWSElasticBlockStore, поэтому я застрял на ReadWriteOnce. Хотя ваш третий вариант звучит интересно. Не могли бы вы объяснить технические различия между этим и StatefulSet? Спасибо - person Tom Greenwood; 24.06.2020
comment
StatefulSet создаст PersistentVolumeClaim для каждой реплики, поэтому, если у вас есть разумная схема сегментирования и вы можете маршрутизировать запросы между репликами, это поможет вам масштабироваться выше одной реплики. StatefulSet также имеет предсказуемое имя для отдельных модулей. Если для вас это не имеет значения, развертывание будет немного более нормальным. - person David Maze; 24.06.2020