Архив метки: Devops

Как работать с Terraform

В данной инструкции мы попробуем разобраться с тем, как работать с Terraform. Мы рассмотрим его установку и базовую настройку, немного синтаксиса и примеры работы с облачным провайдером Яндекс.Облако. Инструкция рассчитана на работу с Linux (Deb и RPM).




Регистрация на хостинге




Для работы с хостинг-провайдером нам заранее понадобятся авторизационные данные и идентификаторы ресурсов. Их мы будем прописывать в сценариях terraform.




Нам нужно зарегистрироваться на сервисе Yandex.Cloud (в нашем примере, мы будем работать, именно, с ним). После этого, нам нужно получить:




1. OAuth-токен. Используется в процедуре аутентификации для получения IAM-токена и нужен нам для прохождения авторизации при подключении terraform. Выдается на 1 год. Получить можно, отправив запрос со страницы документации Яндекс.




2. Идентификатор облака. После регистрации на хостинге мы заходим в контроль-панель. Мы должны увидеть наши ресурсы, в частности, облако:







А справа от него будет идентификатор.




3. Идентификатор каталога. На той же странице контроль панели, ниже облака мы увидим каталог:







Также, справа мы можем скопировать его идентификатор.




После получения нужных данных просто сохраняем их в отдельный файл. После установки terraform они нам понадобятся.




Установка Terraform




Terraform является клиентом и необходимо выполнить установку на компьютер, с которого планируется управление инфраструктурой. Актуальная инструкция по развертыванию представлена на официальном сайте. На текущий момент клиент может быть установлен из репозитория, с использованием бинарника, собран из исходников, а также с помощью choco на Windows или brew на Mac OS. В нашем примере будут рассмотрены установка на Ubuntu и Rocky Linux из репозитория, а также загрузка бинарника.




Ubuntu (Debian)




Обновляем список пакетов:




apt update




Установим дополнительные пакеты:




apt install gnupg software-properties-common curl




* где:




  • gnupg — программа для шифровки и дешифровки цифровых подписей. Нужна для работы с репозиториями.
  • software-properties-common — утилита для работы с репозиториями.
  • curl — отправка GET, POST и других запросов.




Установим в систему ключ для репозитория:




curl -fsSL https://apt.releases.hashicorp.com/gpg | apt-key add -




Добавляем репозиторий:




apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"




Обновляем список пакетов, чтобы загрузить списки с нового репозитория:




apt update




Можно устанавливать terraform:




apt install terraform




Rocky Linux




Устанавливаем утилиту для работы с репозиториями:




yum install yum-utils




Добавляем репозиторий:




yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo




Устанавливаем terraform:




yum install terraform




Скачиваем бинарник




Суть данного метода — скачать бинарный файл и перенести его в каталог /usr/local/bin.




Таким же образом устанавливаем terraform на Windows.




Для начала нам понадобятся утилиты unzip и wget. Устанавливаются они по-разному, в зависимости от дистрибутива Linux.




а) Ubuntu / Debian:




apt install unzip wget




б) Rocky Linux:




yum install unzip wget




Переходим к загрузке бинарного файла. Посмотреть ссылку на него можно на странице официального сайта:







Воспользуемся ссылкой, чтобы скачать архив:




wget https://releases.hashicorp.com/terraform/1.1.7/terraform_1.1.7_linux_amd64.zip




* в нашем примере будет загружена версия 1.1.7.




Распакуем архив командой:




unzip terraform_*_linux_amd64.zip




Перенесем распакованный бинарник в каталог:




mv terraform /usr/local/bin/




После установки




Убедимся, что terraform работает. Для этого вводим команду:




terraform -version




Мы должны получить что-то на подобие:




Terraform v1.1.7
on linux_amd64




Также рекомендуется установить автоподстановки:




terraform -install-autocomplete




Это позволит нам завершать команды terraform с помощью клавиши Tab.




Теперь создадим каталог, в котором будем работать со сценариями для тераформа:




mkdir -p /opt/terraform/yandex




* в моем примере я решил работать в каталоге /opt/terraform/yandex.




Перейдем в созданный каталог:




cd /opt/terraform/yandex




Мы готовы приступить непосредственно к работе с terraform.




Установка провайдера




Чтобы terraform мог корректно взаимодействовать с инфраструктурой провайдера, необходимо использовать набор инструкций, которые будет использовать наша утилита. В терминологии terraform это называется провайдер.




На сайте Hashicorp можно найти все поддерживаемые провайдеры. Как говорилось выше, мы будем работать с Yandex.Cloud. Рассмотрим подробнее установку провайдера для работы с ним.




В нашем рабочем каталоге создаем первый файл:




vi main.tf




terraform {
  required_version = "= 1.1.7"

  required_providers {
    yandex = {
      source  = "yandex-cloud/yandex"
      version = "= 0.73"
    }
  }
}

provider "yandex" {
  token     = "<OAuth>"
  cloud_id  = "<идентификатор облака>"
  folder_id = "<идентификатор каталога>"
  zone      = "<зона доступности по умолчанию>"
}




* где:




  • terraform required_version — версия клиента terraform, для которого должен запускаться сценарий. Параметр не обязательный, но является правилом хорошего тона и может помочь избежать некоторых ошибок, которые возникнут из-за несовместимости при работе в команде.
  • required_providers version — версия провайдера. Мы можем указать, как в данном примере, необходимость использовать конкретную версию, а можно с помощью знака >= или <= указать не выше или не ниже определенной.
  • token — OAuth-токен для прохождения авторизации. Был нами получен после регистрации на хостинге (описание выше).
  • cloud_id — идентификатор для облака, в котором будут создаваться ресурсы. Также получен был нами заранее.
  • folder_id — идентификатор каталога, который также был получен в начале инструкции.
  • zone — ресурсы, которые хранятся на мощностях Яндекс разделены по зонам. Каждая зона — это определенная географическая локация центра обработки данных. Список доступных зон можно посмотреть на странице Зоны доступности.




Теперь выполним команду:




terraform init




Система загрузит нужные файлы и установит провайдер:




Initializing the backend...

Initializing provider plugins...
- Finding latest version of yandex-cloud/yandex...
- Installing yandex-cloud/yandex v0.73.0...
- Installed yandex-cloud/yandex v0.73.0 (self-signed, key ID E40F590B50BB8E40)
...
Terraform has been successfully initialized!
...




Мы готовы двигаться дальше.




Работа с ресурсами




Мы рассмотрим небольшие примеры по созданию, редактированию и удалению ресурсов. В большей степени мы будем работать с виртуальными машинами. Большую часть информации по написанию сценариев можно найти на официальном сайте хостинга или самого terraform.




Создание ресурсов




В нашем рабочем каталоге создадим новый файл:




vi infrastructure1.tf




Напишем минимально необходимый сценарий для создания виртуальной машины: 




data "yandex_compute_image" "ubuntu_image" {
  family = "ubuntu-2004-lts"
}

resource "yandex_compute_instance" "vm-test1" {
  name = "test1"

  resources {
    cores  = 2
    memory = 2
  }

  boot_disk {
    initialize_params {
      image_id = data.yandex_compute_image.ubuntu_image.id
    }
  }

  network_interface {
    subnet_id = yandex_vpc_subnet.subnet_terraform.id
    nat       = true
  }

  metadata = {
    user-data = "${file("./meta.yml")}"
  }

}

resource "yandex_vpc_network" "network_terraform" {
  name = "net_terraform"
}

resource "yandex_vpc_subnet" "subnet_terraform" {
  name           = "sub_terraform"
  zone           = "ru-central1-a"
  network_id     = yandex_vpc_network.network_terraform.id
  v4_cidr_blocks = ["192.168.15.0/24"]
}




* где:







** в нашем примере будет создана виртуальная машина с названием test1, 2 CPU, 2 Gb RAM в сети 192.168.15.0/24 на базе Ubuntu 20.04 LTS.
*** обратите внимание, что мы указали идентификатор той подсети для виртуальной машины, которую создали также с помощью нашего сценария terraform.




Создаем файл с метеданными:




meta.yml




#cloud-config
users:
  - name: dmosk
    groups: sudo
    shell: /bin/bash
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    ssh-authorized-keys:
      - ssh-rsa AAAAB3Nza..................UXFDCb/ujrK4KbpCyvk=




* в данном файле мы опишем пользователя, под которым мы сможем подключиться к нашему серверу по SSH:







Попробуем испытать наш сценарий. Сначала вводим:




terraform plan




Если мы не ошиблись, утилита покажет, что terraform сделает в нашей облачной инфраструктуре. Очень важно внимательно просматривать изменения.




После того, как мы убедимся в корректности действий, применяем настройку:




terraform apply




Мы еще раз увидим, что будет выполнено, а также получим запрос на подтверждение действий — вводим yes:




Enter a value: yes




Terraform выполнит необходимые действия. Мы можем перейти в контроль-панель хостинга и убедиться, что наша виртуальная машина создалась.




Редактирование данных




Если необходимо внести изменения в нашу инфраструктуру, то достаточно просто открыть наш файл со сценарием:




vi infrastructure1.tf




Внести нужные изменения, например:




  ...
  resources {
    cores  = 4
    memory = 4
  }
  ...




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




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




Error: Changing the `secondary_disk`, `resources`, `platform_id`, `network_acceleration_type` or `network_interfaces` on an instance requires stopping it. To acknowledge this action, please set allow_stopping_for_update = true in your config file.




Мы должны явно разрешить для конкретных ресурсов выполнение остановки их работы для внесения изменений. В нашем файле для конкретного ресурса добавим:




...
resource "yandex_compute_instance" "vm-test1" {
  name = "test1"
  allow_stopping_for_update = true

...




* для нашей машины test1 мы указали опцию allow_stopping_for_update, которая говорит о том, что работу ресурса можно останавливать для внесения изменений.




Строим план:




terraform plan




Мы должны увидеть, что будет изменено в нашей инфраструктуре. В моем случае:




      ~ resources {
          ~ cores         = 2 -> 4
          ~ memory        = 2 -> 4
            # (2 unchanged attributes hidden)
        }




Применяем настройки:




terraform apply




Проверяем через контроль-панель, что изменения вступили в силу.




Удаление ресурсов




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




1. Например, можно указать count = 0:




resource "yandex_compute_instance" "vm-test1" {
  count = 0
  ...




2. Можно закомментировать или удалить строки ресурса из файла tf.




3. Если мы хотим оставить содержимое файлов нетронутым, но при этом удалить все ресурсы, вводим:




terraform destroy




Утилита пройдет по всем файлам tf в директории, найдет ресурсы и выполнит их удаление.




Файл state




Очень важно уметь работать с файлом состояния terraform, а также понять, что это. Данный файл появляется после первого применения сценария в том же рабочем каталоге:




ls




terraform.tfstate




В нем содержатся все изменения, которые происходили с применением terraform. Без него последний не будет знать, что уже было сделано — на практике это приведет к дублированию инфраструктуры, то есть, если мы создали сервер, потеряли файл состояния и снова запустили terraform, он создаст еще один сервер. Для больших инфраструктур с большой историей все намного критичнее.




И так, файл состояния важен с точки зрения понимания инфраструктуры самим terraform. Также у него есть еще одна функция — блокировка параллельных выполнений. Это важно для работы в командах, где одновременные действия могут привести к неожиданным последствиям. Чтобы этого не произошло, terraform создает блокировку, которая запрещает выполнения, если уже идет процесс применения плана.




Из вышесказанного делаем выводы:







Рассмотрим возможность хранения данного файла состояния на облачном хранилище Яндекс.




Сначала мы должны создать хранилище. Это можно сделать через веб-интерфейс, но мы это сделаем в terraform.




Но сначала мы сделаем файл:




vi variables.tf




variable "yandex_folder_id" {
  type        = string
  default     = "<идентификатор каталога>"
}




* где yandex_folder_id — название для нашей переменной; <идентификатор каталога> — тот идентификатор, который мы указали в файле main под аргументом folder_id.




Теперь откроем файл main:




vi main.tf




И отредактируем значение folder_id на:




  ...
  folder_id = var.yandex_folder_id
  ...




* в данном примере мы теперь задаем folder_id не явно, а через созданную переменную.




Теперь создадим файл:




vi yandex_storage_bucket.tf




resource "yandex_iam_service_account" "sa" {
  folder_id = var.yandex_folder_id
  name      = "sa-dmosk"
}

resource "yandex_resourcemanager_folder_iam_member" "sa-editor" {
  folder_id = var.yandex_folder_id
  role      = "storage.editor"
  member    = "serviceAccount:${yandex_iam_service_account.sa.id}"
}

resource "yandex_iam_service_account_static_access_key" "sa-static-key" {
  service_account_id = yandex_iam_service_account.sa.id
  description        = "Static access key for object storage"
}

resource "yandex_storage_bucket" "state" {
  bucket     = "tf-state-bucket-dmosk"
  access_key = yandex_iam_service_account_static_access_key.sa-static-key.access_key
  secret_key = yandex_iam_service_account_static_access_key.sa-static-key.secret_key
}




* рассмотрим файл немного подробнее:







Создаем еще один файл:




vi outputs.tf




output "access_key" {
  value = yandex_iam_service_account_static_access_key.sa-static-key.access_key
  sensitive = true
}
output "secret_key" {
  value = yandex_iam_service_account_static_access_key.sa-static-key.secret_key
  sensitive = true
}




* это делается для получения значений аргументов access_key и secret_key и сохранения данных значений в файле состояния. Если access_key можно посмотреть в панели Яндекса, то secret_key мы увидеть не можем.




Строим план и применяем настройки:




terraform plan




terraform apply




Заходим в контроль-панель Яндекса и видим, что у нас создалось хранилище. Его мы будем использовать для хранения файлов состояний terraform.




Открываем наш файл main:




vi main.tf




Добавляем:




terraform {
  ...

  backend "s3" {
    endpoint   = "storage.yandexcloud.net"
    bucket     = "tf-state-bucket-dmosk"
    region     = "ru-central1-a"
    key        = "terraform/infrastructure1/terraform.tfstate"
    access_key = "<access_key>"
    secret_key = "<secret_key >"

    skip_region_validation      = true
    skip_credentials_validation = true
  }
}




* в раздел terraform мы добавили инструкцию для хранения файла state. В нашем примере он будет размещен на бакете tf-state-bucket-dmosk по пути terraform/infrastructure1/terraform.tfstate.
** особое внимание обратите на access_key и secret_key. В разделе terraform мы не можем указать переменные, как это делали при создании хранилища. Сами значения можно найти в нашем локальном файле state.




Используем команду:




terraform init




Система снова инициализирует состояние текущего каталога и создаст файл state на удаленном хранилище. Чтобы убедиться, можно зайти в контроль панель, найти наше хранилище, а в нем — файл terraform/infrastructure1/terraform.tfstate.




Реальный пример




Мы развернем 2 веб-сервера и поместим их за Network load balancer.




Для этого мы создадим новый рабочий каталог:




mkdir -p /opt/terraform/yandex-network-load balancer




И перейдем в него:




cd /opt/terraform/yandex-network-load balancer




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




Мы создадим 5 файлов:




  1. main.tf — в нем мы опишем инструкции для init, а именно требования к версии клиента terraform, провайдера.
  2. web-servers.tf — сценарий для создания 2-х веб-серверов.
  3. network-load-balancer.tf — создание Network Load Balancer.
  4. variables.tf — описание переменных.
  5. outputs.tf — вывод значений после отработки terraform на экран и в файл состояния.




1. Создаем файл main.tf:




vi main.tf




terraform {
  required_version = "= 1.1.7"

  required_providers {
    yandex = {
      source  = "yandex-cloud/yandex"
      version = "= 0.73"
    }
  }
}
provider "yandex" {
  token     = "<OAuth>"
  cloud_id  = "<идентификатор облака>"
  folder_id = "<идентификатор каталога>"
  zone      = "<зона доступности по умолчанию>"
}




* это стандартный вариант файла main.tf, который мы разбирали в начале.




2. web-servers.tf:




vi web-servers.tf




data "yandex_compute_image" "lamp" {
  family = "lamp"
}

data "yandex_compute_image" "lemp" {
  family = "lemp"
}

resource "yandex_compute_instance" "vm-test1" {
  name                      = "vm-test1"
  allow_stopping_for_update = true

  resources {
    cores  = 2
    memory = 2
  }

  boot_disk {
    initialize_params {
      image_id = data.yandex_compute_image.lamp.id
    }
  }

  network_interface {
    subnet_id = yandex_vpc_subnet.subnet_terraform.id
    nat       = true
  }

}

resource "yandex_compute_instance" "vm-test2" {
  name                      = "vm-test2"
  allow_stopping_for_update = true

  resources {
    cores  = 2
    memory = 2
  }

  boot_disk {
    initialize_params {
      image_id = data.yandex_compute_image.lemp.id
    }
  }

  network_interface {
    subnet_id = yandex_vpc_subnet.subnet_terraform.id
    nat       = true
  }

}

resource "yandex_vpc_network" "network_terraform" {
  name = "network_terraform"
}

resource "yandex_vpc_subnet" "subnet_terraform" {
  name           = "subnet_terraform"
  zone           = "ru-central1-a"
  network_id     = yandex_vpc_network.network_terraform.id
  v4_cidr_blocks = ["192.168.15.0/24"]
}




* в данном примере мы создадим 2 виртуальные машины — одну с образом lamp (Apache), вторую на lemp (NGINX).




3. network-load-balancer.tf:




vi network-load-balancer.tf




resource "yandex_lb_network_load_balancer" "lb-dmosk" {
  name = "lb-dmosk"

  listener {
    name = "listener-web-servers"
    port = 80
    external_address_spec {
      ip_version = "ipv4"
    }
  }

  attached_target_group {
    target_group_id = yandex_lb_target_group.web-servers.id

    healthcheck {
      name = "http"
      http_options {
        port = 80
        path = "/"
      }
    }
  }
}

resource "yandex_lb_target_group" "web-servers" {
  name = "web-servers-target-group"

  target {
    subnet_id = yandex_vpc_subnet.subnet_terraform.id
    address   = yandex_compute_instance.vm-test1.network_interface.0.ip_address
  }

  target {
    subnet_id = yandex_vpc_subnet.subnet_terraform.id
    address   = yandex_compute_instance.vm-test2.network_interface.0.ip_address
  }
}




* в данном сценарии мы:







4. variables.tf:




vi variables.tf




variable "yandex_folder_id" {
  type        = string
  default     = "<folder_id>"
}




* создадим переменную с folder_id, в котором мы должны работать. Выше мы уже делали такую переменную.




5. outputs.tf:




vi outputs.tf




output "lb_ip_address" {
  value = yandex_lb_network_load_balancer.lb-dmosk.*
}




* на самом деле, это не обязательно — информацию о созданном балансировщике можно посмотреть в контроль панели, но для примера мы решили это рассмотреть.




Готово. После применения данного сценария мы получим то, что хотели — две виртуальные машины + балансировщик сети, который будет распределять запросы между данными серверами.




Источник: https://www.dmosk.ru/instruktions.php?object=terraform



Шпаргалка по написанию Gitlab Pipelines

В данной инструкции будут рассмотрены небольшие сценарии работы с Gitlab Pipelines. Мы приведем примеры использования наиболее востребованных опций при работе с CI/CD. По мере необходимости, база шаблонов будет пополняться.




Шаблоны




В данном разделе напишем несколько готовых шаблонов, которые можно взять за основы при написании своего сценария.




1. Минимальный сценарий. Для небольших заданий, состоящих из пары заданий:




stages:
  - build

TASK_NAME:
  stage: build
  script:
    - ./build_script.sh




* где:







2. Стандартный цикл при сборке. Обычно, процесс CI/CD включает следующие шаги:







Для написания такого сценария за основу можно взять шаблон:




stages:
  - build
  - test
  - delivery
  - deploy

build-job:
  stage: build
  script:
    - echo "Start build job"
    - build-script.sh

test-job:
  stage: test
  script:
    - echo "Start test job"
    - test-script.sh

delivery-job:
  stage: delivery
  script:
    - echo "Start delivery job"
    - delivery-script.sh

deploy-job:
  stage: deploy
  script:
    - echo "Start deploy job"
    - deploy-script.sh




Задания




В данном разделе мы рассмотрим опции, которые могут применяться при описании задания. Общий синтаксис:




<TASK_NAME>:
  <OPTION1>: ...
  <OPTION2>: ...




Мы перечислим лишь часто встречаемые опции. Полный список можно найти в официальной документации.




Stage







Опция указывает, к какой стадии относится задание. Например:




stages:
  - build
  - test

TASK_NAME:
  ...
  stage: build

TASK_NAME:
  ...
  stage: test




Сами же стадии описываются в общей директиве stages.




Также есть две стадии, которые не требуют предварительного определения в stages:







Например:




stages:
  - build
  - test

getVersion:
  stage: .pre
  script:
    - VERSION=$(cat VERSION_FILE")
    - echo "VERSION=${VERSION}" > variables.env
  artifacts:
    reports:
      dotenv: variables.env




* в данном примере мы до того, как начнем проходить по всем заданиям сборки, определим переменную с версией, прочивав ее из файла, и передадим артефактом в качестве системной переменной VERSION.




Image







Задаем имя образа, если наше задание выполняется в контейнере docker:




TASK_NAME:
  ...
  image: debian:11




Before_script







Данная опция определяет список команд, которые должны выполняться перед опцией script и после получения артефактов.




TASK_NAME:
  ...
  before_script:
    - echo "Run before_script"




Script







Основная часть, где выполняются задания сценария, описана в опции script. Рассмотрим ее подробнее.




1. Описание массива команд. Мы просто перечисляем списком те команды, которые необходимо последовательно выполнить нашему сценарию в конкретной задаче:




TASK_NAME:
  ...
  script:
    - command1
    - command2




2. Длинные команды, разбитые на несколько строк. Нам может потребоваться выполнить команды в виде скрипта (с операторами сравнения, например). В этом случае будет удобна многострочная запись. Ее можно указать разными способами.




Индикатор | :




TASK_NAME:
  ...
  script:
    - |
      command_line1
      command_line2




* для него каждая новая строка является переходом к новой команде или части оператора. По сути, это близко к логике скрипта shell.




Индикатор > :




TASK_NAME:
  ...
  script:
    - >
      command_line1
      command_line1_continue

      command_line2
      command_line2_continue




* данный индикатор интерпретирует новую команду после пустой строки.




After_script







Набор команд, которые запускаются после scripts, даже, при неудачном завершении последнего.




TASK_NAME:
  ...
  script:
    ...
  after_script:
    - command1
    - command2




Artifacts







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




1. Например, так можно указать, какие файлы или каталоги будут артефактами:




TASK_NAME:
  ...
  artifacts:
    paths:
      - ${PKG_NAME}.deb
      - ${PKG_NAME}.rpm
      - *.txt
      - configs/




* в моем примере, в артефакты попадут все файлы, название которых заканчивается на txt, файлы ${PKG_NAME}.deb и ${PKG_NAME}.rpm, а также каталог configs. Где ${PKG_NAME} — переменная (подробнее о переменных ниже).




В других заданиях, которые будут выполняться после можно использовать артефакты, обращаясь к ним по именам, например:




TASK_NAME_2:
  ...
  script:
    - cat *.txt
    - yum -y localinstall ${PKG_NAME}.rpm
    - apt -y install ./${PKG_NAME}.deb




2. Также мы можем передать системные переменные, которые были нами переданы в файл:




TASK_NAME:
  ...
  script:
    - echo -e "VERSION=1.1.1" > variables.env
  ...
  artifacts:
    reports:
      dotenv: variables.env




* в данном примере мы передадим системную переменную VERSION со значением 1.1.1 через файл variables.env.




3. При необходимости, мы можем исключить из списка определенные файлы по названию или маске:




TASK_NAME:
  ...
  artifacts:
    paths:
      ...
    exclude:
      - ./.git/**/*




* в данном примере мы исключаем каталог .git, в котором, как правило, хранятся метаданные репозитория.
** обратите внимание, что в отличие от pathsexclude не берет файлы и каталоги рекурсивно и нужно явно указывать объекты.




Extends







Позволяет вынести часть сценария в отдельный блок и объединить его с заданием. Чтобы это лучше понять, рассмотрим конкретный пример:




.my_extend:
  stage: build
  variables:
    USERNAME: my_user
  script:
    - extend script

TASK_NAME:
  extends: .my_extend
  variables:
    VERSION: 123
    PASSWORD: my_pwd
  script:
    - task script




И так, в нашем задании TASK_NAME мы используем extends. В результате, задание примет такой вид:




TASK_NAME:
  stage: build
  variables:
    VERSION: 123
    PASSWORD: my_pwd
    USERNAME: my_user
  script:
    - task script




Что произошло:







Environment







Позволяет указать системную переменную, которая будет создана для выполнения задания.




TASK_NAME:
  ...
  environment:
    RSYNC_PASSWORD: rpass
    EDITOR: vi




Release







Публикует релиз на портале Gitlab для нашего проекта.




TASK_NAME:
  ...
  release:
    name: 'Release $CI_COMMIT_TAG'
    tag_name: '$CI_COMMIT_TAG'
    description: 'Created using the release-cli'
    assets:
      links:
        - name: "myprogram-${VERSION}"
          url: "https://gitlab.com/master.dmosk/project/-/jobs/${CI_JOB_ID}/artifacts/raw/myprogram-${VERSION}.tar.gz"
  rules:
    - if: $CI_COMMIT_TAG




* обратите внимание, что мы применяем правило if (о нем ниже).




Директивы правил и ограничений




Для управления поведением выполнения задач могут использоваться директивы с правилами и условиями. Подробнее мы их рассмотрим ниже, а в данном разделе просто перечислим их.




Rules







Правила, при соблюдении которых наше задание может быть запущено. Примеры работы с директивой rules приведены ниже.




When





https://docs.gitlab.com/ee/ci/yaml/#when.




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




Needs





https://docs.gitlab.com/ee/ci/yaml/#needs.




Тоже набор правил, требующий определенных условий для запуска задачи. Все директивы условий и правил описаны ниже.




Правила и условия




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




Rules




Регламентирует различные правила, определенные с помощью:







1. Оператор if. Позволяем проверить условие, например, если переменная равна определенному значению:




TASK_NAME:
  ...
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'




* в данном примере коммит должен быть выполнен в бранче по умолчанию.




2. Изменения затронули определенные файлы. Проверка выполняется с помощью опции changes.




В данном примере, файл script.sql:




TASK_NAME:
  ...
  rules:
    - changes:
        - script.sql




3. Несколько условий. Условий для начала выполнения задания может быть несколько. Рассмотрим несколько примеров.




а) При условии, что коммит выполнен в бранче по умолчанию И изменения затронули файл script.sql:




TASK_NAME:
  ...
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
      changes:
        - script.sql




б) При условии, что коммит выполнен в бранче по умолчанию ИЛИ изменения затронули файл script.sql




TASK_NAME:
  ...
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
    - changes:
        - script.sql




4. Проверка на существование файла. Определяется с помощью exists:




TASK_NAME:
  ...
  rules:
    - exists:
        - script.sql




* задание будет выполняться только в случае присутствия файла script.sql.




5. Разрешить сбой задания. Задается с помощью allow_failure:




TASK_NAME:
  ...
  rules:
    - allow_failure: true




* в данном примере наш конвейер продолжит работу, если задание TASK_NAME будет выполнено с ошибкой.




6. Определение переменной в зависимости от условия. Для этого используются вместе if и variables:




TASK_NAME:
  ...
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
      variables:
        DEPLOY_VARIABLE: "production"
    - if: '$CI_COMMIT_BRANCH =~ demo'
      variables:
        DEPLOY_VARIABLE: "demo"




When




Определяет условия запуска задания. Возможные значения:







Разберем примеры.




1. Manual:




TASK_NAME:
  ...
  when: manual




* задание не начнет выполняться, пока мы не нажмем кнопку запуска в GitLab CI/CD.




2. Always:




TASK_NAME:
  ...
  when: always




* задание будет выполняться всегда. Удобно, например, если нужно сформировать отчетный файл, независимо от результатов сборки.




3. On_failure:




TASK_NAME:
  ...
  on_failure: always




* задание будет выполняться при наличии ошибки на ранних этапах. Можно использовать для отправки уведомления.




4. Delayed:




TASK_NAME:
  ...
  when: delayed
  start_in: 30 minutes




* запуск задания будет отложен на 30 минут.




5. Never:




TASK_NAME:
  ...
  when: never




* задание не будет выполняться.




6. Использование вместе с if:




TASK_NAME:
  ...
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
      when: manual




* в данном примере задание будет выполняться, если коммит прошел в основной ветке и если администратор подтвердил запуск.




Needs




Позволяет задавать условия выполнения заданий только при наличии определенного артефакта или выполненного задания. С помощью правил данного типа можно контролировать порядок выполнения задач.




Рассмотрим примеры.




1. Artifacts. Принимает значение true (по умолчанию) и false. Для запуска задания нужно, чтобы на предыдущих этапах были загружены артефакты. Запись:




TASK_NAME:
  ...
  needs:
    - artifacts: false




… позволяет начать выполнение задания без этого.




2. Job. Позволяет начать выполнение задачи только после завершения другого задания:




TASK_NAME:
  ...
  needs:
    - job: createBuild




* в нашем примере задача начнет выполняться не раньше завершения задачи с названием createBuild.




Переменные




В данном разделе будут рассмотрены пользовательские переменные, которые мы можем использовать в сценарии на свое усмотрение, а также некоторые встроенные переменные, которые могут менять процесс работы конвейера.




Пользовательские переменные




Задаются с помощью директивы variables.




Можно определить глобально для всех заданий:




variables:
  PKG_VER: "1.1.1"




Или для конкретного задания:




TASK_NAME:
  ...
  variables:
    PKG_VER: "1.1.1"




Теперь можно использовать нашу переменную в сценарии. Для этого ставим перед ее названием знак доллара, а также стоит заключить его в фигурные скобки, например:




  script:
    - echo ${PKG_VER}




Переменные Gitlab




Данный тип переменных поможет нам управлять процессом сборки. Перечислим данные переменные с описанием их свойств:




ПеременнаяОписаниеПример
LOG_LEVELОпределяет уровень журнала. Варианты: debug, info, warn, error, fatal, и panic. Имеет более низкий приоритет, по сравнению с аргументами командной строки —debug, —log-level.LOG_LEVEL: warning
CI_DEBUG_TRACEВключение или отключение ведения журнала отладки. Принимает значения true или false.CI_DEBUG_TRACE: true
CONCURRENTОграничивает количество заданий, которые могут выполняться одновременно.CONCURRENT: 5
GIT_STRATEGYСпособ загрузки файлов из репозитория. Возможны варианты: clone, fetch, и none (не загружать).GIT_STRATEGY: none




Дополнительные параметры




В данном разделе мы рассмотрим различные опции, которые не вошли в другие разделы.




1. Workflow. Позволяем задать общие правила запуска для всего конвейера. Рассмотрим пример с официального сайта:




workflow:
  rules:
    - if: $CI_COMMIT_TITLE =~ /-draft$/
      when: never
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH




В данном примере конвейер:







2. Значения по умолчанию. Задаются в директиве default. Опции с данными значениями будут использоваться во всех заданиях или могут быть переопределены на уровне конкретного задания.




Пример:




default:
  image: centos:7
  tags:
    - ci-test




* мы определили опцию с именем образа (например, образа docker) и тег (теги могут быть необходимы для запуска некоторых runner).




3. Импорт конфигурации из другого файла yml. Может быть полезным, например, для написания общей части сценария, которую мы захотим применять ко всем pipeline или для разделения громоздкого сценария на составные части. Выполняется с помощью опции include. Имеет различные варианты подгрузки файлов. Рассмотрим их подробнее.




а) подключение локального файла (local):




include:
  - local: .gitlab/ci/build.yml




б) коллекции шаблонов (template):




include:
  - template: Custom/.gitlab-ci.yml




* в данном примере мы подключим к нашему сценарию содержимое файла Custom/.gitlab-ci.yml.




в) внешний файл доступный по HTTP (remote):




include:
  - remote: 'https://gitlab.dmosk.ru/main/build.yml'




г) другой проект:




include:
  - project: 'public-project'
    ref: main
    file: 'build.yml'




4. !reference tags. Позволяет описать сценарий и повторно его использовать для разных стадий и задач нашего CI/CD.




Например:




.apt-cache:
  script:
    - apt update
  after_script:
    - apt clean all

install:
  stage: install
  script:
    - !reference [.apt-cache, script]
    - apt install nginx

update:
  stage: update
  script:
    - !reference [.apt-cache, script]
    - apt upgrade
    - !reference [.apt-cache, after_script]




* давайте разберемся, что происходит в нашем примере.







Источник: https://www.dmosk.ru/miniinstruktions.php?mini=gitlab-pipeline



Prometheus + Grafana + Alertmanager в Docker

В данной инструкции мы рассмотрим пример docker-compose файла для организации системы мониторинга на базе Prometheus. Мы получим:




  • Базу данных Prometheus и интерфейс для выполнения PromQL.
  • Визуализацию с помощью Grafana.
  • Сбор метрик через Node Exporter.
  • Мониторинг HTTP с использованием Blackbox.
  • Отправку уведомлений в Telegram с помощью Alertmanager.




Мы будем работать в среде Linux, хотя полученный файл docker-compose можно применять где угодно. Останавливаться подробно на описании docker-compose мы не будем.




Подготовка системы




Подразумевается, что у нас установлен Docker и docker-compose, в противном случае, можно воспользоваться инструкцией Установка Docker на Linux.




Создаем каталоги, где будем создавать наши файлы:




mkdir -p /opt/prometheus_stack/{prometheus,grafana,alertmanager,blackbox}




Создаем файл:




touch /opt/prometheus_stack/docker-compose.yml




Переходим в каталог prometheus_stack:




cd /opt/prometheus_stack




Дальше будем работать относительно него.




Prometheus + Node Exporter




Открываем файл:




vi docker-compose.yml




version: '3.9'

services:

  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus:/etc/prometheus/
    container_name: prometheus
    hostname: prometheus
    command:
      - --config.file=/etc/prometheus/prometheus.yml
    ports:
      - 9090:9090
    restart: unless-stopped
    environment:
      TZ: "Europe/Moscow"
    networks:
      - default

  node-exporter:
    image: prom/node-exporter
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    container_name: exporter
    hostname: exporter
    command:
      - --path.procfs=/host/proc
      - --path.sysfs=/host/sys
      - --collector.filesystem.ignored-mount-points
      - ^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($$|/)
    ports:
      - 9100:9100
    restart: unless-stopped
    environment:
      TZ: "Europe/Moscow"
    networks:
      - default

networks:
  default:
    ipam:
      driver: default
      config:
        - subnet: 172.28.0.0/16




* в данном примере мы создаем 2 сервиса — prometheus и node-exporter. Также мы отдельно определили подсеть 172.28.0.0/16, в которой будут находиться наши контейнеры docker.




Создаем конфигурационный файл для prometheus:




vi prometheus/prometheus.yml




scrape_configs:
  - job_name: node
    scrape_interval: 5s
    static_configs:
    - targets: ['node-exporter:9100']




* в данном примере мы прописываем наш node-exporter в качестве таргета.




Запускаем контейнеры:




docker-compose up -d




Ждем несколько секунд и можно пробовать подключиться. Открываем браузер и переходим по адресу http://<IP-адрес сервера>:9090 — мы должны увидеть страницу Prometheus:







Переходим по адресу http://<IP-адрес сервера>:9100 — мы должны увидеть страницу Node Exporter:







Мы движемся в правильном направлении. Идем дальше.




Grafana




Добавим к нашему стеку графану.




Открываем файл:




vi docker-compose.yml




Добавляем:




version: '3.9'

services:
  ...
  grafana:
    image: grafana/grafana
    user: root
    depends_on:
      - prometheus
    ports:
      - 3000:3000
    volumes:
      - ./grafana:/var/lib/grafana
      - ./grafana/provisioning/:/etc/grafana/provisioning/
    container_name: grafana
    hostname: grafana
    restart: unless-stopped
    environment:
      TZ: "Europe/Moscow"
    networks:
      - default

...




* по аналогии с другими сервисами, мы добавили сервис для графаны.




Перезапустим контейнеры:




docker-compose up -d




Открываем браузер и переходим по адресу http://<IP-адрес сервера>:3000 — мы должны увидеть стартовую страницу Grafana.




Для авторизации вводим admin / admin. После система потребует ввести новый пароль.




Настроим связку с Prometheus. Кликаем по иконке Configuration — Data Sources:







Переходим к добавлению источника, нажав по Add data source:







Среди списка источников данных находим и выбираем Prometheus, кликнув по Select:







Задаем параметры для подключения к Prometheus:







Сохраняем настройки, кликнув по Save & Test:







Добавим дашборд для мониторинга с node exporter. Для этого уже есть готовый вариант.




Кликаем по изображению плюса и выбираем Import:







Вводим идентификатор дашборда. Для Node Exporter это 1860:







Кликаем Load — Grafana подгрузит дашборд из своего репозитория — выбираем в разделе Prometheus наш источник данных и кликаем по Import:







Мы увидим страницу с настроенными показателями метрик. Можно пользоваться.




Настройка оповещений с AlertManager




В нашем примере мы настроим отправку уведомлений на телеграм бот. Само оповещение будет выполнять AlertManager, который интегрируется с Prometheus.




Для начала подготовим наш бот телеграм. Создадим нового — для этого открываем телеграм и ищем @my_id_bot:







Приложение покажет наш идентификатор. Записываем — он нам потребуется позже.




Теперь создаем бота. Ищем @BotFather:







Переходим в чат с найденным BotFather и запускаем бота:







Создаем бота, последовательно введя команду /newbot и отвечая на запросы мастера:







* в нашем примере мы создаем бота prometheus_alert с именем учетной записи DmoskPrometheusBot.




Переходим в чат с созданным ботом, кликнув по его названию:







Запускаем бота:







С ботом мы закончили. Переходим к docker.




Открываем наш файл docker-compose:




vi docker-compose.yml




И добавляем:




version: '3.9'
  ...

  alertmanager-bot:
    command:
      - --alertmanager.url=http://alertmanager:9093
      - --log.level=info
      - --store=bolt
      - --bolt.path=/data/bot.db
      - --telegram.admin=573454381
      - --telegram.token=5472129845:AAFTQRdujqIHgWHbbVtfYWQQvzvIN98KBqg
    image: metalmatze/alertmanager-bot:0.4.3
    user: root
    ports:
      - 8080:8080
    container_name: alertmanager-bot
    hostname: alertmanager-bot
    environment:
      TZ: "Europe/Moscow"
    restart: unless-stopped
    volumes:
      - ./data:/data
    networks:
      - default

  alertmanager:
    image: prom/alertmanager:v0.21.0
    user: root
    ports:
      - 127.0.0.1:9093:9093
    volumes:
      - ./alertmanager/:/etc/alertmanager/
    container_name: alertmanager
    hostname: alertmanager
    environment:
      TZ: "Europe/Moscow"
    restart: unless-stopped
    command:
      - '--config.file=/etc/alertmanager/config.yml'
      - '--storage.path=/etc/alertmanager/data'
    networks:
      - default

...




* мы добавили два сервиса — alertmanager-bot (телеграм бот для prometheus alertmanager) и alertmanager (система оповещений в prometheus).




Теперь открываем конфигурационный файл для prometheus:




vi prometheus/prometheus.yml




И добавим строки:




...

rule_files:
  - 'alert.rules'

alerting:
  alertmanagers:
  - scheme: http
    static_configs:
    - targets:
      - "alertmanager:9093"




* в данном примере мы указали, что наш сервер мониторинга должен использовать в качестве системы оповещения alertmanager, который доступен по адресу alertmanager:9093. Также мы добавили файл alert.rules с описанием правил оповещения.




Создаем файл с правилами оповещения:




vi prometheus/alert.rules




groups: 
- name: test
  rules:
  - alert: PrometheusTargetMissing
    expr: up == 0
    for: 0m
    labels:
      severity: critical
    annotations:
      summary: "Prometheus target missing (instance {{ $labels.instance }})"
      description: "A Prometheus target has disappeared. An exporter might be crashed. VALUE = {{ $value }}  LABELS: {{ $labels }}"




* в данном примере мы добавили правило, которое будет срабатывать при недоступности узла (node-exporter).




Переходим к конфигурированию alertmanager:




vi alertmanager/config.yml




route:
    receiver: 'alertmanager-bot'

receivers:
- name: 'alertmanager-bot'
  webhook_configs:
  - send_resolved: true
    url: 'http://alertmanager-bot:8080'




* данная конфигурация позволяет отправлять оповещения с помощью webhook на сервис alertmanager-bot:8080 (наш телеграм бот для alertmanager).




Запускаем новые сервисы docker:




docker-compose up -d




Открываем браузер и переходим по адресу http://<IP-адрес сервера>:9090 — на вкладке Alerts мы должны увидеть нашу настройку:







Попробуем проверить работу оповещения. Отключаем наш node exporter:




docker stop exporter




На телеграм должно прийти оповещение:







Отправка уведомлений настроена.




Blackbox exporter




Переходим к настройке мониторинга http сервисов. В нашем примере мы будем проверять работу сайта dmosk.ru.




Открываем наш файл docker-compose:




vi docker-compose.yml




Добавим в него:




version: '3.9'

services:
  ...

  blackbox:
    image: prom/blackbox-exporter
    container_name: blackbox
    hostname: blackbox
    ports:
      - 9115:9115
    restart: unless-stopped
    command:
      - "--config.file=/etc/blackbox/blackbox.yml"
    volumes:
      - ./blackbox:/etc/blackbox
    environment:
      TZ: "Europe/Moscow"
    networks:
      - default

  ...




* сервис blackbox является компонентом Prometheus для мониторинга сетевых сервисов по различным протоколам.




Открываем конфигурационный файл prometheus:




vi prometheus/prometheus.yml




И дописываем:




scrape_configs:
  ...
  - job_name: 'blackbox'
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
        - https://www.dmosk.ru
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: blackbox:9115

...




* подобная конфигурация позволит создать дополнительное задание мониторинга сайта https://www.dmosk.ru.




Создаем конфигурационный файл blackbox:




vi blackbox/blackbox.yml




modules:
  http_2xx:
    prober: http
    timeout: 5s
    http:
      valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
      valid_status_codes: [200]
      method: GET
      no_follow_redirects: true
      fail_if_ssl: false
      fail_if_not_ssl: false
      fail_if_body_matches_regexp:
        - "Could not connect to database"
      fail_if_body_not_matches_regexp:
        - "Download the latest version here"
      fail_if_header_matches: # Verifies that no cookies are set
        - header: Set-Cookie
          allow_missing: true
          regexp: '.*'
      fail_if_header_not_matches:
        - header: Access-Control-Allow-Origin
          regexp: '(*|example.com)'
      tls_config:
        insecure_skip_verify: false
      preferred_ip_protocol: "ip4"
      ip_protocol_fallback: false




* во многом, данный пример взят с официальной страницы на Github.




Теперь откроем конфигурационный файл с описанием правил для предупреждений:




vi prometheus/alert.rules




Добавим:




  ...

  - alert: BlackboxSlowProbe
    expr: avg_over_time(probe_duration_seconds[1m]) > 5
    for: 1m
    labels:
      severity: warning
    annotations:
      summary: Blackbox slow probe (instance {{ $labels.instance }})
      description: "Blackbox probe took more than 1s to completen  VALUE = {{ $value }}n  LABELS = {{ $labels }}"

  - alert: BlackboxProbeHttpFailure
    expr: probe_http_status_code <= 199 OR probe_http_status_code >= 400
    for: 0m
    labels:
      severity: critical
    annotations:
      summary: Blackbox probe HTTP failure (instance {{ $labels.instance }})
      description: "HTTP status code is not 200-399n  VALUE = {{ $value }}n  LABELS = {{ $labels }}"




* в данном примере мы создали два правила:




  • BlackboxSlowProbe — предупреждать, если сайт открывается дольше 5 секунд.
  • BlackboxProbeHttpFailure — реагировать, в случае получения кода ответа с ошибкой работы сайта (более 400).




Запускаем добавленный в докер сервис:




docker-compose up -d




Для визуализации мониторинга с помощью blackbox есть готовый дашборд в графане. Снова открываем страницу импорта:







Вводим идентификатор 7587 и выбираем источник (как делали при добавлении дашборда node exporter).




Источник https://www.dmosk.ru/miniinstruktions.php?mini=prometheus-stack-docker#prometheus



2022-10-02T19:55:44
DevOps

90+ полезных инструментов для Kubernetes: развертывание, управление, мониторинг, безопасность и не только

Осенью 2018 года мы опубликовали список из 25 полезных инструментов Kubernetes. С тех популярность платформы сильно выросла. Экосистема оркестрации контейнеров бурно развивается, можно найти вспомогательные инструменты практически для любой задачи.




Поэтому команда Kubernetes aaS от Mail.ru обновила и дополнила подборку. Предлагаем вашему вниманию список с почти сотней полезных инструментов, упрощающих жизнь тем, кто работает с Kubernetes.










Инструменты развертывания кластера




1. Keel




Оператор Kubernetes, который автоматизирует обновления DaemonSet, StatefulSet, Helm и Deployment. Одна команда, никаких зависимостей, конфигурационных файлов и блокировок.




2. Kube-prod-runtime




Набор служб Kubernetes, который упрощает работу в продакшене под серьезной нагрузкой. Обеспечивает мониторинг производительности в кластере, ведение журналов, управление сертификацией и автоматическое обнаружение ресурсов в K8s через общедоступные DNS-серверы. Это полезный набор сервисов и для других инфраструктурных нужд.




3. K3sup




После установки k3sup (произносится как ketchup) вы можете за считанные секунды сгенерировать kubeconfig на любой локальной или удаленной виртуальной машине.







4. Mail.Ru Cloud Solutions: Cloud Containers




На платформе можно развернуть кластеры Kubernetes в виде облачного сервиса: за несколько минут вы получите готовый к работе кластер без необходимости в настройке и обновите его до нужной версии. Также кластеры просто масштабировать — они работают на инфраструктуре Mail.Ru, рассчитанной на высоконагруженные сервисы.







5. Kubeadm




Средство для инициализации кластеров Kubernetes в оптимальной конфигурации на вашей инфраструктуре. Главное преимущество — возможность запускать минимально жизнеспособные кластеры Kubernetes в любой среде. Надстройки и сетевые настройки не входят в конфигурацию из коробки, все придется настроить вручную. 




6. Kubespray




Набор ролей Ansible для развертывания и конфигурации Kubernetes. Работает на разных облачных платформах: AWS, GCE, Azure, Mail.Ru Cloud Solutions, OpenStack и bare metal IaaS. Это open source проект, построен на kubeadm. Подходит тем, кто хорошо знаком с Ansible — с этим инструментом вам ничего не нужно больше знать, чтобы развернуть все нужные ресурсы. 




7. Conjure-up 




Позволяет развертывать Kubernetes с помощью нескольких команд, поддерживает развертывания на локальном хосте, bare metal, в облачных средах, в том числе OpenStack.




8. Minikube




Хорошее начало для тех, кто только знакомится с Kubernetes. Инструмент позволяет пользователям легко запускать одноузловой кластер локально внутри виртуальной машины на ноутбуке пользователя. Поддерживается в Mac OS X, Windows и Linux.




9. MicroK8s 




Инструмент для пользователей Kubernetes, позволяющий развернуть автономный кластер на сервере Linux, хорошо подходит для Edge и IoT.




10. Bootkube 




Запускает автономные кластеры и помогает настроить временную плоскость управления Kubernetes. Bootkube также можно использовать для создания необходимых ресурсов, которые будут использоваться при начальной загрузке нового кластера.




11. RKE от Rancher




Сертифицированный CNCF дистрибутив Kubernetes, работающий внутри контейнеров. Позволяет упростить и автоматизировать установку Kubernetes, не зависеть от операционной системы и платформы, на которой вы работаете.




Инструменты мониторинга




12. Kube-state-metrics




Простая утилита для прослушивания сервера Kubernetes API, помогает в генерации метрик о состоянии объектов. Фокусируется на работоспособности различных объектов внутри кластера, включая узлы, поды и развертывания.




13. Kubebox




Терминальная консоль, позволяющая управлять кластером Kubernetes и отслеживать его статус в режиме реального времени. Мониторит кластер, показывает, что происходит с ресурсами подов, журналы контейнеров и другие параметры. Позволяет легко перейти к нужному пространству имен и выполнить команду в нужном контейнере. Это помогает быстро справляться с неполадками и восстанавливать работу.  







14. Rakess




Плагин Rakess (Review Access) показывает все права доступа к кластеру Kubernetes. Конечно, для отдельных ресурсов можно выполнить проверку командой kubectl auth can-i list deployments, но она не дает полную информацию обо всех ресурсах на сервере.




15. Kubetail




Bash-скрипт, позволяющий агрегировать журналы многих подов в один поток. В исходной версии не умеет фильтровать или выделять, но на Github есть отдельный форк, позволяющий раскрашивает логи с помощью MultiTail.




16. Stern




Еще один инструмент из категории «tail для подов в Kubernetes». Особенности: использование регулярных выражений для удобной фильтрации подов (не нужно знать конкретные ID), аналогично можно фильтровать отдельные контейнеры для запрашиваемых подов, есть стандартные и кастомные Go-шаблоны для выводимых логов, ограничение вывода логов по периоду времени или количеству строк и много чего еще.




17. Prometheus




Не можем снова не упомянуть этот опенсорсный инструмент для мониторинга и уведомлений, который давно стал стандартом для мониторинга Kubernetes. Он интегрирован со всеми популярными языками программирования, помогает создавать собственные метрики и содержит много готовых интеграций с популярными технологиями, например: PostgreSQL, MySQL, ETCD.




С помощью Prometheus Operator можно создавать экземпляры Prometheus в кластерах Kubernetes, в том числе тесную интеграцию с Grafana и Alertmanager.




18. Jaeger




Инструмент трассировки с открытым исходным кодом. Умеет мониторить транзакции и сервисные зависимости в распределенных системах, выявлять и устранять неполадки. Один из способов начать работу с ним в Kubernetes — использовать специальный оператор Jaeger




19. Searchlight




Оператор Kubernetes для Icinga. Умеет запускать периодические проверки на кластерах Kubernetes, а потом отправлять уведомления по электронной почте, СМС или в чат, если что-то идет не так. В инструмент по дефолту включен комплект проверок специально для Kubernetes. С его помощью можно расширить возможности мониторинга Prometheus, также он станет резервной системой, если внутренние системы мониторинга полностью откажут.




20. Kubernetes Operational View (Kube-ops-view)




Read-only системная панель, способная работать со многими кластерами Kubernetes. Позволяет удобно перемещаться между кластерами, отслеживать ноды и состояние подов. Визуализирует ряд процессов, таких как создание и уничтожение подов. 







21. Kubewatch 




Запускается в подах в кластере Kubernetes, отслеживает системные изменения, после запуска вы будете получать уведомления через веб-хуки. Можно настроить свои уведомления, просто отредактировав файл конфигурации.




22. Weave Scope 




Отслеживает и устраняет неполадки в кластерах Kubernetes и Docker, чтобы вы могли легко выявлять и устранять проблемы с контейнеризованными приложениями. Вы можете использовать его, чтобы определить узкие места производительности приложений.







23. Turbonomic/Kubeturbo 




Обеспечивает видимость всего вашего стека, позволяет контролировать эффективность базовой инфраструктуры и производительность запущенных микросервисов в Kubernetes.




Тестирование




24. Kubeval




Инструмент для проверки конфигурационного файла Kubernetes YAML или JSON. Проверка осуществляется с использованием схем, сгенерированных из Kubernetes OpenAPI. Это позволяет производить валидацию схем для разных версий Kubernetes.




25. Helm-kubeval




Плагин Helm, используемый для валидации диаграмм на соответствие схемам Kubernetes. Для проверки диаграмм можете выбрать определенные версии Kubernetes.




26. BotKube




BotKube может отслеживать, отлаживать и запускать проверки в кластерах Kubernetes. Инструмент также интегрируется в различные платформы для обмена сообщениями, такие как Slack и Mattermost. Преимущества — открытый исходный код и простота настройки.







27. Sonobuoy




Sonobuoy — диагностический инструмент для проверки на соответствие нормативам, отладки рабочей нагрузки и проведения пользовательских тестов, которые помогают определить состояние кластера. Тесты выполняются неразрушающим образом, при этом генерируются четкие информативные отчеты.




28. Snyk Container




Snyk позволяет быстро находить и исправлять уязвимости в контейнерах и приложениях Kubernetes на протяжении всего жизненного цикла разработки.







29. Kube-monkey




Следуя принципам хаос-инжиниринг, Kube-monkey случайным образом удалит модули Kubernetes в кластере и проверит разработку отказоустойчивых сервисов.




30. K8s-testsuite 




Состоит из двух диаграмм Helm для тестирования пропускной способности сети и нагрузочного тестирования кластеров Kubernetes. Это поможет убедиться в правильности их конфигурации, а также в работоспособности служб и правильном распределении нагрузки.




31. PowerfulSeal 




Инструмент специфичен для Kubernetes и также следует принципам хаос-инжиниринг, позволяя проверить объекты, работающие в контейнерах. Также его можно использовать для проверки выбранных компонентов кластера вручную через интерактивный режим. После развертывания инструмент работает автономно.







Безопасность




32. Harbor




Реестры Harbor защищают образы с контейнерами путем внедрения системы управления доступом на основе ролей. Инструмент также проверяет образы на наличие уязвимостей и подписывает их как надежные.




33. Kubesec




Инструмент с открытым исходным кодом для анализа рисков безопасности ресурсов Kubernetes. С ним вы сможете контролировать систему и получите полный список рекомендаций по повышению ее общей безопасности. 




34. Permission-Manager




Это приложение разработки компании SIGHUP позволяет легко управлять ролями доступа для Kubernetes через систему Role-Based Access Control. Создайте пользователей, назначьте пространство имен/разрешения, а также распространите файлы Kubeconfig YAML.







35. Kube-scan




Инструмент от компании Octarine фокусируется на оценке рисков в рабочих нагрузках Kubernetes. Kube-scan запускается как под в кластерах и оценивает 30 параметров безопасности, чтобы вывести максимально приемлемый уровень риска. Затем инструмент анализирует, какие параметры работают в тандеме, чтобы понять, какие комбинации уменьшат уровень угроз.







36. K-rail




K-rail предназначен для ситуаций, когда требуется чуть больше контроля в реализации ваших политик. Есть множество простых способов повышения привилегий, но в мультитенантном кластере они могут представлять опасность или приводить к нестабильности.




37. KeyCloak




KeyCloak — опенсорсный инструмент управления доступом и идентификационной информацией пользователей. Он добавляет функцию аутентификации приложений и помогает минимальными усилиями обеспечить безопасность служб. Устраняет необходимость детально разбираться с ведением списка пользователей и их аутентификацией. Всё это теперь работает прямо из коробки.




38. Aquasec




Инструмент предназначен для защиты инсталляций Kubernetes на протяжении всего жизненного цикла. Он развертывает на каждом контейнере выделенный агент, работающий как межсетевой экран и устраняющий возможные уязвимости. Управлять ограничениями безопасности вы сможете через центральную консоль. Кроме того, инструмент позволяет использовать гибкие настройки безопасности в локальных и облачных средах. 




С ним связан еще один open source инструмент  — Kube-Bench, проверяющий среду Kubernetes по тестам из документа CIS Kubernetes Benchmark.




39. Tigera




Инструмент от создателей проекта Calico, набор решений для сетевой безопасности Kubernetes с поддержкой мультиоблачных и устаревших сред через автоматизированную универсальную политику безопасности.




40. Klum




Klum, или Kubernetes Lazy User Manager, выполняет простые задачи, такие как создать/удалить/изменить пользователей. Он выдает файлы kubeconfig и управляет ролями юзеров.




41. StrongDM




StrongDM — это плоскость управления для проверки безопасности и доступа к вашим серверам и/или базам данных. Состоит из API аутентификации, прокси-сервера, поддерживающего протокол, и хранилища журналов. 




42. Falco




Инструмент для обеспечения безопасности с открытым исходным кодом для облачных вычислений, обнаруживает риски для Kubernetes. Замечает неожиданное поведение приложения и оповещает об угрозах во время его выполнения.




43. Sysdig Secure 




Платформа, обеспечивающая мониторинг безопасности микросервисов и контейнеров. Поддерживаются Kubernetes и Docker. Может быть использована в облаке и локально.




Полезные утилиты




44. Krew




Krew помогает разработчикам находить полезные плагины kubectl для программ и устанавливать, а потом управлять ими. Этот инструмент похож на APTDNF или Homebrew.




45. Ksniff




Плагин для kubectl, который эффективно использует Wireshark и tcpdump для удаленного захвата трафика с любого пода в кластере Kubernetes.







46. Kube-ps1




Скрипт Kube-ps1 добавляет текущий контекст Kubernetes и сконфигурированное пространство имен из kubectl в консоль Bash/Zsh, никаких команд не требуется.




47. Kubefwd




Если вы запускаете службы Kubernetes на удаленном кластере, то Kubefwd поможет перенаправить их на локальную рабочую станцию. Никаких модификаций не требуется: если вы используете kubectl, вы уже соответствуете всем требованиям.







48. Kubeterminal




Это скорее вспомогательный инструмент, который дополняет kubectl и вашу консоль в Kubernetes.







49. Skaffold




Skaffold — консольная утилита, помогающая обеспечить процесс непрерывной разработки приложений Kubernetes. Инструмент очень легкий и не требует компонентов на стороне кластера.




50. Kubectl-aliases




Простой и очень мощный генератор алиасов для kubectl. С его помощью вы сможете очень быстро писать команды для повседневного администрирования Kubernetes, так как он предоставляет более 800 коротких алиасов на все случаи жизни.




51. Kubectx/Kubens




Опенсорсная утилита, дополняет Kubectl, позволяет переключать контекст и подключаться одновременно к нескольким кластерам Kubernetes, а также перемещаться между пространствами имен. Есть поддержка автозаполнения в оболочках bash/zsh/fish.




kubectx помогает переключаться между кластерами вперед и назад:







kubens помогает плавно переключаться между пространствами имен Kubernetes:







52. Kube-shell




Инструмент, ускоряющий работу с kubectl. Автодополняет команды, предлагает разные варианты, ищет и исправляет команды, которые введены неправильно, отображает in-line справку о выполняемых командах.







53. Tilt




Если вы редко выходите из консоли, Tilt синхронизирует все изменения с кластером и обновляет серверы, так что вы сразу видите, как внесенные изменения влияют на систему. Инструмент показывает состояние каждого ресурса, выдает журналы для каждого из них или всё вместе. Все обновления выполняются внутри контейнера, что делает их очень быстрыми.





https://embedd.srv.habr.com/iframe/5f9a63672c0608e1441a4051




54. Kail (Kubernetes Tail)




Инструмент позволяет отслеживать логи Docker для нужных подов. Он фильтрует поды по службам, развертываниям, меткам и иным параметрам. В соответствии с критериями фильтрации поды после запуска будут автоматически добавлены в журнал или удалены из него.




Инструменты разработки




55. Helm 




Пакетный менеджер, помогает управлять приложениями Kubernetes с помощью Helm Charts. Это позволяет пользователям создавать воспроизводимые сборки, которыми можно делиться.




56. Helm-2to3




Этот плагин помогает разработчикам перенести конфигурацию из Helm v2 в Helm v3 с соответствующей очисткой конфигурации.







57. Rook




Rook помогает автоматизировать различные задачи для хранилища данных, такие как развертывание, загрузка, масштабирование, обновление и так далее. Это гарантирует, что на Kubernetes будет стабильно работать решение любого поставщика (Ceph, EdgeFS, CockroachDB, Cassandra, NFS, Yugabyte DB).




58. Contour




Contour — ingress-контроллер Kubernetes, обеспечивает плоскость управления для Ingress и служебного прокси.




59. Shell-operator




Shell Operator упрощает создание операторов Kubernetes. Он обеспечивает интеграцию между событиями кластера Kubernetes и сценариями оболочки. Упрощает управление кластером. 




60. Helm-operator-get-started




Помогает управлять вашими релизами Helm.







61. Helmfile




Инструмент для управления релизами helm-чартов. Позволяет в одном месте описывать множество helm релизов, задавать порядок их деплоя и делать другие полезные вещи.




62. Kudo




Kudo упрощает создание операторов Kubernetes, в основном используя YAML. Он предоставляет готовые операторы, которые можно настроить из коробки.




63. Helm-docs




Этот инструмент автоматически генерирует документацию из диаграмм Helm в файл markdown. Данный файл содержит метаданные, включая таблицу со всеми значениями диаграммы и значениями по умолчанию.




64. Telepresence 




Позволяет локально отлаживать службу Kubernetes, упрощая процесс разработки.




65. Kubectl-debug




Позволяет запускать дополнительный контейнер в интересующем вас поде. Новый контейнер будет использовать пространство имен совместно с целевым контейнером/контейнерами. 




66. Ksync 




Почти мгновенно синхронизирует файлы вашей локальной системы с кластером Kubernetes. Подходит, если вы используете сценарии, в которых основной проблемой является доставка кода в работающий контейнер. 




67. Squash 




Используют для отладки процессов во время их работы в кластере. Простой в использовании, вы можете в интерактивном режиме выбрать нужный отладчик и пространство имен/под интересующего процесса. 




Конвейер CI/CD




68. Rafay




Rafay — программный инструмент, который упрощает для компании или отдельного разработчика создание собственной платформы, системы автоматизации и управления жизненным циклом приложений. Rafay также способен запускать кластеры Kubernetes.




69. Rancher




Rancher — полноценная программная платформа, которая легко развертывает контейнерные среды, выходящие за рамки инсталляторов Kubernetes, таких как Kops и Kubespray. Предоставляет множество функций, включая управление инфраструктурой, планирование и оркестровку контейнеров, мониторинг, проверку работоспособности, ведение журналов, а также мощную систему управления доступом на основе ролей.




70. Draft




Утилита от разработчиков Helm. Ее цель — упростить приложения, которые разрабатываются для работы в Kubernetes. С помощью двух простых команд вы можете работать с контейнерными приложениями, даже не нуждаясь в установке Docker или Kubernetes.




71. Jenkins




Пожалуй, наиболее популярный open source CI/CD-сервер в мире. К нему есть бесплатный плагин, помогающий развертывать приложения в Kubernetes, обновлять их с минимальным простоем и обеспечивать Green/Blue-развертывание обновлений. 







72. TeamCity




Известный CI/CD сервис от JetBrains. Есть плагин, с которым можно использовать инфраструктуру кластера Kubernetes для запуска билд-агентов TeamCity (в версии 2017.1.x и новее). 




73. Apollo 




Решение для непрерывного развертывания (CD), предоставляющее интерфейс самообслуживания для команд. Может интегрироваться с существующими процессами сборки. Это позволяет управлять кластерами Kubernetes, предоставляя каждому пользователю определенные разрешения для обеспечения безопасности развертывания.







74. Werf




CLI-инструмент с открытым исходным кодом, написанный на Go, предназначен для упрощения и ускорения доставки приложений. Werf создает образы Docker с использованием Dockerfiles или альтернативного быстрого встроенного компоновщика на основе собственного синтаксиса. Он также удаляет неиспользуемые образы из реестра Docker. Потом Werf развертывает ваше приложение в Kubernetes, используя диаграмму в формате, совместимом с Helm, с удобными настройками и улучшенным механизмом отслеживания развертывания, обнаружения ошибок и вывода журнала.




Инструмент позволяет создавать конвейеры, которые можно встроить в любую существующую систему CI/CD. 




75. Garden




Garden — инструмент для разработчиков, который автоматизирует ваши рабочие процессы и делает разработку и тестирование приложений Kubernetes быстрее и проще. Подходит для совместной разработки в удаленном кластере.







Сервисные сетки




76. Kiali




Kiali помогает создавать определения, проверять и наблюдать за работой микросервисов и соединений в сервисной сетке Istio. Инструмент создает визуальное графическое представление топологии сервисной сетки и дает представление о таких функциях, как разрыв цепи (circuit breaker), маршрутизация запросов, задержка и других. 




77. Kuma




Универсальная панель управления для сервисных сеток и микросервисов. Может нативно работать и в виртуальной среде, и в Kubernetes. Легко вводится в арсенал инструментов любой команды в организации.







78. Tenkai




Tenkai — это менеджер микросервисов, основанный на диаграммах Helm. Инструмент с графическим веб-интерфейсом позволяет вызывать репозитории из диаграмм Helm, легко их настраивать и деплоить.







Обнаружение служб




79. Обнаружение cлужб Vert.X




Репозиторий с множеством инструментов для обнаружения служб, которые видны из ваших приложений с микросервисами. Службы можно импортировать и из Kubernetes (а также из Docker и Consul).




Визуализация и управление




80. Octant




Веб-инструмент с открытым исходным кодом, который позволяет визуализировать ваши рабочие нагрузки Kubernetes и предоставляет по ним обновления в режиме реального времени.




81. Kubernetic




Kubernetic помогает легко и быстро развертывать общедоступные или приватные диаграммы, видеть все связанные объекты кластера и их зависимости на одном экране. Отличается такими функциями, как визуализация в реальном времени, а также поддержка нескольких кластеров.







82. Kubernetes Dashboard




Универсальный веб-интерфейс кластеров Kubernetes. С помощью этой нативной панели управления проще устранять неполадки и мониторить кластеры. 







83. Kubeapps




Веб-интерфейс для каталога приложений в кластерах Kubernetes. Позволяет устанавливать, обновлять и удалять Helm-чарты нажатием одной кнопки, без использования командной строки.





https://embedd.srv.habr.com/iframe/5f9a6367d4323713fd415876




84. Lens




Приложение для рабочего стола, работает в Windows, Mac и Linux. Может подключаться к локальному кластеру K8s, подходит для небольшого количества кластеров.







85. Kubevious




Программное обеспечение с открытым исходным кодом, удобный графический интерфейс. Отображает все конфигурации, относящиеся к приложению, в одном месте. Это экономит время, избавляя от необходимости искать настройки и копаться в селекторах и метках. Один из недостатков инструмента — он работает непосредственно на кластере K8s. Значит, вам придется развертывать Kubevious на каждом кластере, а не просто указывать на существующий.





https://embedd.srv.habr.com/iframe/5f9a6368905dc4e15aeed79b




86. Kubelive




Основанный на терминалах пользовательский интерфейс, использующий Node.js. Довольно прост в использовании, но в настоящее время ограничен несколькими командами kubectl. Позволяет легко перемещаться по различным пространствам имен кластера K8s и быстро отображать состояние заданного набора подов.







87. K9s




Еще один удобный пользовательский интерфейс, упрощает навигацию, наблюдение и управление вашими приложениями.




Инструменты для бессерверных вычислений/функций




88. Kubeless




Безсерверная инфраструктура Kubernetes с открытым исходным кодом, которая позволяет вам развертывать небольшие фрагменты кода. Поддерживает большинство популярных языков, позволяет редактировать и развертывать функции в режиме реального времени.




89. Fission




Еще один открытый серверный фреймворк Kubernetes с открытым исходным кодом. Поддерживает все языки программирования. Напишите недолговечные функции на любом языке и сопоставьте их с HTTP-запросами (или другими триггерами событий) — инструмент позволяет развернуть функции мгновенно с помощью одной команды. Нет контейнеров для сборки и нет реестров Docker для управления.







90. Funktion




Это модель программирования лямбда-стиля с открытым исходным кодом для Kubernetes. Позволяет разработчикам сосредоточиться на написании функций, в то время как Kubernetes позаботится обо всем остальном.




91. IronFunction




Серверная вычислительная платформа с открытым исходным кодом для любого облака — частного, общедоступного или гибридного. Используя этот инструмент, разработчики могут просто загрузить свой код, пока платформа работает с инфраструктурой. 




92. OpenFaaS




Упрощает развертывание как функций, так и существующего кода в Kubernetes. Работает в публичных и частных облаках. Позволяет создавать микросервисы и функции на любом языке. 




93. Nuclio




Cерверный проект, который позволяет использовать его в качестве автономного контейнера Docker или даже поверх другого кластера Kubernetes. Предназначен для работы с высокопроизводительными событиями и большими объемами данных. Также обеспечивает обработку данных в режиме реального времени с минимальными издержками.




94. Virtual-Kubelet




Является открытой реализацией Kubernetes Kubelet. Запускается внутри контейнера в вашем текущем кластере и маскируется под узел. Оттуда он контролирует запланированные пакеты так, как это делает настоящий Kubelet.




На этом всё. Пишите в комментариях, если знаете другие полезные инструменты.




Источник: https://habr.com/ru/company/vk/blog/499676/



2022-08-31T19:40:06
DevOps

Helm: пошаговое создание чарта и деплоймента из Jenkins



Сам Хельм в общих чертах рассмотрели в посте Helm: Kubernetes package manager — обзор, начало работы – теперь надо прикрутить его в Jenkins. И не просто прикрутить его вызов – а создать чарт, потому что сейчас приложение деплоится через “голые” манифест-файлы Kubernetes, в котором sed проставляет теги Докер-образа и значения переменных для загрузки на окружение через kubectl apply -f.




Данный пост очередной НЕ-HowTo, а пример знакомства с Helm: возьмём существующий проект, который уже деплоится в Kubernetes-кластер, обновим его манифесты, что бы использовать их с Helm, продумаем – как именно и куда будем деплоить, и создадим Jenkins-джобу.




По ходу дела будем ближе знакомиться с Helm, и его подводными камнями.




В общем, ещё один пример того, как очередная задача из смутной идеи в голове превращается в рабочий сервис – длиннопост в вольном стиле, аналог AWS Elastic Kubernetes Service: автоматизация создания кластера, часть 1 — CloudFormation и AWS Elastic Kubernetes Service: — автоматизация создания кластера, часть 2 — Ansible, eksctl, где шаг за шагом реализуем свою задумку.




Планирование




Репозитории




Итак, у нас имеется некое веб-приложение, которое надо деплоить в Kubernetes.




Само приложение разбито на две части – фронтенд на React, хостится и деплоится в AWS S3, и бекенд – NodeJS, работает в Docker-контейнере.




Первый вопрос, который появляется в голове – монорепа, или нет?




Т.е. – где хранить код приложения, где – файлы чартов Helm-а, а где – jenkins-файлы?




Хотелось бы монорепу, и всё держать в одном репозитории, но у нас подобных проектов будет не один, и смысла под каждый писать отдельные дженкис-файлы нет. Тем более, что если (когда!) захочется что-то изменить в одном – то придётся делать это во всех по отдельности.




При этом и их файлы манифестов для Kubernetes будут практически одинаковы – и можно было бы заморочится вообще, и используя возможности шаблонизатора Go – использовать один общий чарт на всех.




Но так как их одинаковость пока под вопросом – запускаемые веб-проекты ещё только разрабатываются, да ещё и отдельными группами девелоперов – то чарты будем делать под каждый проект отдельно.




Значит, у нас будет:




  • отдельный репозиторий с кодом проекта
    • там же в отдельной папке храним файлы чартов
  • отдельный репозиторий с файлами для Jenkins-pipeline




Хочется прикрутить ещё и релизы, да ещё и связать их с Github Releases – но это, может быть, потом. В целом – реализуемо, и даже есть helm/chart-releaser.




Jenkins build steps




Дальше.




Билд Docker-образов – и билд/деплой самих чартов – делать одной джобой – или разными?




Сейчас у нас образы собираются в одной джобе, после чего пушатся в DockerHub, после чего девелопер должен сходить в джобу деплоймента, и при запуске в параметрах указать тег (номер билда) + дополнительные параметры:





Это, конечно, ни разу неудобно, поэтому переделаем.




Итак, будет один пайплайн, в котором нам надо:




  1. чекаут кода проекта
  2. линт чарта
  3. сгенерить kubeconfig
  4. helm install example-chart --dry-run --debug example-chart/
  5. helm install example-chart example-chart/
  6. тест деплоя – helm get manifest example-chart




Опционально – удалять с chart uninstall. Про удаление ресурсов вообще поговорим ниже.




Что ещё?




Namespaces




Ооо – нейспейсы жеж!




Что хочется:




  • иметь возможность деплоить по одной кнопке в какой-то дефолтный namespace, имя которого зависит от проекта/приложения/чарта
  • деплоить в кастомный namespace – по имени бранча репозитория, из которого запускался билд
  • деплоить в вообще кастомный namespace – дать возможность указать его при старте джобы




А как их потом удалять?




Можно добавить вебхук из Гитхаба при delete-операциях, но во-первых часть проектов хостятся в Gitlab – хотя он тоже умеет в вебхуки. Но во-вторых – а все ли девелоперы всех команд будут удалять свои закрытые бранчи?




Т.е. тут проблема как раз из-за разных команд и разных проектов, а решение хочется иметь маскимально универсальное.




А удалять НС-ы надо – иначе будет пачка заброшенных ресурсов – подов, ингресов, волюмов, и т.д.




Что делать?…




Окей. А пусть будет какой-то дефолтный неймспейс. Например, чарт/приложение называются bttrm-apps – значит, для Dev-деплой джобы НС будем создавать bttrm-apps-dev-ns.




В джобе добавить параметр, в нём сделать возможность выбора – использовать этот дефолтный НС, создать/использовать НС по имени бранча, или указать свой.




Можно так в Jenkins?




Не факт – идём глянем.




Choise parameter – тут просто задаётся список предефайненных значений – нельзя будет задать своё имя НС-а:





А Multi string parameter?





Вроде как что-то аналогичное Choise parameter?




Смотрим на него:





Нет, тоже не подходит – оно просто из параметра передаст нам в переменную дженкисфайла значение из нескольких строк, а нам нужна одна string.




Значит – или таки обычный String параметр, или Choise parameter с набором уже заданных значений… Но тогда потеряем возможность создать кастомный НС…




Или… Или… Или… Мысль…




А что на счёт Boolien parameter?




Типа “поменять НС”…




Дефолтное значение “не менять” – и используем предефайненное значение bttrm-apps-dev-1-ns




А если юзер выбирает менять – то используем имя НС как имя бранча – а имя бранча вытянем из репозитория после чекаута…




Мысль? А может быть!




Хотя снова-таки – лишаемся возможности создать кастомный НС…




А что если просто использовать тот же Choise parameter с набором уже заданных значений, но создать три значения:




  • use default bm-apps-dev-ns
  • use github-branch-name
  • set own name




А потом в коде самого пайплайна проверять выбор, и если выбрано set own name – то просто запросить User input, и пользователь задаст имя неймспейса, который хочет создать.




Тоже не самое кошерное решение – но может сработать. Пока остановимся на нём.




Остаётся открытым вопрос про удаление НС-ов – будем думать потом 




Хотя потом может быть больно.




В конце-концов – мы спокойно можем раз в месяц удалять весь Dev-кластер, и провиженить заново – дело 20 минут и одного клика в Jenkins, а для Stage/Prod деплоев будут использоваться только жёстко заданные неймспейсы, потому там такой проблемы не будет (но это не точно).




Окей, make sense.








Что дальше?




Дальше локально сделаем:




  1. создадим чарт для приложения – используем реальное, но отбранчуемся, что бы не мешать девелоперам.
  2. настроим kubectl на новый Dev-кластер
  3. выполним helm install




Потом пойдём делать джобу в дженкисе.




Джоба будет клонировать репозиторий с приложением, и делать helm install в нужный namespace.




А что с релизами-то? Го, почитаем Charts and Versioning.




А релиз-версии нужны судя по всему только если мы будем заливать чарты в виде архивов в свой Helm-репозиторий – в самом Кубере они никак не применяются…




Значит – пока этот вопрос отложим, потом вернёмся к chart-releaser.




Поехали тестить?




Helm test deploy




kubectl config




У меня есть новый тестовый кластер bttrm-eks-dev-1 – создаём для него конфиг.




Генерим конфиг, создаём новый контекст с именем arseniy@bttrm-eks-dev-1, см. Kubernetes: kubectl и kubeconfig — обзор файла, добавление кластера, пользователя и контекста:




aws --profile arseniy eks update-kubeconfig --name bttrm-eks-dev-1 --alias arseniy@bttrm-eks-dev-1
Added new context arseniy@bttrm-eks-dev-1 to /home/setevoy/.kube/config




Создаём тестовый чарт:




cd /tmp/
helm create deployment-testing-chart
Creating deployment-testing-chart




Helm: the server has asked for the client to provide credentials




Пробуем залить в default namespace:




helm install deployment-testing-chart --dry-run deployment-testing-chart/
Error: Kubernetes cluster unreachable: the server has asked for the client to provide credentials




WTF?




Проверяем контекст:




kk config current-context
arseniy@bttrm-eks-dev-1




(kk – алиас для kubectl в ~/.bashrcalias kk="kubectl")




Всё верно…




А доступ есть?




kk get pod
error: You must be logged in to the server (Unauthorized)




Нет.




В автоматизации создания кластера не добавлен мой IAM user…




Что там вообще? Читаем пост AWS Elastic Kubernetes Service: RBAC-авторизация через AWS IAM и RBAC группы, вспоминаем – делал через роли, отдельных пользователей в aws-auth ConfigMap уже не добавляю.




Надо локально настроить AssumeRole.




Надеюсь я прописал в полиси этой роли доступ для моего юзера…




Пробуем – обновляем ~/.aws/config:




...
[profile iam-bttrm-eks-root]
role_arn = arn:aws:iam::534***385:role/iam-bttrm-eks-root-role
source_profile = arseniy
region = us-east-2




Удаляем созданный контекст:




kk config delete-context arseniy@bttrm-eks-dev-1
warning: this removed your active context, use "kubectl config use-context" to select a different one
deleted context arseniy@bttrm-eks-dev-1 from /home/setevoy/.kube/config




Генерим новый:




aws --profile iam-bttrm-eks-root eks update-kubeconfig --name bttrm-eks-dev-1 --alias iam-bttrm-eks-root@bttrm-eks-dev-1
Updated context iam-bttrm-eks-root@bttrm-eks-dev-1 in /home/setevoy/.kube/config




Проверяем доступ:




kk get po
NAME                                 READY   STATUS    RESTARTS   AGE
reloader-reloader-55448df76c-wdzqp   1/1     Running   0          28h




(про reloader – см. Kubernetes: ConfigMap и Secrets — auto-reload данных в подах)




Окей – возвращаемся к хельму:




helm install deployment-testing-chart --dry-run deployment-testing-chart/
NAME: deployment-testing-chart
LAST DEPLOYED: Thu May  7 20:06:44 2020
NAMESPACE: default
STATUS: pending-install
...




Найс!




Helm – deploy to  a Namespace




А что с деплоем в кастомный неймспейс?




helm install deployment-testing-chart --dry-run deployment-testing-chart/ --namespace deployment-testing-chart-ns
NAME: deployment-testing-chart
LAST DEPLOYED: Thu May  7 20:08:00 2020
NAMESPACE: deployment-testing-chart-ns
STATUS: pending-install
...




Тоже вроде ОК.




Helm и неймспейс сам создаёт? Не верится…




Попробуем реальный запуск, без --dry-run:




helm install deployment-testing-chart deployment-testing-chart/ --namespace deployment-testing-chart-ns
Error: create: failed to create: namespaces "deployment-testing-chart-ns" not found




Нет, не создаёт)




Окей – это хорошо




Гуглим – понятное дело, что до нас люди с таким уже сталкивались, например – https://github.com/helm/helm/issues/4456, и там комментарий https://github.com/helm/helm/issues/4456#issuecomment-412134651:




This is a known limitation of Helm. Helm will not do cross-namespace management, and we do not recommend setting namespace: directly in a template.
If you want to install resources in a namespace other than the default namespace, helm install –namespace=foo will install the resources in that namespace. If the namespace does not exist, it will create it.




Эээ? Так мы  ж так и делали…




Читаем ниже:




For Helm 3, the namespace creation doesn’t happen during helm install any more, so you’ll have to create that namespace ahead of time as you do today.




Ага!




И ещё ниже – https://github.com/helm/helm/issues/4456#issuecomment-607927999:




For Helm 3, the namespace creation doesn’t happen during helm install any more, so you’ll have to create that namespace ahead of time as you do today.Right now, use kubectl create namespace foo prior to helm install. When Helm 3.2.0 is released, use helm install … –create-namespace.




А у нас какая?




helm version
version.BuildInfo{Version:"v3.2.0", ...




Ага!




Пробуем:




helm install deployment-testing-chart deployment-testing-chart/ --namespace deployment-testing-chart-ns --create-namespace
NAME: deployment-testing-chart
LAST DEPLOYED: Thu May  7 20:15:38 2020
NAMESPACE: deployment-testing-chart-ns
STATUS: deployed
REVISION: 1
...




Бимба!




Проверяем НСы:




kk get ns
NAME                          STATUS   AGE
bttrm-apps-dev-1-ns           Active   28h
bttrm-workouts-dev-1-ns       Active   28h
default                       Active   28h
deployment-testing-chart-ns   Active   19s
...




Няшка.




Сервисы:




kk -n deployment-testing-chart-ns get svc
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
deployment-testing-chart   ClusterIP   172.20.227.114   <none>        80/TCP    2m1s




Окей, вроде работает – можно думать за Helm chart для самого приложения.




Хотя тут можно начать наоборот с Jenkins-джобы и скрипта, и использовать тестовый чарт, а потом создавать чарт реального приложения.




Но давайте сначала всё-таки приведём в рабочий вид приложение.




Helm – создание чарта




Сейчас у нас файлы для Kubernetes лежат в отдельном репозитории devops, а код приложения – в репозитории самого приложения.




Что надо сделать – это создать чарт в репозитории с приложением – в этом репозитории будет и Dockerfile, там же будем хранить Chart.yaml.




Скрипты для Jenkins (jekinsfiles) хранятся в ещё одном отдельном репозитории для общего доступа из различных, но однотипных джоб.




What about RBAC?




Кстати. Задумался я о том, как мы будем деплоить с Jenkins и о правах доступа.




Сам Jenkins использует свою EC2 Instance Profile, которая даёт ему полный доступ к кластерам. Ту же роль использую сейчас я при AssumeRole, которую мы настроили выше в ~/.aws/config.




А что с девелоперами?




У них-то создаются отдельные RoleBinding из определённых неймспейсов, в которые им разрешается доступ, а не глобальный рутовый доступ, как у меня.




Значит – эти RoleBinding надо включить в чарт, и создавать их в тех неймспейсах, которые будут создавать при деплое чарта из Jenkins в – напомню – том числе и кастомные неймспейсы.




Как быть? Делать RBAC сабчартом?




Вопрос… Да и для самого Helm, по-хорошему, надо создавать отдельный Kubernetes ServiceAccount при создании кластера.




Хотя – зачем нам выносить доступы юзеров в отдельный чарт или сабчарт?




Там всего-то создать одну RoleBinding в нужном неймпсейсе. А “глобальная” ClusterRole создаётся при провижене самого кластера из Ansible (потом надо будет переписать на Helm, и все RBAC-ресурсы через него деплоить).




Окей – значит так и сделаем.




Создание чарта




Поехали – клонируем репозиторий, создаём каталог, создаём чарт:




mkdir k8s
cd k8s/
helm create bttrm-apps-backend
Creating bttrm-apps-backend




Удаляем шаблоны, копируем из старого репозитория:




cd bttrm-apps-backend
rm -rf templates/*
cp ~/Work/devops/projects/EKS/roles/eks/templates/bttrm-apps/* templates/




Что у нас тут есть:




ls -1 templates/
bttrm-apps-deployment.yaml
bttrm-apps-ns-ingress-hpa.yaml
bttrm-apps-secrets.yaml




Посмотрим файл деплоймента:




apiVersion: apps/v1
kind: Deployment
metadata:
  name: bttrm-apps-EKS_ENV
  annotations:
    secret.reloader.stakater.com/reload: "bttrm-docker-secret"
spec:
  replicas: DEPLOY_REPLICAS_NUM
  strategy:
    type: RollingUpdate
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: bttrm-apps-EKS_ENV
  template:
    metadata:
      labels:
        app: bttrm-apps-EKS_ENV
    spec:
      containers:
      - name: bttrm-apps-EKS_ENV
        image: bttrm/bttrm-apps:IMAGE_TAG
        env:
        - name: CLIENT_HOST
          value: CLIENT_HOST_VAl
        - name: DATABASE_HOST
          value: DATABASE_HOST_VAL
...




Собственно, как говорилось в начале – все КАПСы вырезаются в Jenkins с помощью sed, и меняются на реальные значения, полученные из параметров джобы, а потом выполняется kubectl apply -f.




Как-то так:




...
        dir ('eks') {
            git branch: "${DEVOPS_REPO_BRANCH}", url: "${DEVOPS_REPO_URL}", credentialsId: "jenkins-github"
            def templates_path = "projects/EKS/roles/eks/templates/bttrm-apps" 
            // .env
            sed_env("$templates_path","bttrm-apps-deployment.yaml","BACKEND_HOST_VALUE","$BACKEND_HOST")
            sed_env("$templates_path","bttrm-apps-deployment.yaml","CLIENT_HOST_VAl","$CLIENT_HOST")
            sed_env("$templates_path","bttrm-apps-deployment.yaml","DEPLOY_REPLICAS_NUM","$DEPLOY_REPLICAS_NUM")
...




Ужас, правда?)




Для тестов было ОК, давайте приводить в порядок.




Сначала во всех файлах удаляем все metadata: namespace: – неймспейс будет определяться самим Хельмом.




Удаляем файл values.yaml, который сгененрировал Helm во время инициализации чарта, создаём новый файл, пустой.




Открываем в одном окне values.yaml, в другом – файл деплоймента, начинаем обновлять:




  • kind: Deployment metadata: name: bttrm-apps-EKS_ENV
    испольуем {{ .Chart.Name }}
  • spec: replicas: DEPLOY_REPLICAS_NUM
    вот – тут уже пора в values.yaml идти, добавляем в нём replicaCount: 2
    а в деплойменте используем replicas: {{ .Values.replicaCount }}, см. пример ниже
  • selector:  matchLabels: app: bttrm-apps-EKS_ENV
    меняем на application: {{ .Chart.Name }}




Сначала думал в имя деплоймента включить .Chart.Version или .Chart.AppVersion – но тут у Хельма всё оказалось через… Печаль какую-то, т.к. задать их значения во время helm install нельзя – только во время package, см. https://github.com/helm/helm/issues/3555 (с 2018 обсуждают!).




Ладно – оставим на совести разработчиков – жираф большой, ему виднее. Пока в имени оставлю {{ .Chart.Name }} – по ходу дела посмотрим. Да и не факт, что использовать версии в имени хорошая идея.




По теме:







Пока в лейблах сделал так:




...
  selector:
    matchLabels:
      application: {{ .Chart.Name }}
  template:
    metadata:
      labels:
        application: {{ .Chart.Name }}
        version: {{ .Chart.Version }}-{{ .Chart.AppVersion }}
        managed-by: {{ .Release.Service }}-{{ .Release.Name }}
...




{{ Chart.version }} и {{ .Chart.appVersion }} будет задаваться в Jenkins, пока будем брать дефолтные значения из Chart.yaml.




Далее, для выбора Docker-образа надо в values задать имя образа и тег.




Мы сейчас хостим образы в DockerHub, но потом думаю переезжать на AWS Elastic Container Registry, поэтому сразу пусть будет с возможностью поменять.




Заполняем values.yaml – добавляем image:




replicaCount: 2
    
image:
  repository: bttrm
  name: bttrm-apps
  tag: ""




Получится строка типа bttrm/bttrm-apps:TAG, а TAG думаю формировать при сборке образа из $BUILD_NUMBER + $GIT_COMMIT, т.е. получим что-то вроде bttrm/bttrm-apps:123.67554433.




Дальше у нас идёт пачка переменных:




...
        env:
        - name: CLIENT_HOST
          value: CLIENT_HOST_VAL
        - name: DATABASE_HOST
          value: DATABASE_HOST_VAL
        - name: DB_USERNAME
          value: DB_USERNAME_VAL
...




Значения для плейсхолдеров типа CLIENT_HOST_VAL в основном будут задаваться из параметров джобы Дженкинса, но добавляем их в values тоже. Где можно – задаём дефолтные значения, где нет – просто “”.




Пока, кстати, вообще все значения можно задать в values – до Jenkins-джобы ещё будем тестить локально.




Кавычки




А что там с кавычками, кстати?




Тоже мрак)




С одной стороны – документация по созданию чарта (тыц>>>) и по переменным (тыц>>>) говорит использовать quote-функцию, которая будет “оборачивать” наши значения в кавычки.




При этом, если посмотреть файлы, сгенерированные при helm create – то там нет ни quote, ни кавычек – в большинстве случаев. Но не везде 




Например, для:




...
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
...




Кавычки есть. Почему? Потому что “составная строка” – конкатенируется из нескольких? Окей, допустим.




Но почему:




...
      containers:
        - name: {{ .Chart.Name }}
...




Без кавычек, если документация говорит их использовать? Потому что это данные из Chart.yaml, а не values.yaml?




В чём принципиальная разница?




Ну и сам YAML, как всегда – “радует”, читаем в той же документации по Values – Make Types Clear:




YAML’s type coercion rules are sometimes counterintuitive. For example, foo: false is not the same as foo: “false”. Large integers like foo: 12345678 will get converted to scientific notation in some cases.The easiest way to avoid type conversion errors is to be explicit about strings, and implicit about everything else. Or, in short, quote all strings.




Мрак!




Ладно – в values.yaml стринги заключаем в кавычки, целочисленные – без кавычек.




В файле шаблонов… Я не знаю 




Использовать quote – тогда само значение в переменных будет с кавычками. Посмотрел, как приложение запущено сейчас – без кавычек:




kk -n bttrm-apps-stage-ns describe pod bttrm-apps-stage-7c5cfd9698-tkmjp | grep CLIENT_HOST
CLIENT_HOST:                          https://test.example.com




Значит пока без quote, и без явного указания “” в шаблоне вообще.




(у нас тут Stage, который pre-Dev даже)




values.yaml




Получается такой файл:




replicaCount: 2
    
image:
  repository: "bttrm"
  name: "bttrm-apps"
  tag: ""
# backend app config
backendConfig:
  clientHost: "https://test.example.com"
  nodeEnv: "dev"
  host: "https://test.api.example.com"
  port: 3001
  database:
    host: "stage.aurora.example"
    user: "dbuser"
    password: "dbpass"
    connection: "mysql"
    port: 3306




Passwords… Secrets…




Пароли пока хардкодим – потом будем передавать из Credentials parameter в Jenkins-джобе.




А ещё лучше – таки добавить helm secrets – но это потом (добавлено – см. Helm: helm-secrets — шифрование sensitive данных с AWS KMS и деплой из Jenkins)




Секреты




Так, секреты.




В деплойменте передаём секретами, секреты создаём из файла bttrm-apps-secrets.yaml.




Сейчас он выглядит так же, как деплоймент – обрабатывается с sed в старой джобе Jenkins:




---
apiVersion: v1
kind: Secret
metadata:
  name: bttrm-app-secret
type: Opaque
stringData:
  backend-db-password: DB_PASSWORD_VAL
...




В Деплойменте маунтим из секретов:




...
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: {{ .Values.image.repository }}/{{ .Values.image.name }}:{{ .Values.image.tag }}
        env:
        ...
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: bttrm-app-backend-secret
              key: backend-db-password
...




Обновляем секрет – передаём из values:




--- 
apiVersion: v1
kind: Secret
metadata:
  name: bttrm-app-backend-secrets
type: Opaque
stringData:
  backend-db-password: {{ .Values.backendConfig.db.password }}
  backend-apple-cert-passphrase: {{ .Values.backendConfig.apple.certPassphrase }}
  backend-apple-sigin-key-id: {{ .Values.backendConfig.apple.signInKeyID }}




chart install




Ну и что – пробуем?




helm install --debug bttrm-apps-backend-release bttrm-apps-backend
install.go:159: [debug] Original chart version: ""
install.go:176: [debug] CHART PATH: /home/setevoy/Work/landing-backend/k8s/bttrm-apps-backend
client.go:108: [debug] creating 6 resource(s)
Error: Deployment in version "v1" cannot be handled as a Deployment:
v1.Deployment.Spec: v1.DeploymentSpec.Template: v1.PodTemplateSpec.Spec: v1.PodSpec.Containers: []v1.Container: v1.Container.Env: []v1.EnvVar: v1.EnvVar.Value:
ReadString: expects " or n, but found 3, error found in #10 byte of ...|,"value":3001}




Ах ты ж…




Вот честно – я тут очень матерился.




Может я не догоняю чего-то, но ты же мне везде в документации говоришь, что Integer без кавычек кушаешь нормально?




Что ж ты теперь ругаешься на цифры?




Про то, как Go вообще ошибки выводит промолчим – в них часто сложно что-то понять.




Но тут в принципе видно значение, вызвавшее ошибку – 3001:




v1.PodSpec.Containers: []v1.Container: v1.Container.Env: []v1.EnvVar: v1.EnvVar.Value: ReadString: expects ” or n, but found 3, error found in #10 byte of …|,”value”:3001}




Непонятно, конечно, где именно – но так как порты в деплойменте встречаются не так часто – то просто добавляем кавычки для всех, меняем:




...
        - name: DB_PORT
          value: {{ .Values.backendConfig.port }} 
...




На:




...
        - name: DB_PORT
          value: {{ .Values.backendConfig.db.port | quote }}
...




При этом в ports: - containerPort: на кавычки он ругается.




А в livenessProbe: port: при --dry-run не ругается. А при install – ругается.




Рукалицо. Ладно.




Деплоим ещё раз:




helm install --debug bttrm-apps-backend-release bttrm-apps-backend/
install.go:159: [debug] Original chart version: ""
install.go:176: [debug] CHART PATH: /home/setevoy/Work/landing-backend/k8s/bttrm-apps-backend
client.go:108: [debug] creating 6 resource(s)
NAME: bttrm-apps-backend-release
LAST DEPLOYED: Sun May 10 14:35:37 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
...




Йай!




Проверяем:




helm ls
NAME                    NAMESPACE       REVISION        UPDATED                                         STATUS          CHART                   APP VERSION
bttrm-apps-backend-release   default         1               2020-05-10 14:35:37.364401788 +0300 EEST        deployed        bttrm-apps-backend-0.1.0     1.16.0




Ну – бимба!




Оно 100% не работает, но нам важен сам файкт, что оно задеплоилось:




kk get pod
NAME                                 READY   STATUS    RESTARTS   AGE
bttrm-apps-backend-c4d8f8c5d-98vd2   1/1     Running   0          54s
bttrm-apps-backend-c4d8f8c5d-v6slt   1/1     Running   0          54s
...




Хорошо.




Удаляем, передеплоим в нормальный НС:




helm uninstall bttrm-apps-backend-release
release "bttrm-apps-backend-release" uninstalled




Деплоим ещё раз, указываем --create-namesapce:




helm install bttrm-apps-backend-release bttrm-apps-backend/ --namespace bttrm-apps-dev-1-ns --create-namespace
NAME: bttrm-apps-backend-release
LAST DEPLOYED: Sun May 10 14:45:23 2020
NAMESPACE: bttrm-apps-dev-1-ns
STATUS: deployed
REVISION: 1
TEST SUITE: None




Проверяем:




kk -n bttrm-apps-dev-1-ns get po
NAME                                READY   STATUS    RESTARTS   AGE
bttrm-apps-backend-6c54d5c676-5j6mc   0/1     Pending   0          47s
bttrm-apps-backend-6c54d5c676-vchvh   0/1     Pending   0          47s




Супер, но почему Pending?




Что-то с реквестами, наверно?




Глянем events:




kk -n bttrm-apps-dev-1-ns get event
LAST SEEN   TYPE      REASON                         OBJECT                                      MESSAGE
7s          Warning   FailedScheduling               pod/bttrm-apps-backend-6c54d5c676-5j6mc       0/8 nodes are available: 8 Insufficient cpu.
10s         Normal    NotTriggerScaleUp              pod/bttrm-apps-backend-6c54d5c676-5j6mc       pod didn't trigger scale-up
(it wouldn't fit if a new node is added): 4 Insufficient cpu




А почему?




В values.yaml 500 CPU requests, WorkerNodes у нас на ЕС2 t3.medium – у каждого 2000 CPU юнитов…




Проверим реквесты:




kk -n bttrm-apps-dev-1-ns describe pod bttrm-apps-backend-6c54d5c676-5j6mc
Name:           bttrm-apps-backend-6c54d5c676-5j6mc
Namespace:      bttrm-apps-dev-1-ns
...
Host Port:  0/TCP
Requests:
cpu:      500
...




Да, вроде всё верно.




Или реквесты криво описал…




Что там… Как они задаются вообще, где дока?




Вот тут вроде было толково – https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-resource-requests-and-limits.




Хм…




Кавычки и m?




Редактируем values – вместо 500 указываем “500m”:




...
resources:
  requests:
    cpu: "500m"
...




И добавим quote в деплоймент:




...

        resources:

          requests:

            cpu: {{ .Values.resources.requests.cpu | quote }} 

...




Пробуем:




helm upgrade bttrm-apps-backend-release bttrm-apps-backend/ --namespace bttrm-apps-dev-1-ns

Release "bttrm-apps-backend-release" has been upgraded. Happy Helming!

NAME: bttrm-apps-backend-release

LAST DEPLOYED: Sun May 10 14:54:57 2020

NAMESPACE: bttrm-apps-dev-1-ns

STATUS: deployed

REVISION: 2

TEST SUITE: None




Евенты:




kk -n bttrm-apps-dev-1-ns get event

LAST SEEN   TYPE      REASON                         OBJECT                                      MESSAGE

47s         Normal    Scheduled                      pod/bttrm-apps-backend-69d74849df-nvtt2       Successfully assigned bttrm-apps-dev-1-ns/bttrm-apps-backend-69d74849df-nvtt2 to ip-10-3-33-123.us-east-2.compute.internal

15s         Warning   FailedMount                    pod/bttrm-apps-backend-69d74849df-nvtt2       MountVolume.SetUp failed for volume "apple-keys" : secret "apple-keys" not found

15s         Warning   FailedMount                    pod/bttrm-apps-backend-69d74849df-nvtt2       MountVolume.SetUp failed for volume "apple-certificates" : secret "apple-certificates" not found

47s         Normal    SuccessfulCreate               replicaset/bttrm-apps-backend-69d74849df      Created pod: bttrm-apps-backend-69d74849df-nvtt2

...




Ага!




Всё создалось.




Теперь поды не стартуют, потому что не файлов сертификатов для Apple – но это уже детали, сейчас их создадим.




Helm secrets from files




Добавим файлы сертификата – в Jenkins они будут маунтиться из Credentials типа Secret file, тут добавляем в текущий репозиторий:




ll bttrm-apps-be/secrets/

total 12

-rw-r--r-- 1 setevoy setevoy  258 May 10 17:32 AppleAuth.key.p8

-rw-r--r-- 1 setevoy setevoy 3088 May 10 17:27 ApplePay.crt.pem

-rw-r--r-- 1 setevoy setevoy 2006 May 10 17:28 ApplePay.key.pem




Добавляем в ../.gitignore репозитория и в .helmignore чарта:




...

k8s/bttrm-apps-backend/secrets/




Обновляем bttrm-apps-secrets.yaml – используем Files, см https://helm.sh/docs/chart_template_guide/accessing_files/:




...

---

apiVersion: v1

kind: Secret

metadata:

  name: apple-certificates

type: Opaque

data:

  ApplePay.crt.pem: {{ .Files.Get "secrets/ApplePay.crt.pem" | b64enc }}

  ApplePay.key.pem: {{ .Files.Get "secrets/ApplePay.key.pem" | b64enc }}

---

apiVersion: v1

kind: Secret

metadata:

  name: apple-key

type: Opaque

data:

  AppleAuth.key.p8: {{ .Files.Get "secrets/AppleAuth.key.p8" | b64enc }}




Запускаем:




helm upgrade bttrm-apps-be-release bttrm-apps-be/ --namespace bttrm-apps-dev-1-ns

Release "bttrm-apps-be-release" has been upgraded. Happy Helming!

NAME: bttrm-apps-be-release

LAST DEPLOYED: Sun May 10 17:36:47 2020

NAMESPACE: bttrm-apps-dev-1-ns

STATUS: deployed

REVISION: 4

TEST SUITE: None




Проверяем секреты:




kk -n bttrm-apps-dev-1-ns get secret

NAME                                          TYPE                                  DATA   AGE

apple-certificates                            Opaque                                2      37s

apple-key                                     Opaque                                1      37s




Но поды серты не увидели, и не запустилиись, так и будут висеть в FailedMount.




Пересоздаём их – вызываем upgrade с --recreate-pods:




helm upgrade bttrm-apps-be-release bttrm-apps-be/ --namespace bttrm-apps-dev-1-ns --recreate-pods

Flag --recreate-pods has been deprecated, functionality will no longer be updated. Consult the documentation for other methods to recreate pods

Release "bttrm-apps-be-release" has been upgraded. Happy Helming!

NAME: bttrm-apps-be-release

LAST DEPLOYED: Sun May 10 17:39:39 2020

NAMESPACE: bttrm-apps-dev-1-ns

STATUS: deployed

REVISION: 5

TEST SUITE: None




Проверяем:




helm -n bttrm-apps-dev-1-ns ls

NAME                    NAMESPACE               REVISION        UPDATED                                         STATUS          CHART                   APP VERSION

bttrm-apps-be-release   bttrm-apps-dev-1-ns     2               2020-05-10 17:44:56.505478002 +0300 EEST        deployed        bttrm-apps-be-0.1.0     1.16.0

kk -n bttrm-apps-dev-1-ns get pod

NAME                                READY   STATUS    RESTARTS   AGE

bttrm-apps-be-dp-6f86d5c7d7-k4rjm   1/1     Running   0          2m

bttrm-apps-be-dp-6f86d5c7d7-ztcvp   1/1     Running   0          83s




Тут готово.




.dockerconfigjson




Сейчас в секретах файла bttrm-apps-secrets.yaml значение для .dockerconfigjson задан хардкодом:




--- 

apiVersion: v1

kind: Secret

metadata:

  creationTimestamp: null

  name: bttrm-docker-secret

type: kubernetes.io/dockerconfigjson

data:

  .dockerconfigjson: eyJhdXRo[...]

...




Находим пример в документации – Creating Image Pull Secrets.




Обновляем values.yaml – в блок image добавляем registryusername и password, пароль позже будем передавать из Jenkins:




...

image:

  registry: "docker.io" 

  username: "username"

  password: "pass"

  repository: "project"

  name: "bttrm-apps"

  tag: "120"

...




Создаём templates/_helpers.tpl, см. Nested template definitions.




Копируем функцию из примера в Creating Image Pull Secrets, меняем .Values.imageCredentials на наш .Values.image:




{{- define "imagePullSecret" }}

{{- printf "{"auths": {"%s": {"auth": "%s"}}}" .Values.image.registry (printf "%s:%s" .Values.image.username .Values.image.password | b64enc) | b64enc }}

{{- end }}




Обновляем секреты – вместо хардкод-строки в base64 вызываем этот самый {{ template "imagePullSecret" . }}:




--- 

apiVersion: v1

kind: Secret

metadata:

  creationTimestamp: null

  name: bttrm-docker-secret

type: kubernetes.io/dockerconfigjson

data:

  .dockerconfigjson: {{ template "imagePullSecret" . }} 

...




Передеплоиваем для проверки, и если всё ОК – то можно приступать в Jenkins.




Jenkins




Поехали к сиаю.




Что нам надо?




Сначала давай подумаем про шаги, которые надо выполнить в джобе:




  1. склонировать репозиторий приложения с helm-чартом, кодом приложения и докерфайлом
  2. билд образа – тегаем Jenkins $BUILD_NUMBER + $GIT_COMMIT
  3. docker push собранного образа, пока в DockerHub
  4. упаковка релиза + задать номера релиза и AppVersion, AppVersion == Docker Tag. т.е. $BUILD_NUMBER + $GIT_COMMIT
    1. позже – релиз в Гитхаб
  5. сгенерить кубконфиг
  6. выполнить helm install




Версинирование




Тут, конечно, по желанию каждого.




Мне пока в голову пришла такая схема:




  • chart release number == Jenkins $BUILD_NUMBER джобы
  • AppVersion == $BUILD_NUMBER + $GIT_COMMIT
  • Docker image tag == $BUILD_NUMBER + $GIT_COMMIT




Неймспейсы опять (снова?)




Что там с НС-ами было?




Давайте вспоминать – день четвёртый, на самом деле.




Хочется давать на выбор три варианта:




  1. дефолтный неймпейс – APP_NAME + CLUSTER_ENV + “NS”, т.е. поулчим bttrm-apps-dev-1ns
  2. неймспейс с именем бранча – APP_NAME + CLUSTER_ENV + GIT_BRANCH_NAME + “NS”, т.е. bttrm-apps-dev-1-WLIOS-5848-Projects-deployments
  3. кастомный неймспейс, задаётся юзером




Есть сомнения по второму пункту – bttrm-apps-dev-1-WLIOS-5848-Projects-deployments – не слишком ли длинно?




Загуглим “kubernetes namespace best practices”, но лучшее, что нашлось – это вот эта запись в блоге, в которой говорится:




An easy to grasp anti-pattern for Kubernetes namespaces is versioning. You should not use Namespaces as a way to disambiguate versions of your Kubernetes resources




Ну и ладно – версии в НС мы включать и не думали.




Но подсказали в Kubernetes Slack:




Alan J Castonguay  3 days ago




Namespace names are DNS1123 Labels: maximum 63 characters

You may want to populate generateName with a prefix, and let kubernetes make a unique suffix.




Хорошо – раз лимит в 63 символа – мы можем в дженкисфайле добавить хендлер, который будет проверять имя неймспейса, переданного из Jenkins-парамтеров, и при необходимости обрезать его.




Про удаление НС-ов – потом, потом…




Тестирование





https://dzone.com/articles/easily-automate-your-cicd-pipeline-with-jenkins-he




Хорошая идея запускать тесты во время билда/деплоя – сначала какие-то юнит-тесты после сборки Docker-образа, потом – smoke-тесты после деплоя.




Но добавим потом – достаточно будет дописать функции на их вызов, пока задача запустить билд-деплой вообще.




Поехали?




Jenkins job




Создаём новую джобу, тип пайплайн:





Будем использовать Jenkins Scripted Pipelines.




Теперь поехали по шагам, которые напланировали выше.




Jenkins job stages




Init stage




Начнём с такого себе init-стейджа, который будет клонировать репозиторий с кодом, настраивать kubectl, и определять общие параметры и переменные.




Что нам в нём надо выполнить?




  • клонируем репозиторий
  • генерируем kubeconfig
  • вызываем kubctl cluster-info – для проверки kubeconfig
  • вызываем helm version – для проверки Helm вообще
  • задаём параметры:
    • release version – $BUILD_NUMBER, получаем из самого Jenkins
    • Docker Tag: будет $BUILD_NUMBER + $GIT_COMMIT, приходит в джобу из Git plugin после чекаута
    • AppVersion – $BUILD_NUMBER + $GIT_COMMIT, приходит в джобу из Git plugin после чекаута




Получается такой код:




node {

    docker.image('bttrm/kubectl-aws:4.0').inside('-v /var/run/docker.sock:/var/run/docker.sock') {

        stage('Init') {

            

            gitenv = git branch: "master",

                         credentialsId: 'jenkins-github',

                         url: 'git@github.com:example-org/bttrm-apps-backend.git'

        

            GIT_COMMIT_SHORT = gitenv.GIT_COMMIT.take(8)            

        

            RELEASE_VERSION = "${BUILD_NUMBER}"

            DOCKER_TAG = "${BUILD_NUMBER}.${GIT_COMMIT_SHORT}"

            APP_VERSION = "${BUILD_NUMBER}.${GIT_COMMIT_SHORT}"

            

            echo "DOCKER_TAG == ${DOCKER_TAG}"

            echo "APP_VERSION == ${APP_VERSION}"

            echo "RELEASE_VERSION == ${RELEASE_VERSION}"                

                

            sh "aws eks update-kubeconfig --region us-east-2 --name bttrm-eks-dev-1"

            sh "kubectl cluster-info"

            sh "helm version"

            sh "helm -n bttrm-apps-dev-1-ns ls "

        }

    }

}




Весь билд будет выполняться нашим кастомным Docker-образом kubectl-aws, собирается из такого Dockerfile:




FROM bitnami/minideb:stretch

RUN apt update && install_packages ca-certificates wget

RUN install_packages curl python-pip python-setuptools jq git

RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl

RUN chmod +x ./kubectl

RUN mv ./kubectl /usr/local/bin/kubectl

WORKDIR /tmp

RUN curl  --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp

RUN mv /tmp/eksctl /usr/local/bin 

RUN pip install ansible boto3 awscli

WORKDIR /tmp

RUN curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3

RUN /bin/bash get_helm.sh

USER root




Пока все значения тпиа Github URL и имени бранча в скрипте билда хардкодим – потом вынесем в параметры джобы.




Запускаем, проверяем – всё работает.




Пошли дальше.




Docker build




Далее нам надо собрать Docker-образ, и запушить его в репозиторий.




Добавлять ли тег latest? Вопрос.




Наверно нет – билдов может быть много, из разных бранчей – перезаписывать каждый раз latest смысла нет, тем более деплоится в Dev окружение всё будет автоматом при создании пул-реквестов, см. Jenkins: Github Pull-Request Builder плагин.




Значит – делаем только docker build с тегом из переменной $DOCKER_TAG.




Создаём данные доступа для DockerHub:





Добавляем новый стейдж “Docker build”, в нём с помощью Docker-плагина для Jenkins собираем образ, для логина в DockerHub через credentialsId передаём созданные выше данные:




node {

    docker.image('bttrm/kubectl-aws:4.0').inside('-v /var/run/docker.sock:/var/run/docker.sock') {

        stage('Init') {

            ...            

        }

        

        stage("Docker build") {

            

            withDockerRegistry(registry: [credentialsId: 'bttrm-docker-hub']){

                docker.build("bttrm/bttrm-apps:${DOCKER_TAG}").push()

            }

        }

    }

}




Запускаем, проверяем, всё работает?




Хорошо, что дальше?




helm package




Дальше генерируем пакет. Пока надо только для того, что бы можно было задать release verion и app-version. Позже хочется добавить их пуш куда-то в репозиторий – или Github, или S3-backended.




...

        stage("Helm package") {

            

            sh "helm package k8s/bttrm-apps-be --version ${RELEASE_VERSION} --app-version ${APP_VERSION}"

        }

...




Запускаем – докер-образ собрался, локальный пакет хельм-чарта собрался – всё хорошо:




...

4d1ab3827f6b: Layer already exists

5.872a4dc3: digest: sha256:558e3b0ec0a7c5fc6302adca8321de2a3ee75656202930dcb979960d49273c0b size: 4089

[Pipeline] }

[Pipeline] // withDockerRegistry

[Pipeline] }

[Pipeline] // stage

[Pipeline] stage

[Pipeline] { (Helm package)

[Pipeline] sh

+ helm package k8s/bttrm-apps-backend --version 5 --app-version 5.5.872a4dc3

Successfully packaged chart and saved it to: /var/lib/jenkins/workspace/DO_EKS/Deployments/bttrm-apps/bttrm-apps-TEST/bttrm-apps-backend-5.tgz

[Pipeline] }

[Pipeline] // stage

[Pipeline] }

docker stop --time=1 023b7970d36e20b85912062b35bc7aa4136af7807b975a373c655c0cf38a6010

docker rm -f 023b7970d36e20b85912062b35bc7aa4136af7807b975a373c655c0cf38a6010

[Pipeline] // withDockerContainer

[Pipeline] }

[Pipeline] // node

[Pipeline] End of Pipeline

Finished: SUCCESS




Дальше – собственно деплой приложения.




helm install




Ну и деплоим – добавляем создание Namespace.




Сам неймспейс пока ставим дефолтный.




Можно добавить --atomic, что бы удалять зафейлившиеся деплои:




...

        stage("Helm install") {

            

            sh "helm install --atomic bttrm-apps-be bttrm-apps-be-${RELEASE_VERSION}.tgz"

        }




Запускаем, и:




...

[Pipeline] { (Helm install)

[Pipeline] sh

+ helm install --atomic bttrm-apps-backend bttrm-apps-backend-6.tgz

Error: unable to build kubernetes objects from release manifest: error validating "": error validating data:

[unknown object type "nil" in Secret.data.ApplePay.crt.pem, unknown object type "nil" in Secret.data.ApplePay.key.pem]

[Pipeline] }

[Pipeline] // stage

[Pipeline] }

docker stop --time=1 fa1e59d52af1c622d5122ddc8db25b72e5e2afff82a211f077fd8c3a8d1a48bb

docker rm -f fa1e59d52af1c622d5122ddc8db25b72e5e2afff82a211f077fd8c3a8d1a48bb

[Pipeline] // withDockerContainer

[Pipeline] }

[Pipeline] // node

[Pipeline] End of Pipeline

ERROR: script returned exit code 1

Finished: FAILURE




Ага, ну да – секреты в репозиторий мы не добавляли, они заигнорены через .gitignore, и должны мапится из Secret file самой джобы.




Собственно – пора добавить и параметры.




Job parameters




Посмотрим на весь скрипт, который у нас уже получился:




node {

    docker.image('bttrm/kubectl-aws:4.0').inside('-v /var/run/docker.sock:/var/run/docker.sock') {

        stage('Init') {

            

            gitenv = git branch: "WLIOS-5848-Projects-deployments",

                         credentialsId: 'jenkins-github',

                         url: 'git@github.com:example-org/bttrm-apps-backend.git'

        

            GIT_COMMIT_SHORT = gitenv.GIT_COMMIT.take(8)            

        

            RELEASE_VERSION = "${BUILD_NUMBER}"

            DOCKER_TAG = "${BUILD_NUMBER}.${GIT_COMMIT_SHORT}"

            APP_VERSION = "${BUILD_NUMBER}.${DOCKER_TAG}"

            

            echo "DOCKER_TAG == ${DOCKER_TAG}"

            echo "APP_VERSION == ${APP_VERSION}"

            echo "RELEASE_VERSION == ${RELEASE_VERSION}"                

                

            sh "aws eks update-kubeconfig --region us-east-2 --name bttrm-eks-dev-1"

            sh "kubectl cluster-info"

            sh "helm version"

            sh "helm -n bttrm-apps-dev-1-ns ls "

        }

        

        stage("Docker build") {

            

            withDockerRegistry(registry: [credentialsId: 'bttrm-docker-hub']){

                docker.build("bttrm/bttrm-apps:${DOCKER_TAG}").push()

            }

        }

        

        stage("Helm package") {

            

            sh "helm package k8s/bttrm-apps-backend --version ${RELEASE_VERSION} --app-version ${APP_VERSION}"

        }

        

        stage("Helm install") {

            

            sh "helm install --atomic bttrm-apps-backend bttrm-apps-backend-${RELEASE_VERSION}.tgz"

        }

    }

}




Что из этого надо вынести в параметры, и в какие?




Собственно – почти всё надо выносить в параметры джобы, потому что это же скрипт будет использоваться для деплоя аналогичных проектов.




Пока сделаем:




  • репозиторий проекта – String parameter
  • бранч проекта – String parameter
  • регион для aws eks update-kubeconfig – можно задать в скрипте, вряд ли кто-то будет деплоить в кластера в других регионах (хотя Jenkins-джоба для создания кластеров в любом регионе есть, см. AWS Elastic Kubernetes Service: — автоматизация создания кластера, часть 2 — Ansible, eksctl)
  • имя кластера для создания kubeconfig – в параметры джобы, String parameter
  • namespace – пока сделаем один, дефолтный – выносим в параметр джобы, Choice parameter
  • имя чарта – String parameter





Добавляем секретные файлы.




Выбираем тип Credentials parameter, тип Secret file:





Либо, если ключи для Dev/Stage/Prod одинаковые – то не выносить их в параметры, а сразу использовать в скрипте.




Теперь нам надо замапить эти ключи в контейнер во время билда, см. Jenkins: Credentials Binding Plugin и использование нескольких Secret file в Jenkins pipeline.




Получается такой скрипт:




node {

    docker.image('bttrm/kubectl-aws:4.0').inside('-v /var/run/docker.sock:/var/run/docker.sock') {

        stage('Init') {

            

            gitenv = git branch: '${APP_REPO_BRANCH}',

                         credentialsId: 'jenkins-github',

                         url: '${APP_REPO_URL}'

        

            GIT_COMMIT_SHORT = gitenv.GIT_COMMIT.take(8)            

        

            RELEASE_VERSION = "${BUILD_NUMBER}"

            DOCKER_TAG = "${BUILD_NUMBER}.${GIT_COMMIT_SHORT}"

            APP_VERSION = "${BUILD_NUMBER}.${DOCKER_TAG}"

            AWS_EKS_REGION = "us-east-2"

            

            echo "DOCKER_TAG == ${DOCKER_TAG}"

            echo "APP_VERSION == ${APP_VERSION}"

            echo "RELEASE_VERSION == ${RELEASE_VERSION}"                

            

            sh "aws eks update-kubeconfig --region ${AWS_EKS_REGION} --name ${AWS_EKS_CLUSTER}"

            sh "kubectl cluster-info"

            sh "helm version"

            sh "helm -n ${AWS_EKS_NAMESPACE} ls "

        }

        

        stage("Docker build") {

            

            /*

            withDockerRegistry(registry: [credentialsId: 'bttrm-docker-hub']){

                docker.build("bttrm/bttrm-apps:${DOCKER_TAG}").push()

            }

            */

            echo "Docker build"

        }

        

        stage("Helm package") {

            dir("k8s") {

                sh "helm package ${APP_CHART_NAME} --version ${RELEASE_VERSION} --app-version ${APP_VERSION}"

            }

        }

        

        stage("Helm install") {

            

            dir("k8s") {

                

                withCredentials([

                    file(credentialsId: 'bttrm-apps.applepay.crt', variable: 'APPLEPAY_CERT'),

                    file(credentialsId: 'bttrm-apps.applepay.key', variable: 'APPLEPAY_KEY'),

                    file(credentialsId: 'bttrm-apps.appleauth.key', variable: 'APPLEAUTH_KEY'),

                    ]) {

                    

                    sh "test -d bttrm-apps-backend/secrets || mkdir bttrm-apps-backend/secrets"

                    sh "cp $APPLEPAY_CERT bttrm-apps-backend/secrets/ApplePay.crt.pem"

                    sh "cp $APPLEPAY_KEY bttrm-apps-backend/secrets/ApplePay.key.pem"

                    sh "cp $APPLEAUTH_KEY bttrm-apps-backend/secrets/AppleAuth.key.p8"

                    

                    sh "helm install --namespace ${AWS_EKS_NAMESPACE} --create-namespace --atomic ${APP_CHART_NAME} ${APP_CHART_NAME}-${RELEASE_VERSION}.tgz"

                }

            }

        }

    }

}




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




Тут в Helm install мы:




  1. переходим в каталог k8s репозитория
  2. проверяем наличие каталога bttrm-apps-backend/secrets, если его нет – создаём
  3. из Jenkins Credentials создаём три файла ключей
  4. и выполняем установку чарта




Параметры при запуске выглядят так:





Запускаем, проверяем:





Супер!




“It works!” (c)




Helm: “Error: cannot re-use a name that is still in use”




Но – если мы запустим билд повторно – он уже сфейлится с ошибкой “Error: cannot re-use a name that is still in use“:





Ожидаемо – раз уже есть задплоенный резил с таким именем – Helm не будет его перезаписывать.




Тут достаточно просто заменить install на helm upgrade --install:





В целом-то это всё…




Что осталось ещё?







Но пока, думаю, хватит.




helm upgrade – resource cannot be imported into the current release




P.S. Когда добавлял RBAC-роль – то при апдейте получил ошибку:




helm upgrade --install --namespace bttrm-apps-dev-1-ns --create-namespace --atomic bttrm-apps-backend bttrm-apps-backend-17.tgz

Error: UPGRADE FAILED: rendered manifests contain a resource that already exists. Unable to continue with update:

RoleBinding "rbac-bttrm-web-apps-ro-role-binding" in namespace "bttrm-apps-dev-1-ns" exists and cannot be imported into the current release:

invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by":

must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "bttrm-apps-backend";

annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "bttrm-apps-dev-1-ns"




Собственно, это к тому, что Helm задаёт аннотации и лейблы сам – но есть смысл добавлять их в шаблоны манифестов:




kk -n bttrm-apps-dev-1-ns get rolebinding rbac-bttrm-web-apps-ro-role-binding -o yaml

apiVersion: rbac.authorization.k8s.io/v1

kind: RoleBinding

metadata:

annotations:

meta.helm.sh/release-name: bttrm-apps-backend

meta.helm.sh/release-namespace: bttrm-apps-dev-1-ns

creationTimestamp: "2020-05-14T16:02:42Z"

labels:

app.kubernetes.io/managed-by: Helm

...




Такие дела.




Источник: https://rtfm.co.ua/helm-poshagovoe-sozdanie-charta-i-deplojmenta-iz-jenkins/



2022-08-08T20:57:39
DevOps

Как диагностировать проблемы соединения в Kubernetes при помощи Mizu

Стоит попробовать Mizu – это ПО для мониторинга Kubernetes-трафика. Программа может сильно упростить ежедневную диагностику сетей, да и жизнь в целом.




Одна из наиболее частых задач, с которыми сталкиваются администраторы Kubernetes по ходу тестирования и дебаггинга – проверка коммуникаций между компонентами внутри сети. 




Если вы хоть как-то взаимодействуете c Kubernetes по работе, то наверняка частенько проверяете входящий трафик, чтобы изучить входящие запросы и т.п. Обычно задачи подобного рода решаются при помощи утилиты tcpdump, установленной в конкретный контейнер. Таким образом, проверяются некоторые сетевые аспекты вне контейнеров, но иногда такой подход оказывается довольно сложным из-за специфики окружения или конфигурации системы. 




Чтобы не натыкаться на кучу проблем по ходу мониторинга сети, советую использовать утилиту Mizu. Многие программисты, работающие с Kubernetes, мечтали бы найти подобный инструмент раньше.




Mizu можно описать как простой, но при этом мощный инструмент для отслеживания трафика в Kubernetes. Он позволяет отслеживать все API-коммуникации между микросервисами независимо от используемого протокола и упрощает процесс дебаггинга соединений.




Установка Mizu




Процесс установки довольно простой. Все что нужно – загрузить бинарный файл Mizu и настроить соответствующие разрешения в системе. Выбор бинарного файла (установщика) зависит от архитектуры устройства. Например, чтобы установить Mizu на компьютер Apple с чипом Intel нужно ввести в терминал команду:




‌curl -Lo mizu github.com/up9inc/mizu/releases/latest/download/mizu_darwin_amd64 && chmod 755 mizu && mv mizu /usr/local/bin




Обычно этого достаточно. Загруженный бинарный файл теперь можно использовать для подключения к кластеру Kubernetes и работы с Kubernetes API, но для этого нужно внести несколько изменений в настройки Докера. 




Вот как это может выглядеть в случае с базовым nginx-сервером. Начать стоит с команды:




‌kubectl run simple-app --image=nginx --port 3000




После развертки базового приложения на основе nginx переходим непосредственно к запуску Mizu. Делается это всего одной командой:




mizu tap




Через пару секунд на экране появится веб-страница с интерфейсом Mizu. Здесь и отображается весь трафик на выбранном сервере. Но для настройки такого поведения необходимо внести изменения в параметры портов. К примеру, если ваше приложение называется ‘my-app’, команда будет выглядеть так:




kubectl expose pod/my-app




После этого деплоим еще один временный сервер, используя готовый образ (при помощи следующей команды):




kubectl run -it --rm --image=curlimages/curl curly -- sh




Теперь можно использовать утилиту curl для отправки запросов непосредственно на nginx-сервер. Например, так:




curl -vvv http://my-app:3000




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




Конечно, Mizu не сможет заменить более сложные продукты и полноценные системы наблюдения за сетью. Но это довольно удобный инструмент, который поможет вам исправить немало багов по ходу работы с Kubernetes, и его точно стоит иметь под рукой.




Источник: https://te.legra.ph/Kak-diagnostirovat-problemy-soedineniya-v-Kubernetes-pri-pomoshchi-Mizu-07-09



2022-08-07T23:59:02
DevOps