Pull to refresh
0
Иннотех
We help the businesses with digital transformation

Отличия DeploymentConfig от Deployment и примеры использования

Reading time7 min
Views12K

Разницу между объектами DeploymentConfig и Deployment в OpenShift для коллег я объяснял с помощью упрощения:

«Да, короче, деплойментконфиг — это та же штука, что и деплоймент, только поделка от Редхата».

Да-да, мне было лень вдаваться в подробности. Но теперь я хочу попробовать раскрыть более подробно, а заодно поделиться информацией с другими. Сухой оригинал можно найти тут (по версии 4.8, на которой и буду основывать текст статьи).

Для примеров я буду использовать простое приложение на Python и Dockerfile.

Дополнительные объекты ImageStream и BuildConfig

DeploymentConfig — это объект, чуть усовершенствованный по сравнению с Deployment. Он использует триггеры и дополнительные объекты, такие как ImageStream и BuildConfig.

ImageStream — это объект, который хранит в себе sha-хеш образов во внутреннем реджистри OpenShift и позволяет задать произвольный тег, независимо от того, что определено в реджистри. Стоит понимать, что это ещё один уровень абстракций Kubernetes, а самих образов в ImageStream нет. Теги ссылаются либо на другой ImageStream, либо на Dockerimage. Помимо этого, с его помощью можно закешировать образ во внутреннем реджистри и не тянуть каждый раз снаружи.

Создадим такой объект:

apiVersion: image.openshift.io/v1
kind: ImageStream
metadata:
  name: deploymentconfig-demo
  namespace: test-project

BuildConfig — это объект, который, по сути, является сценарием сборки образа. У него может быть много источников исходного кода (git, dockerfile и другие), стратегия сборки (Docker, S2I и другие). И назначение сборки — Dockerimage или ImageStreamTag.

Пример ниже для стратегии Docker:

apiVersion: build.openshift.io/v1
kind: BuildConfig
metadata:
  name: deploymentconfig-demo
  namespace: test-project
spec:
  source:
    git:
      ref: main
      uri: 'https://github.com/kruchkov-alexandr/deploymentconfig-demo.git'
    type: Git
  strategy:
    type: Docker
    dockerStrategy:
      pullSecret:
        name: mysecret
  triggers:
    - type: ConfigChange
  output:
    to:
      kind: ImageStreamTag
      name: 'deploymentconfig-demo:latest'

Как примерно это работает:

  • триггером для запуска build является изменение конфигурации BuildConfig;

  • после создания этого объекта BuildConfig мы увидим, что он запустил объект build, в котором и происходит сборка;

  • build подключается к git-репозиторию, выполняется клонирование из ветки main;

  • по стратегии Docker читается содержимое файла Dockerfile (дефолтный путь в корне репозитория, но можно указать и другой путь);

  • для скачивания образа из директивы FROM используется логин и пароль из заранее созданного секрета с именем mysecret (в примере просто мой логин и пароль от гитхаба);

  • полученный образ пушится во внутренний репозиторий кластера OpenShift;

  • после сборки проставляется тег ImageStreamTag в контейнере ImageStream.

Есть масса триггеров и хуков, о них можно почитать тут. Можно хоть по коммиту в битбакете или гитхабе триггерить билд в OpenShift.

Далее для демонстрации триггера мы создадим новый объект DeploymentConfig:

apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
  name: deploymentconfig-demo
  namespace: test-project
spec:
  selector:
    app: deploymentconfig-demo
  replicas: 1
  template:
    metadata:
      labels:
        app: deploymentconfig-demo
    spec:
      containers:
        - name: deploymentconfig-demo
          env:
            - name: APP_COLOR
              value : blue
          image: image-registry.openshift-image-registry.svc:5000/test-project/deploymentconfig-demo:latest
          ports:
            - containerPort: 8080
  triggers:
  - type: ConfigChange 
  - imageChangeParams:
      automatic: true
      containerNames:
      - deploymentconfig-demo
      from:
        kind: ImageStreamTag
        name: deploymentconfig-demo:latest
    type: ImageChange 

Тут мы видим новый блок с триггерами, в котором происходит проверка на ImageStreamTag.

Как это работает в связке, если не брать в расчёт service + route: 

  • в OpenShift создаём объекты ImageStream, BuildConfig и DeploymentConfig;

  • после создания DeplymentConfig автоматически будет создан объект ReplicationController, который создаст нужное количество экземпляров POD, в нашем случае 1 экземпляр;

  • разработчик получил готовый и работающий сервис в OpenShif;

  • далее разработчик отправляет новый коммит в git-репозитории;

  • репозиторий битбакета/гитхаба запускает вебхук (я его не рассматривал в статье), запуская Build от BuildConfig, или разработчик вручную запускает Build от BuildConfig в OpenShift (как в моём примере);

  • Build клонирует git-репозиторий от ветки main, берёт Dockerfile и запускает сборку, подставляя логин и пароль от заранее созданного секрета mysecret для образа из FROM, пушит собранный образ в репозиторий кластера и добавляет/обновляет тег ImageStreamtag в ImageStream;

  • при изменении тега в ImageStream происходит триггер запуска DeploymentConfig;

  • создаётся новый deployer POD с суффиксом -deploy, который контролирует процесс развёртывания;

  • создаётся ещё один ReplicationController, который создаёт новый экземпляр POD с нашим приложением;

  • после успешного старта контейнера внутри нового POD’а deployer POD завершает работу и переходит в состояние Completed;

  • предыдущий ReplicationController гасит предыдущий POD;

  • разработчик снова получил готовый и работающий сервис в OpenShift с пересобранным образом.

Я бы назвал это некой заменой инструмента CI/CD, упрощающей жизнь разработчику в публикации приложения. То есть разработчику не обязательно настраивать CI/CD процессы и утилиты, привлекать отдельного инженера девопса. Он может быстро опубликовать приложение в OpenShift с минимальными ресурсами и затраченным временем. Настроил git, включил хуки, задеплоил DeploymentConfig, коммитнул в репозиторий, приложение развернулось в OpenShift.

Надо также понимать, что если в вашем неймспейсе кластера есть дефолтные значения реквестов/лимитов ресурсов для POD’ов (объект LimitRange) и это значение, например, 100m для CPU limits, то для deployer POD необходимо 100m CPU. То есть если вы одновременно запустили редеплой 10 DeploymentConfig, то будет поднято 10 deployer POD, которые суммарно возьмут из квоты (объект ResourceQuota) 1000m CPU и будут их держать ещё в течение до 5 секунд после перехода в состояние Completed. В условиях ограничения ресурсов могут возникнуть сложности в одновременном деплое из-за нехватки ресурсов.

Стоит также упомянуть про небольшой баг особенность, которая идёт от версии к версии. Все деплойер POD’ы переходят в состояние Completed и не подчищаются за собой. 

Обходное решение: 

  1. Можно использовать revisionHistoryLimit:1, и тогда будет по 1 Completed деплойер POD’у на каждый из DeploymentConfig.

  2. Либо можно поставить «костыль» в скрипты/скедулер, нечто типа:

oc delete pod --field-selector=status.phase==Succeeded

Иначе у вас картина в кластере будет выглядеть следующим образом:


Применение DeploymentConfig не обязывает вас использовать ImageStream и BuildConfig.

Контроллеры ReplicaSet и ReplicationController

Вторая разница — это использование различных контроллеров:

  • у Deployment — ReplicaSet;

  • у DeploymentConfig — ReplicationController.

Replication Controller и RepliicaSet — это объекты API Kubernetes, которые следят, чтобы указанное количество экземпляров подов было запущено в неймспейсе (проекте) в любое время. Если один или несколько POD’ов завершаются с ошибкой, то контроллер создаст и запустит новый экземпляр, чтобы количество подов всегда соответствовало желаемому.

ReplicaSet является усовершенствованной версией ReplicationController и поддерживает множественный селектор.

Пример различия контроллеров ниже. Обратите внимание на spec.selector.

Для ReplicationController:

apiVersion: v1
kind: ReplicationController
metadata:
  name: example
  namespace: test-project
spec:
  replicas: 2
  selector:
    app: hello-openshift
  template:
    metadata:
      name: hello-openshift
      labels:
        app: hello-openshift
    spec:
      containers:
        - name: hello-openshift
          image: openshift/hello-openshift
          ports:
            - containerPort: 8080

Для ReplicaSet:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: example
  namespace: test-project
spec:
  replicas: 2
  selector:
    matchExpressions:
      - {key: app, operator: In, values: [hello-openshift]}
  template:
    metadata:
      name: hello-openshift
      labels:
        app: hello-openshift
    spec:
      containers:
        - name: hello-openshift
          image: openshift/hello-openshift
          ports:
            - containerPort: 8080

Напрямую создавать объекты ReplicaSet или ReplicationController не нужно. Необходимо использовать создание высокоуровневого объекта Deployment или DeploymentConfig соответственно. Говоря простым языком, нужно создавать объект DeploymentConfig, который автоматически создаст объект ReplicationController, который, в свою очередь, создаст необходимое количество экземпляров POD’ов и будет следить за их количеством.

Автооткат в случае неудачи деплоя

У DeploymentConfig есть возможность автоматического отката в случае неудачного деплоя. Deployer POD сам контролирует процесс деплоя и в случае неудачи автоматически удалит новую версию, откатив на успешную последнюю.

Поддержка кастомных стратегий развёртывания

DeploymentConfig поддерживает кастомные стратегии развёртывания, кроме стандартных Recreate и дефолтной RollingUpdate

Например, OpenShift позволяет определить отдельный контейнер, который отвечает за весь процесс сборки или деплоя. 

Пример:

strategy:
  type: Custom
  customParams:
    image: docker.io/imagestrategy:latest
    command: [ "command", "arg1" ]

Дополнительные примеры можно посмотреть тут.

Поддержка prehook и posthook

DeploymentConfig поддерживает pre-hook и post-hook для стратегии развёртывания.

Пример, как это можно использовать для стратегии Rolling:

...
spec:
...
  strategy:
    type: Rolling
    rollingParams:
      updatePeriodSeconds: 1 
      intervalSeconds: 1 
      timeoutSeconds: 120 
      maxSurge: "20%" 
      maxUnavailable: "10%" 
      pre: {} 
      post: {}
...

Как это работает:

  • запускается pre-hook;

  • количество экземпляров POD’а скалируется вверх для нового ReplicationController исходя из maxSurge;

  • количество экземпляров POD’а скалируется вниз для предыдущего ReplicationController исходя из maxUnavailable;

  • повторяется масштабирование во время деплоя до тех пор, пока новый ReplicationController не наберёт нужного количества экземпляров POD’а, а старый ReplicationController не станет равным 0;

  • запускается post-hook.

Заключение

Надеюсь, ничего важного не упустил и информация была полезной. Я хоть немного раскрыл разницу между этими двумя объектами в кластере OpenShift. В зависимости от процесса разработки вы можете использовать то, что подходит больше всего.

Tags:
Hubs:
+17
Comments13

Articles

Information

Website
inno.tech
Registered
Founded
Employees
5,001–10,000 employees
Representative
Дмитрий