В данной статье я хочу рассказать как деплоить приложения в разные среды. В этом примере, мы будем деплоить в: «Test» и «Production». Разумеется, вы можете добавить любые среды.

Для деплоя приложений я использую HELM. Он позволяет гибко управлять конфигурациями. В чем вы сможете убедится ниже. Предполагается, что у вас уже есть настроенный runner с helm-ом и вы знаете и умеете работать с HELM-ом.

Пример файла: .gitlab-ci.yml

.base_deploy: &base_deploy
  stage: deploy
  script:
  - PROJECT_NAME="${CI_PROJECT_NAME}-${CI_ENVIRONMENT_SLUG}"
  - helm --namespace ${CI_ENVIRONMENT_SLUG} upgrade -i ${PROJECT_NAME} helm --set "global.env=${CI_ENVIRONMENT_SLUG}";

stages:
  - deploy

Deploy to Test:
  <<: *base_deploy
  environment:
    name: test

Deploy to Production:
  <<: *base_deploy
  environment:
    name: production
  when: manual

Здесь стоит обратить внимание на то, что в зависимости от среды мы передаем переменную: «test» или «production».

Имя проекта мы тоже формируем с учетом имени переменной, для того, чтобы helm понимал, что это разные проекты (helm ls).

Далее, мы передаем эту переменную (среду) в HELM как: «global.env».

Для выше указанного примера helm должен находиться в одноименной папке в вашем репозиторие.

Теперь рассмотрим пример, как использовать переменную среды в Chart-ах HELM.

Создадим такой values.yaml:

replicas:
  test: 1
  production: 3

domain:
  test: test.domain.com
  production: production.domain.com

resources:
  requests:
    cpu:
      _default: 50m
      production: 50m
    memory:
      _default: 256Mi
      production: 10Mi
  limits:
    memory:
      _default: 1Gi
      production: 1Gi
    cpu:
      _default: 1000m

Здесь видно, что для разных сред мы указываем разные настройки.
Для удобства можно указывать и default-ные настройки.

Ещё один пример, для ingress.yaml:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ .Chart.Name }}
spec:
  rules:
  - host: {{ pluck .Values.global.env .Values.domain | first | default .Values.domain._default }}
    http:
      paths:
      - path: /
        backend:
          serviceName: {{ .Chart.Name }}
          servicePort: 80

Вы всегда можете проверить как собирается ваш Chart, командой:

helm template ./helm --set "global.env=test"
helm template ./helm --set "global.env=production"

Так же вы можете деплоить ваш код на разные ноды в зависимости от среды.

Пример:

{{ if eq .Values.global.env "test" }}
      nodeSelector:
        nodetype: testnodes
{{ else if eq .Values.global.env "production" }}
      nodeSelector:
        nodetype: productionnodes
{{ else }}

Всем спасибо. Деплойте правильно.

Комментарии (8)


  1. RPG18
    06.09.2018 17:21

    Если так правильно, то как деплоить неправильно? Например я разгуливаю через --kube-context, т.к. тестовый и продовый k8s, это разные кластера с разными сертификатами и токенами.


    1. danuk Автор
      06.09.2018 18:30

      Слово «правильно» конечно же здесь носит шуточный характер)
      Мне было бы очень интересно посмотреть/почитать о вашей инсталляции.


  1. danuk Автор
    06.09.2018 18:29

    -


  1. Faight
    06.09.2018 22:53
    +1

    у helm есть опция -i — это позволяет установить релиз, если его нет.

    Предпочитаю иметь свои vars.yml под разные среды, а не плодить кучу if.

    Так же использую у себя конструкцию вида:
    - helm upgrade -i -f chart/vars.yml chart_name
    - kubectl rollout status deploy || helm rollback chart_name 0 && exit 1


    Немного упрощенно, там есть еще несколько шагов, но смысл в ролл бэке. Можно у хэлма использовать опцию wait, но она мне не нравится, так как не наглядна и иногда нужно делать цепочку из rollout status.


    1. danuk Автор
      07.09.2018 10:53

      Спасибо, крутое замечание. Поизучаю.


  1. Avvero
    07.09.2018 16:19

    А Вы можете рассказать, как вы делаете деплой на test, если нужна миграция базы? На каком этапе это осуществляется?


    1. Bezk
      07.09.2018 18:23

      Осуществляется джобом с restartPolicy: Never, например так


  1. Bezk
    07.09.2018 18:12

    Мы столкнулись с проблемой хостов Ingress'a.
    У него есть большой минус, он не поддерживает wildcards. Мы хотели сделать динамические entrypoint's, а ля username.domain.com, но из-за упрямства разработчиков Ingress так не сделать.
    Т.е. если вы хотите сделать приложение которое реализует схему *.domain.com – так сделать не получится.