Некоторая предыстория

Мою жизнь в сфере надежности сайта можно описать как идеальный коктейль из автоматизации зданий, реактивного решения проблем и… размещения ссылок позвольте мне погуглить для вас на каналах Slack. Одна из основных тем - выяснить, как мы масштабируемся в соответствии с требованиями клиентов. В настоящее время в LogicMonitor мы запускаем гибридную среду, в которой наше основное приложение, а также базы данных временных рядов работают на серверах в наших физических центрах обработки данных. Эти среды взаимодействуют с микросервисами, работающими в AWS. Мы назвали одну из этих гибридных производственных сред pod (что, оглядываясь назад, было неудачным выбором после того, как мы представили Kubernetes). Мы используем продукт Atlassian Bamboo для CI / CD.

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

Развертывание на k8s

Наш процесс развертывания заключался в использовании Helm из Bamboo. Каждое построенное приложение будет создавать артефакт диаграммы управления и образ докера. После развертывания образ помещается в частный репозиторий докеров, и запускается команда установки helm с соответствующими диаграммами. Однако, поскольку каждая производственная среда считалась пространством имен Kubernetes, нам нужно было выполнить развертывание в нескольких пространствах имен для каждого кластера, что было задано с помощью индивидуального плана развертывания Bamboo для каждого пространства имен для каждого приложения. На сегодняшний день у нас есть 50 различных производственных сред и 8 микросервисов (для математиков это 400 индивидуальных планов развертывания). Иногда, только для одной версии приложения, разработчику может потребоваться больше часа или двух, чтобы развернуть и проверить всю производственную среду.

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

Так что пути нет… если мы хотим эффективно масштабировать инфраструктуру, нам нужно найти более разумный способ развертывания. В настоящее время мы используем различные сценарии оболочки, которые запускают процесс развертывания. Чтобы создать новый инструмент, он должен:

  • Уметь запрашивать и перечислять все производственные пространства имен
  • Интегрируйте библиотеки helm / kubernetes
  • Разверните сразу в нескольких пространствах имен.
  • Централизованные журналы для прогресса развертывания

Представляем k8sdeploy

K8sdeploy - это инструмент на основе Go, написанный с целью создания cli, который использует клиентские библиотеки helm и kubernetes для одновременного развертывания в нескольких пространствах имен.

Инициализация:
Это создает клиент Helm и клиент для Kubernetes . Текущий пример ниже для helmv2. Кардинальные изменения в helm3 позволяют helm напрямую взаимодействовать с сервером api k8s напрямую через kubeconfig.

// GetKubeClient generates a k8s client based on kubeconfig
func GetKubeClient(kubeconfig string) (*kubernetes.Clientset, error) {
 config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) 
 if err != nil {  
   panic(err.Error()) 
 }  
 return kubernetes.NewForConfig(config)
}
//GetHelmClientv2 creates helm2 client based on kubeconfig
func GetHelmClientv2(kubeconfig string) *helm.Client {
 config, _ := clientcmd.BuildConfigFromFlags(“”, kubeconfig)
 client, _ := kubernetes.NewForConfig(config)
// port forward tiller (specific to helm2)
 tillerTunnel, _ := portforwarder.New(“kube-system”, client, config)
// new helm client
 host := fmt.Sprintf(“127.0.0.1:%d”, tillerTunnel.Local)
 helmClient := helm.NewClient(helm.Host(host))
 return helmClient
}

Shared Informer:
после того, как инструмент создает клиента, он инициализирует наблюдатель развертывания. Это общий информер, который следит за изменениями текущего состояния объектов Kubernetes. В нашем случае после развертывания мы создадим канал для запуска и остановки общего информера для ресурса ReplicaSet. Цель здесь - не только зарегистрировать статус развертывания (доступна 1 из 2 обновленных реплик), но и сопоставить всю информацию в одном потоке, что имеет решающее значение при развертывании сразу в нескольких пространствах имен.

factory := informers.NewSharedInformerFactory(clientset, 0)
//set informer to listen to pod resources
informer := factory.Core().V1().ReplicaSets().Informer()
stopper := make(chan struct{}) 
defer close(stopper)
// informer catches events when replicaSets are added or updated
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
   AddFunc:    func(obj interface{}) { 
     panic("not implemented") 
   },
   UpdateFunc: func(interface{}, interface{}) { 
     panic("not implemented") 
   },
})
go informer.Run(stopper)

Установка диаграммы с помощью Helm
После инициализации нашего deployWatcher инструмент использует библиотеки helm для инициализации установки / обновления развертывания с помощью диаграммы. Ниже приведен пример использования helm2 для обновления существующего развертывания. Вот - для helm3

resp, _ := helmClient.ReleaseStatus(deployName)
resp.GetInfo().GetStatus().GetCode().String() == "DEPLOYED" {
  fmt.Printf("Found existing deployment for %s...updating\n", deployName)
   helmClient.UpdateReleaseFromChart(deployName, chart)
}

Определение успеха
Добавлены несколько проверок, чтобы убедиться, что новое развертывание считается успешным. Мы указали наши диаграммы управления для обновления времени развертывания во время развертывания, чтобы сообщить информеру, что он должен регистрировать только новые события. Инструмент также проверяет, совпадают ли «готовые реплики» и «желаемые реплики», а также удостоверяется, что информер не улавливает другие события в случае, если несколько пользователей развертывают разные приложения. Инструмент добавляет все успешные развертывания в таблицу.

build	29-Jul-2020 19:23:20	Starting deployment in namespace=name-space-1 for app=customapp at 2020-07-29 19:23:20 -0700 PDT
build	29-Jul-2020 19:23:20	Waiting for deployment  rollout to finish: 0 of 2 updated replicas are available...
build	29-Jul-2020 19:23:20	Waiting for deployment  rollout to finish: 0 of 2 updated replicas are available...
build	29-Jul-2020 19:23:20	Starting deployment in namespace=name-space-2 for app=customapp at 2020-07-29 19:23:20 -0700 PDT
build	29-Jul-2020 19:23:20	Waiting for deployment  rollout to finish: 0 of 2 updated replicas are available...
build	29-Jul-2020 19:23:35	Waiting for deployment  rollout to finish: 1 of 2 updated replicas are available...
build	29-Jul-2020 19:23:35	Waiting for deployment  rollout to finish: 1 of 2 updated replicas are available...
build	29-Jul-2020 19:23:49	Waiting for deployment  rollout to finish: 1 of 2 updated replicas are available...
build	29-Jul-2020 19:23:56	Waiting for deployment  rollout to finish: 2 of 2 updated replicas are available...
build	29-Jul-2020 19:23:56	Successful Deployment of customapp on name-space-2
build	29-Jul-2020 19:23:58	Waiting for deployment  rollout to finish: 2 of 2 updated replicas are available...
build	29-Jul-2020 19:23:58	Successful Deployment of customapp on name-space-2
build	29-Jul-2020 19:24:10	All deployments finished, sutting down watcher gracefully
build	29-Jul-2020 19:24:10	+----------------+--------------+---------+
build	29-Jul-2020 19:24:10	| APP            | NAMESPACE    | STATUS  |
build	29-Jul-2020 19:24:10	+----------------+--------------+---------+
build	29-Jul-2020 19:24:10	| customapp      | name-space-1 | Success |
build	29-Jul-2020 19:24:10	| customapp      | name-space-2 | Success |
build	29-Jul-2020 19:24:10	+----------------+--------------+---------+

Собираем все вместе
На этом этапе у инструмента были элементы, созданные для одного пространства имен. Это быстро решается с помощью подпрограмм go для распараллеливания вызовов развертывания. Мы использовали Cobra для создания cli, где пользователи могут вводить пространства имен, разделенные запятыми.

k8sdeploy deploy kubeconfig --configpath <full-path-to-kubeconfig> --releasename <name-of-release> --namespace <namespace1,namespace2,namespace3> --chartdir <full-path-to-tgz-chart-file> --set <set-string-values>

Давайте с открытым исходным кодом

В настоящее время инструмент совместим с helm3. Я сделал его доступным для использования и публичной критики здесь.