Архив автора: admin

Kubernetes — пример использования RBAC

Начиная с Kubernetes 1.6, политики RBAC включаются по умолчанию. Политики RBAC имеют жизненно важное значение для правильного управления вашим кластером, поскольку они позволяют вам указывать, какие типы действий разрешены для конкретного пользователя и его роли в вашей организации.




Примеры включают:




  • Защиту кластера путем разрешения привилегированные действий (например, доступ к секретам) только администраторам.



  • Включение принудительной аутентификации пользователей в вашем кластере.



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



  • Разрешение пользователям просматривать ресурсы только в своем авторизованном пространстве имен, что позволяет изолировать ресурсы внутри вашей организации (например, между отделами или департаментами).




В следствие того, что в последних версиях Kubernetes RBAC включен по умолчанию, вы, возможно, уже обнаружили специфические ошибки при настройке решений по сетевой виртуализации (например, flunneld) или деплое Helm в вашем кластере. Обычно такие ошибки выглядят следующим образом:




the server does not allow access to the requested resource




ща рассмотрим как правильно работать с RBAC, чтобы вы могли решать такого рода проблемы.




API объекты RBAC




Одной из основных функций Kubernetes является то, что все его ресурсы представляют собой моделируемые API объекты, которые позволяют выполнять с ними операции CRUD (Create, Read, Update, Delete). Примерами ресурсов являются:




  • Pods



  • Deployments



  • Namespaces



  • Secrets



  • Replicasets



  • PersistentVolumes



  • ConfigMaps



  • Nodes




Примеры возможных операций над этими ресурсами:




  • create



  • get



  • delete



  • list



  • update



  • edit



  • watch



  • exec




Высокоуровневые ресурсы связаны с группами API (например, Pod относится к core группе API, а Deployments относятся к группе API apps). Дополнительные сведения обо всех доступных ресурсах, операциях и группах API см. в официальном справочнике API Kubernetes.




Для управления RBAC в Kubernetes, помимо ресурсов и операций, нам нужны следующие элементы:




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



  • Roles и ClusterRoles. Оба состоят из правил. Разница между Role и ClusterRole – это область применимости: в Role правила применимы к одному пространству имен, тогда как ClusterRole правила распространяются на весь кластер, поэтому правила применяются к нескольким пространствам имен. ClusterRoles также могут определять правила для ресурсов уровня кластера (например, узлы). Roles и ClusterRoles мапятся на API ресурсы внутри нашего кластера.



  • Subjects. Субъекты соответствуют объектам, которые пытаются выполнить операции в кластере. Существует три типа субъектов:



  • User Accounts (учетные записи пользователей): глобальны и предназначены для людей или процессов, живущих вне кластера. В кластере Kubernetes нет связанного с этим субъектом объекта API ресурса.



  • Service Accounts (учетные записи служб). Этот вид учетной записи предназначен для внутрикластерных процессов, запущенных в Pod-ах вашего кластера, которым необходимо получить доступ к API кластера.



  • Groups (группы). Группы используется для ссылки на сразу несколько учетных записей.Некоторые группы, такие как cluster-admin (объясняется в последующих разделах), создаются по умолчанию.



  • RoleBindings (связи ролей) и ClusterRoleBindings (связи кластерных ролей): как видно из названия сущностей, они связывают субъекты с ролями (т.е. операциями, которые может выполнять конкретный пользователь). Что касается их разницы с ClusterRoles, разница заключается в области применимости: RoleBinding применяет правила внутри одного пространства имен, тогда как ClusterRoleBinding применяет их во всех пространствах имен кластера.




Вы можете найти примеры каждого элемента API в официальной документации Kubernetes.




Создание пользователя с ограничениями по пространству имен




В этом примере мы создадим следующую учетную запись пользователя:




  • Имя пользователя: user1



  • Группа: deparment1




Мы добавим необходимые политики RBAC, чтобы этот пользователь мог полностью управлять развертываниями (т.е. использовать команду kubectl run) только внутри пространства имен office. В конце мы проверим созданные политики, чтобы убедиться, что они работают так, как мы их определили.




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




Выполните команду kubectl create для создания пространства имен office. Команду необходимо запустить от пользователя Kubernetes admin:




[root@kub-master-1 ~]# kubectl create namespace office




Создание пользователя




Как уже упоминалось ранее, в Kubernetes нет объектов API для управления учетными записями пользователей. Из доступных способов управления аутентификацией (см. официальную документацию Kubernetes) для простоты мы будем использовать сертификаты OpenSSL. Необходимые шаги:




  • Создайте закрытый ключ для своего пользователя. В этом примере мы назовем файл user1.key[root@kub-master-1 ~]# openssl genrsa -out user1.key 2048



  • Создайте запрос сертификата user1.csr, используя только что созданный вами закрытый ключ (user1.key). Убедитесь, что вы указали свое имя пользователя и группу в разделе -subj(CN для имени пользователя и O для группы). Как упоминалось ранее, мы будем использовать имя user1 и deparment1 в качестве группы:




[root@kub-master-1 ~]# openssl req -new -key user1.key -out user1.csr -subj «/CN=user1/O=deparment1»




  • Найдите свой центр сертификации кластера Kubernetes (CA). Он будет отвечать за утверждение запроса и получение необходимого сертификата для доступа к API кластера. Обычно он располагается в директории /etc/kubernetes/pki/. В случае Minikube это будет ~/.minikube/. Убедитесь, что файлы ca.crt и ca.key существуют в соответствующей директории.




[root@kub-master-1 ~]# ll /etc/kubernetes/pki/

total 156

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 admin-kub-master-1-key.pem

-rw-------. 1 kube kube-cert 1399 Mar  8 18:58 admin-kub-master-1.pem

-rw-------. 1 kube kube-cert 1675 Mar  8 18:58 admin-kub-master-2-key.pem

-rw-------. 1 kube kube-cert 1399 Mar  8 18:58 admin-kub-master-2.pem

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 admin-kub-master-3-key.pem

-rw-------. 1 kube kube-cert 1399 Mar  8 18:58 admin-kub-master-3.pem

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 apiserver-key.pem

-rw-------. 1 kube kube-cert 2444 Mar  8 18:58 apiserver.pem

-rw-------. 1 kube kube-cert 1675 Mar  8 18:58 ca-key.pem

-rw-------. 1 kube kube-cert 1090 Mar  8 18:58 ca.pem

-rw-------. 1 kube kube-cert 1675 Mar  8 18:58 front-proxy-ca-key.pem

-rw-------. 1 kube kube-cert 1111 Mar  8 18:58 front-proxy-ca.pem

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 front-proxy-client-key.pem

-rw-------. 1 kube kube-cert 1367 Mar  8 18:58 front-proxy-client.pem

-rw-------. 1 kube kube-cert 1675 Mar  8 18:58 kube-controller-manager-key.pem

-rw-------. 1 kube kube-cert 1375 Mar  8 18:58 kube-controller-manager.pem

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 kube-proxy-kub-master-1-key.pem

-rw-------. 1 kube kube-cert 1273 Mar  8 18:58 kube-proxy-kub-master-1.pem

-rw-------. 1 kube kube-cert 1675 Mar  8 18:58 kube-proxy-kub-master-2-key.pem

-rw-------. 1 kube kube-cert 1273 Mar  8 18:58 kube-proxy-kub-master-2.pem

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 kube-proxy-kub-master-3-key.pem

-rw-------. 1 kube kube-cert 1273 Mar  8 18:58 kube-proxy-kub-master-3.pem

-rw-------. 1 kube kube-cert 1675 Mar  8 18:58 kube-proxy-kub-worker-1-key.pem

-rw-------. 1 kube kube-cert 1273 Mar  8 18:58 kube-proxy-kub-worker-1.pem

-rw-------. 1 kube kube-cert 1675 Mar  8 18:58 kube-proxy-kub-worker-2-key.pem

-rw-------. 1 kube kube-cert 1273 Mar  8 18:58 kube-proxy-kub-worker-2.pem

-rw-------. 1 kube kube-cert 1675 Mar  8 18:58 kube-scheduler-key.pem

-rw-------. 1 kube kube-cert 1363 Mar  8 18:58 kube-scheduler.pem

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 node-kub-master-1-key.pem

-rw-------. 1 kube kube-cert 1273 Mar  8 18:58 node-kub-master-1.pem

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 node-kub-master-2-key.pem

-rw-------. 1 kube kube-cert 1273 Mar  8 18:58 node-kub-master-2.pem

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 node-kub-master-3-key.pem

-rw-------. 1 kube kube-cert 1273 Mar  8 18:58 node-kub-master-3.pem

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 node-kub-worker-1-key.pem

-rw-------. 1 kube kube-cert 1273 Mar  8 18:58 node-kub-worker-1.pem

-rw-------. 1 kube kube-cert 1679 Mar  8 18:58 node-kub-worker-2-key.pem

-rw-------. 1 kube kube-cert 1273 Mar  8 18:58 node-kub-worker-2.pem

-rw-------. 1 kube kube-cert 1675 Mar  8 18:58 service-account-key.pem





  • Создайте сертификат user1.crt, одобрив запрос на подпись сертификата, user1.csr, сделанный ранее. Убедитесь, что вы заменили CA_LOCATION в примере команды ниже на местоположение вашего актуального CA кластера. Сертификат будет действителен в течение 500 дней:




$ openssl x509 -req -in user1.csr -CA CA_LOCATION/ca.crt -CAkey CA_LOCATION/ca.key -CAcreateserial -out user1.crt -days 500




в моём случае это команда:




[root@kub-master-1 ~]# openssl x509 -req -in user1.csr -CA /etc/kubernetes/pki/ca.pem -CAkey /etc/kubernetes/pki/ca-key.pem -CAcreateserial -out user1.crt -days 500
и её вывод:




Signature ok

subject=/CN=user1/O=deparment1

Getting CA Private Key




  • Сохраните как user1.crt, так и user1.key где-нибудь в безопасном месте (например, в директории ~/.kube/certs/):
    $ mkdir ~/.kube/certs
    $ cp user1.crt ~/.kube/certs
    $ cp user1.key ~/.kube/certs



  • добавьте новый контекст с новыми учетными данными для вашего кластера Kubernetes.
    [root@kub-master-1 ~]# kubectl config set-credentials user1 —client-certificate=$HOME/.kube/certs/user1.crt —client-key=$HOME/.kube/certs/user1.keyСмотрим имя кластера:
    [root@kub-master-1 ~]# kubectl config view -o jsonpath='{«Cluster nametServern»}{range .clusters[*]}{.name}{«t»}{.cluster.server}{«n»}{end}’



  • добавьте новый контекст с новыми учетными данными для вашего кластера Kubernetes.
    [root@kub-master-1 ~]# kubectl config set-credentials user1 —client-certificate=$HOME/.kube/certs/user1.crt —client-key=$HOME/.kube/certs/user1.keyСмотрим имя кластера:
    [root@kub-master-1 ~]# kubectl config view -o jsonpath='{«Cluster nametServern»}{range .clusters[*]}{.name}{«t»}{.cluster.server}{«n»}{end}’



  • [root@kub-master-1 ~]# kubectl config set-context user1-context —cluster=cluster.local —namespace=office —user=user1




добавим теперь пользователя  под которым будем работать:




[root@kub-master-1 ~]# adduser test
[root@kub-master-1 ~]# mkdir -p /home/test/.kube/certs
[root@kub-master-1 ~]# cp /root/.kube/certs/user1.* /home/test/.kube/certs/




смотрим файл:
[root@kub-master-1 ~]# cat /root/.kube/config




нас интересует:




certificate-authority-data
и
server




и создаём файл следующего вида:




[root@kub-master-1 ~]# cat /home/test/.kube/config




apiVersion: v1

clusters:

- cluster:

    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMrVENDQWVHZ0F3SUJBZ0lKQUl0L0JPdHQrWUhVTUEwR0NTcUdTSWIzRFFFQkN3VUFNQkl4RURBT0JnTlYKQkFNTUIydDFZbVV0WTJFd0lCY05NakV3TXpBNE1USTFPREE1V2hnUE1qRXlNVEF5TVRJeE1qVTRNRGxhTUJJeApFREFPQmdOVkJBTU1CMnQxWW1VdFkyRXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCCkFRQ2FRZk9nbzdpZ3oyV0QyWEd1dzNSd2x6VUhxcjRFT2k1d0wwaWZvVnBaWXBzZk9ORlE0ME90akVEQUVsUXYKSW5YeW1iVEdQN0w0QUFIZlNFZWRULysyUFh4NmV6VDV3WlozbGg5WWt1UmhHcWZUamtsVXN6LzVoOVpNekhzNgpwWWVyNzVJQUZyRXlxSDFtR2pwM0FjaUZmNUU1TmFvczJXQ21HWklPbmdqTmVUMElXdHFGQjNVTzNMSTkxS0JJCi9tNWRPZTh6elJjVWxBODltTTFhTzBBSTZEYWNUbXRiVllDcklwVW01cE45UHFWSjVZNGorTXQvSlpISTlnRisKMUsvUW5hb0owVm5udkl0T0dJbzhaSlZ5ellTVTlNZlltcmE0RkhvYmQzaGsrN1RBZ3lNRWJlOERLdUlpRENzKwozOVhEaXByL0FaRHVnYnZuOVJYV0M5WnhBZ01CQUFHalVEQk9NQjBHQTFVZERnUVdCQlJaUUtYWFdJTlpCSkJzCkZERTlpTTYydHJuSDhUQWZCZ05WSFNNRUdEQVdnQlJaUUtYWFdJTlpCSkJzRkRFOWlNNjJ0cm5IOFRBTUJnTlYKSFJNRUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFBQVgrakdVT3k4R1lEKzh6M244SFV6V25XeAp0RWRrdEJEakxVcjB2anovN0lVRDU0R0MrRm5FY0ZybXZMVHhkYWNNNXNEQmo2MHhscjh2dG9mbDFzekJxMjVVCnFUWTRveDZ1VzUreGlBU1hqNFhHeEZtUG8rUzVGUi9EZjA3clBJZ3QzWWdEYkZHUUw5aHh4UXdKMDdVR3JKa08KM0QyNjYzUDJ4WTBndGdyYzY0UG5EWDBuZ1VxSzJ0akxsKy9qU1c1MHdnWURvbUlYNjlyWUxyMElzOWpYZmk0OQpFK3ljb2ZURElSeUFWT2U2QTBXbmQ2MFhlMEZPdUdqUVZHcWRKeVhBeVhrOW1FK1lNRk9kS09PZjMxNmtYeW90ClppNmE3bnZtYjhFSWpXZWFpd1JwQzNGOEgrdHRFYzFmSVdvNkoralJZTlFjME5BaFhZbFRwRmp6blA0TAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==

    server: https://192.168.1.201:6443

  name: cluster.local

contexts:

- context:

    cluster: cluster.local

    namespace: office

    user: user1

  name: user1-context

kind: Config

preferences: {}

users:

- name: user1

  user:

    client-certificate: certs/user1.crt

    client-key: certs/user1.key




не забываем указать certificate-authority-data и server




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




[test@kub-master-1 ~]$ kubectl get pod -n my-site
The connection to the server localhost:8080 was refused — did you specify the right host or port?
данная ошибка логична потому что мы не указали context




[test@kub-master-1 ~]$ kubectl —context=user1-context get pods -n my-site
Error from server (Forbidden): pods is forbidden: User «user1» cannot list resource «pods» in API group «» in the namespace «my-site»




а вот эта как рас та ошибка что и должна прилетать Forbidden




Создание роли для управления развертываниями




Создайте файл role-deployment-manager.yaml с приведенным ниже содержимым. В этом yaml-файле мы создаем правило, которое позволяет пользователю выполнять несколько операций с Deployments, Pods и ReplicaSets (необходимых для создания Deployment), которые принадлежат к core (выделены “” в yaml-файле) extensions группам API:




[root@kub-master-1 ~]# cat role-deployment-manager.yaml




apiVersion: rbac.authorization.k8s.io/v1

kind: Role

metadata:

  namespace: office

  name: deployment-manager

rules:

- apiGroups: ["", "extensions", "apps"]

  resources: ["deployments", "replicasets", "pods"]

  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # вы таже можете использовать ["*"] вместо списка




[root@kub-master-1 ~]# kubectl create -f role-deployment-manager.yaml




Установление связи пользователь-роль




Создайте файл rolebinding-deployment-manager.yaml так, как показано ниже. В этом файле мы привязываем Role deployment-manager к субъекту User Account user1 внутри пространства имен office:




[root@kub-master-1 ~]# cat rolebinding-deployment-manager.yaml




apiVersion: rbac.authorization.k8s.io/v1

kind: RoleBinding

metadata:

  name: deployment-manager-binding

  namespace: office

subjects:

- kind: User

  name: user1

  apiGroup: ""

roleRef:

  kind: Role

  name: deployment-manager

  apiGroup: ""




[root@kub-master-1 ~]# kubectl create -f rolebinding-deployment-manager.yaml




Тестирование политик RBAC




Теперь вы можете выполнять следующие команды без каких-либо проблем:




[test@kub-master-1 ~]$ kubectl —context=user1-context get pods -n office
No resources found in office namespace.




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




[test@kub-master-1 ~]$ kubectl —context=user1-context get all -n office




NAME                                        READY   STATUS    RESTARTS   AGE

pod/my-deployment-apache-859486bd8c-8ccxd   1/1     Running   0          96s



NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE

deployment.apps/my-deployment-apache   1/1     1            1           96s



NAME                                              DESIRED   CURRENT   READY   AGE

replicaset.apps/my-deployment-apache-859486bd8c   1         1         1       96s

Error from server (Forbidden): replicationcontrollers is forbidden: User "user1" cannot list resource "replicationcontrollers" in API group "" in the namespace "office"

Error from server (Forbidden): services is forbidden: User "user1" cannot list resource "services" in API group "" in the namespace "office"

Error from server (Forbidden): daemonsets.apps is forbidden: User "user1" cannot list resource "daemonsets" in API group "apps" in the namespace "office"

Error from server (Forbidden): statefulsets.apps is forbidden: User "user1" cannot list resource "statefulsets" in API group "apps" in the namespace "office"

Error from server (Forbidden): horizontalpodautoscalers.autoscaling is forbidden: User "user1" cannot list resource "horizontalpodautoscalers" in API group "autoscaling" in the namespace "office"

Error from server (Forbidden): jobs.batch is forbidden: User "user1" cannot list resource "jobs" in API group "batch" in the namespace "office"

Error from server (Forbidden): cronjobs.batch is forbidden: User "user1" cannot list resource "cronjobs" in API group "batch" in the namespace "office"





как видим нам доступны только следующие сущности:
deployments  replicasets   pods




как рас их мы и перечислили в конфиге  role-deployment-manager.yaml  для нашего namespace office




проверим удаление:




YAML




[test@kub-master-1 ~]$ kubectl --context=user1-context delete pod my-deployment-apache-859486bd8c-8ccxd -n office

pod "my-deployment-apache-859486bd8c-8ccxd" deleted




как видим всё ок.




Источник: https://sidmid.ru/kubernetes-пример-использования-rbac/



2023-01-02T06:12:18
DevOps

Использование PostStart хука при запуске пода в Kubernetes-кластере

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




Для каждого контейнера в поде хуки определяются отдельно. Существуют два типа хуков — PostStart и PreStop. Первый является асинхронным и выполняется сразу же при создании контейнера, однако нет никакой гарантии, что данный хук будет выполнен до запуска инструкции ENTRYPOINT контейнера. Стоит отметить, что если выполнение PostStart хука занимает очень много времени (или зависает), то контейнер не может перейти в состояние Running.




Хук PreStop, как видно из его названия, выполняется перед тем как контейнер будет остановлен (terminated) — будь то API-запрос или другое событие (например, неудачная liveness probe, “выдавливание” пода с узла кластера, перебор используемых ресурсов). Этот вызов синхронный, а это значит, что он обязательно должен быть завершен до того, как будет отправлен сигнал остановки контейнера.




Для хуков в жизненном цикле контейнеров предусмотрено два варианта обработчиков (handlers):




  • Exec — выполняет определенную команду (скрипт) в пространстве имен контейнера. Ресурсы, которые используются данной командой также учитываются в используемых ресурсах контейнера (важно при определении памяти и CPU);



  • HTTP — выполняет HTTP-запрос на определенный эндпоинт контейнера.




Если какой-то из хуков PostStart или PreStop завершается с ошибкой, то контейнер также будет остановлен. Логи хуков недоступны при выполнении команды kubectl logs <pod_name>, но если по какой-то причине они выполнились неудачно, то происходит событие FailedPostStartHook или FailedPreStopHook соответственно. Эти события можно увидеть выполнив команду kubectl describe pod <pod_name>.




Итак, мы вполне можем использовать PostStart хук для вставки данных в Redis при старте контейнера.




Идея состоит в следующем: с помощью ConfigMap мы добавим файл(ы) внутрь контейнера, причем названием ключа в редисе будет имя, а значением — содержимое этого файла. Далее, используя PostStart хук, мы “обработаем” каждый из файлов и вставим соответствующие данные в БД Redis.




Манифест, содержащий в себе все необходимые объекты Kubernetes, будет выглядеть так:




apiVersion: v1

kind: Service

metadata:

  name: ads-redis-test

  namespace: default

spec:

  selector:

    app: ads-redis-test

  ports:

  - name: redis

    port: 6379

  clusterIP: None

---

apiVersion: v1

kind: ConfigMap

metadata:

  name: ads-redis-test

  namespace: default

data:

  flow-rules-key: |

    [{

      "resource": "loopme.grpc.ssp.v0.AdsTxtRecordService/GetAdsTxtRelationships",

      "count": 100.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "loopme.grpc.ssp.v0.PublisherAccountService/GetPublisherById",

      "count": 5.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "loopme.grpc.ssp.v1.PublisherAccountService/GetPublisherById",

      "count": 5.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "loopme.grpc.ssp.v0.BundleLegacyService/GetBundleByKey",

      "count": 20.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "loopme.lsm.ssp.v0.BundleService/GetBundleById",

      "count": 20.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "loopme.lsm.ssp.v0.BundleService/QueryBundle",

      "count": 20.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "loopme.grpc.ssp.v0.AppLegacyService/GetAppById",

      "count": 10.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "loopme.grpc.ssp.v0.AppLegacyService/GetAppIdByKey",

      "count": 10.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "loopme.grpc.ssp.v0.AppLegacyService/GetAppIdByContainerKey",

      "count": 16.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "loopme.grpc.ssp.v0.AppLegacyService/GetAppByContainerKey",

      "count": 10.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "ExchangeThrottleRateService/GetThrottleRatesByKeys",

      "count": 20.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "dsp-fetcher",

      "count": 25.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "exchange-fetcher",

      "count": 300.0,

      "grade": "THREAD",

      "limit-app": "default"

    },{

      "resource": "kafka_dmp_ads_requests_info",

      "count": 500.0,

      "grade": "QPS",

      "limit-app": "default"

    }]    

  degrade-rules-key: |

    [{

      "resource": "analytics.AnalyticsApiService/AnalyzeCall",

      "count": 10.0,

      "grade": "EXCEPTION_COUNT",

      "time-window": 10,

      "min-request-amount": 100,

      "stat-interval-ms": 20000,

      "slow-ratio-threshold": 0.6

    },{

      "resource": "analytics.AnalyticsApiService/AnalyzeCall",

      "count": 10.0,

      "grade": "EXCEPTION_RATIO",

      "time-window": 10,

      "min-request-amount": 100,

      "stat-interval-ms": 20000,

      "slow-ratio-threshold": 0.6

    }]    

---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: ads-redis-test

  namespace: default

spec:

  replicas: 1

  selector:

    matchLabels:

      app: ads-redis-test

  template:

    metadata:

      labels:

        app: ads-redis-test

    spec:

      containers:

      - name: redis

        image: redis:6.0.9

        ports:

        - name: redis

          containerPort: 6379

        resources:

          limits:

            cpu: "0.5"

            memory: 1Gi

          requests:

            cpu: "0.5"

            memory: 1Gi

        lifecycle:

          postStart:

            exec:

              command: ["/bin/bash", "-c", "cd /script/ && for FILE in *key; do cat ${FILE} | redis-cli -n 2 -x set ${FILE}; done"]

        livenessProbe:

          exec:

            command:

            - sh

            - -c

            - redis-cli -h $(hostname) ping

          initialDelaySeconds: 5

          periodSeconds: 3

        readinessProbe:

          exec:

            command:

            - sh

            - -c

            - redis-cli -h $(hostname) ping

          initialDelaySeconds: 5

          timeoutSeconds: 3

        volumeMounts:

        - mountPath: /script

          name: script

      volumes:

      - name: script

        configMap:

          name: ads-redis-test




Вся “магия” заключается в команде, которая определена в postStart хуке:




command: ["/bin/bash", "-c", "cd /script/ && for FILE in *key; do cat ${FILE} | redis-cli -n 2 -x set ${FILE}; done"]




Здесь для каждого файла в каталоге /script, который заканчивается на key выполняется следующее:




  • с помощью команды cat выводится содержимое файла в STDOUT;



  • через конвейер | передаются следующей команде — консольной утилите redis-cli (здесь в STDIN попадает содержимое STDOUT из предыдущего шага);



  • redis-cli выполняет вставку данных во вторую БД (ключ -n 2) с помощью команды SET.




Примечание Именем ключа будет значение переменной ${FILE} (имя файла), а значением — данные из STDIN (об этом заботится ключ -x).




Источник: https://sidmid.ru/использование-poststart-хука-при-запуске-пода/



2023-01-02T06:04:30
DevOps

Kubernetes. Gitlab (ci/cd) (HTTP Basic: Access denied)

У меня имелся следующий проект, в котором собираются 4 контейнера а дальше деплоятся в кластер kubernetes
вот пример helm чарта:




[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/templates/deployment.yaml




---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: {{ .Values.deployment_name }}

  namespace: {{ .Values.namespace }}

  labels:

    app: {{ .Values.app_name }}



spec:

  replicas: {{ .Values.replica_number }}

  selector:

    matchLabels:

      app: {{ .Values.app_name }} # по вот этому лейблу репликасет цепляет под

# тут описывается каким мокаром следует обновлять поды

  strategy:

    rollingUpdate:

      maxSurge: 1  # указывает на какое количество реплик можно увеличить

      maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить

#т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под)

    type: RollingUpdate

## тут начинается описание контейнера

  template:

    metadata:

      labels:

        app: {{ .Values.app_name }}  # по вот этому лейблу репликасет цепляет под

#       name_elk: elk-log-{{ .Values.namespace }} #это имя будет записываться в EFK

    spec:

      containers:

        - image: "{{ .Values.image_app.repository }}:{{ .Values.image_app.tag }}"

          imagePullPolicy: Always

          name: {{ .Values.app_name }}

          ports:

            - containerPort: {{ .Values.deployment_port }}

# тут начинаются проверки по доступности

#          readinessProbe: # проверка готово ли приложение

#            failureThreshold: 3 #указывает количество провалов при проверке

#            httpGet:  # по сути дёргает курлом на 8080 порт

#              path: /monitoring

#              port: 8080

#            periodSeconds: 20 #как часто должна проходить проверка (в секундах)

#            successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок

#            timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда

#            initialDelaySeconds: 120

#          livenessProbe: #проверка на жизнь приложения, живо ли оно

#            failureThreshold: 3

#            tcpSocket:

#              port: 8888

#            httpGet:

#              path: /monitoring

#              port: 8080

#            periodSeconds: 20

#            successThreshold: 1

#            timeoutSeconds: 1

#            initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд



# тут начинается описание лимитов для пода

          resources:

            requests: #количество ресурсов которые резервируются для pod на ноде

              cpu: {{ .Values.requests_cpu_app }}

              memory: {{ .Values.requests_memory_app }}

            limits: #количество ресурсов которые pod может использовать(верхняя граница)

              cpu: {{ .Values.limits_cpu_app }}

              memory: {{ .Values.limits_memory_app }}

      imagePullSecrets:

      - name: {{ .Values.secret_name_gitlab_login }}





[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/templates/service.yaml




---

kind: Service

apiVersion: v1

metadata:

  name: {{ .Values.service_name }}

  namespace: {{ .Values.namespace }}

spec:

  selector:

    app: {{ .Values.app_name }}

  ports:

    - protocol: TCP

      port: {{ .Values.service_port }}

      targetPort: {{ .Values.deployment_port }}





[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/templates/ingress.yaml




---

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: {{ .Values.ingress_name }}

  namespace: {{ .Values.namespace }}

spec:

  rules:

  - host: {{ .Values.domain }}  #тут указывается наш домен

    http:

      paths:

     # - path: "/ui/test"

     #   backend:

     #     serviceName: {{ .Values.service_name }}

     #     servicePort: 8083

      - path: "/"

        backend:

          serviceName: {{ .Values.service_name }}

          servicePort: {{ .Values.service_port }}





[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/Chart.yaml




apiVersion: v2

name: cache-builder

description: A Helm chart for Kubernetes

type: application

version: 1.0.0

appVersion: 1.0.0





[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/values-mrunner.yaml




#неймспейс в котором запускаемся

namespace: test-cache-builder



#имя деплоймента

deployment_name: deployment-cache-builder-mrunner



deployment_port: 8888

service_port: 8888



#имя сервиса

service_name: service-cache-builder-mrunner



#имя ingress

ingress_name: ingress-cache-builder-mrunner



#указываем наш домен по которому будет слушать ingress

domain: cb-mrunner.prod.test.local



#количество реплик деплоймента минимальное количество

replica_number: 1



#имя лейбла сервиса

app_name: cache-builder-mrunner



#имя образа для сервиса

image_app:

  repository: gitnexus.test.local:4567/cache-builder/cache-builder/mrunner

  tag: "v5"



#количество ресурсов которые резервируются для pod на ноде проц и оперативка

requests_cpu_app: 100m

requests_memory_app: 500Mi

#количество ресурсов которые pod может использовать(верхняя граница)

limits_cpu_app: 400m

limits_memory_app: 1000Mi



#имя секрета под которым воркер ноды будут выкачивать образа из gitlab

secret_name_gitlab_login: docker-login-cache-builder




[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/values-node.yaml




#неймспейс в котором запускаемся

namespace: test-cache-builder



#имя деплоймента

deployment_name: deployment-cache-builder-node



deployment_port: 7777

service_port: 7777



#имя сервиса

service_name: service-cache-builder-node



#имя ingress

ingress_name: ingress-cache-builder-node



#указываем наш домен по которому будет слушать ingress

domain: cbapi.prod.test.local



#количество реплик деплоймента минимальное количество

replica_number: 1



#имя лейбла сервиса

app_name: cache-builder-node



#имя образа для сервиса

image_app:

  repository: gitnexus.test.local:4567/cache-builder/cache-builder/node

  tag: "v5"



#количество ресурсов которые резервируются для pod на ноде проц и оперативка

requests_cpu_app: 100m

requests_memory_app: 500Mi

#количество ресурсов которые pod может использовать(верхняя граница)

limits_cpu_app: 400m

limits_memory_app: 1000Mi



#имя секрета под которым воркер ноды будут выкачивать образа из gitlab

secret_name_gitlab_login: docker-login-cache-builder





[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/values-scheduler.yaml




#неймспейс в котором запускаемся

namespace: test-cache-builder



#имя деплоймента

deployment_name: deployment-cache-builder-scheduler



deployment_port: 7777

service_port: 7777



#имя сервиса

service_name: service-cache-builder-scheduler



#имя ingress

ingress_name: ingress-cache-builder-scheduler





#количество реплик деплоймента минимальное количество

replica_number: 1



#имя лейбла сервиса

app_name: cache-builder-scheduler



#имя образа для сервиса

image_app:

  repository: gitnexus.test.local:4567/cache-builder/cache-builder/scheduler

  tag: "v5"



#количество ресурсов которые резервируются для pod на ноде проц и оперативка

requests_cpu_app: 100m

requests_memory_app: 500Mi

#количество ресурсов которые pod может использовать(верхняя граница)

limits_cpu_app: 400m

limits_memory_app: 1000Mi



#имя секрета под которым воркер ноды будут выкачивать образа из gitlab

secret_name_gitlab_login: docker-login-cache-builder





[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/values-web.yaml




#неймспейс в котором запускаемся

namespace: test-cache-builder



#имя деплоймента

deployment_name: deployment-cache-builder-web



deployment_port: 8080

service_port: 8080



#имя сервиса

service_name: service-cache-builder-web



#имя ingress

ingress_name: ingress-cache-builder-web



#указываем наш домен по которому будет слушать ingress

domain: cb.prod.test.local



#количество реплик деплоймента минимальное количество

replica_number: 1



#имя лейбла сервиса

app_name: cache-builder-web



#имя образа для сервиса

image_app:

  repository: gitnexus.test.local:4567/cache-builder/cache-builder/web

  tag: "v5"



#количество ресурсов которые резервируются для pod на ноде проц и оперативка

requests_cpu_app: 100m

requests_memory_app: 500Mi

#количество ресурсов которые pod может использовать(верхняя граница)

limits_cpu_app: 400m

limits_memory_app: 1000Mi



#имя секрета под которым воркер ноды будут выкачивать образа из gitlab

secret_name_gitlab_login: docker-login-cache-builder





далее показываю .gitlab-ci.yml при котором у меня возникли ошибки:




variables:

  NAMESPACE: test-cache-builder

  kubeconfig_url: /home/gitlab-runner/.kube/config 

  PWD: $(pwd)





stages:

  - deploy_to_kuber



.autorizate_to_gitlab: &autorizate_to_gitlab |

    docker logout $CI_REGISTRY

    docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY

.git_tag_variable: &git_tag_variable |

    git fetch --tags

    export TAG=$(git describe --tags --abbrev=0)

    echo $TAG





deploy_to_kuber:

  stage: deploy_to_kuber

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - *autorizate_to_gitlab

    - *git_tag_variable

    - mkdir -p `echo $kubeconfig_url | awk -F '/' 'sub(FS $NF,x)'`

    - echo $kubeconfig | base64 -d > $kubeconfig_url

    - kubectl create namespace $NAMESPACE --kubeconfig=$kubeconfig_url || echo "all OK - namespace =  $NAMESPACE alredy exist"

    - kubectl --kubeconfig=$kubeconfig_url delete secret docker-login-$CI_PROJECT_NAME -n $NAMESPACE || echo "error secret not exist"

    - kubectl --kubeconfig=$kubeconfig_url create secret docker-registry docker-login-$CI_PROJECT_NAME --docker-server=$CI_REGISTRY --docker-username=$CI_REGISTRY_USER --docker-password=$CI_REGISTRY_PASSWORD --docker-email=$GITLAB_USER_EMAIL -n $NAMESPACE

  script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE test-$CI_PROJECT_NAME-web  helm/

      --values helm/values-web.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME



    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE test-$CI_PROJECT_NAME-mrunner  helm/

      --values helm/values-mrunner.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME



    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE test-$CI_PROJECT_NAME-node  helm/

      --values helm/values-node.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME



    - helm  upgrade --install --atomic --timeout 3m 

      --kubeconfig=$kubeconfig_url -n $NAMESPACE test-$CI_PROJECT_NAME-scheduler  helm/

      --values helm/values-scheduler.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME



  after_script:

    - *git_tag_variable

    - kubectl --kubeconfig=$kubeconfig_url get pod -n $NAMESPACE

    - kubectl --kubeconfig=$kubeconfig_url get service -n $NAMESPACE

    - kubectl --kubeconfig=$kubeconfig_url get ingress -n $NAMESPACE

    - rm -rf $kubeconfig_url




переменная kubeconfig является токеном кубернетеса добавленным в переменные  проекта:





при создании секрета
kubectl —kubeconfig=$kubeconfig_url create secret docker-registry docker-login-$CI_PROJECT_NAME —docker-server=$CI_REGISTRY —docker-username=$CI_REGISTRY_USER —docker-password=$CI_REGISTRY_PASSWORD —docker-email=$GITLAB_USER_EMAIL -n $NAMESPACE




под которым дальше будет выкачиваться образ из registry я использовал встроенные переменные:
CI_REGISTRY_USER
CI_REGISTRY_PASSWORD
при их использовании не выкачивается один из образов, вот вывод describe этого pod




Events:

  Type     Reason     Age               From                           Message

  ----     ------     ----              ----                           -------

  Normal   Scheduled  <unknown>         default-scheduler              Successfully assigned test-cache-builder/deployment-cache-builder-node-6f5c998487-gvhbc to prod-srv-kubeworker1

  Normal   BackOff    13s               kubelet, prod-srv-kubeworker1  Back-off pulling image "gitnexus.test.local:4567/cache-builder/cache-builder/node:v14"

  Warning  Failed     13s               kubelet, prod-srv-kubeworker1  Error: ImagePullBackOff

  Normal   Pulling    1s (x2 over 14s)  kubelet, prod-srv-kubeworker1  Pulling image "gitnexus.test.local:4567/cache-builder/cache-builder/node:v14"

  Warning  Failed     1s (x2 over 14s)  kubelet, prod-srv-kubeworker1  Failed to pull image "gitnexus.test.local:4567/cache-builder/cache-builder/node:v14": rpc error: code = Unknown desc = Error response from daemon: Get http://gitnexus.test.local:4567/v2/cache-builder/cache-builder/node/manifests/v14: unauthorized: HTTP Basic: Access denied

  Warning  Failed     1s (x2 over 14s)  kubelet, prod-srv-kubeworker1  Error: ErrImagePull





вылетает ошибка:
unauthorized: HTTP Basic: Access denied
хотя под этими учётными данными login проходит нормально.




нашёл следующие решения:




1.Костыльное — это добавить sleep между helm




variables:

  NAMESPACE: megacom-cache-builder

  kubeconfig_url: /home/gitlab-runner/.kube/config

  PWD: $(pwd)





stages:

  - deploy_to_kuber



.autorizate_to_gitlab: &autorizate_to_gitlab |

    docker logout $CI_REGISTRY

    docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY

.git_tag_variable: &git_tag_variable |

    git fetch --tags

    export TAG=$(git describe --tags --abbrev=0)

    echo $TAG





deploy_to_kuber:

  stage: deploy_to_kuber

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - *autorizate_to_gitlab

    - *git_tag_variable

    - mkdir -p `echo $kubeconfig_url | awk -F '/' 'sub(FS $NF,x)'`

    - echo $kubeconfig | base64 -d > $kubeconfig_url

    - kubectl create namespace $NAMESPACE --kubeconfig=$kubeconfig_url || echo "all OK - namespace =  $NAMESPACE alredy exist"

    - kubectl --kubeconfig=$kubeconfig_url delete secret docker-login-$CI_PROJECT_NAME -n $NAMESPACE || echo "error secret not exist"

    - echo "CI_PROJECT_NAME = $CI_PROJECT_NAME"

    - echo "CI_REGISTRY = $CI_REGISTRY"

    - echo "CI_REGISTRY_USER = $CI_REGISTRY_USER"

    - echo "CI_REGISTRY_PASSWORD = $CI_REGISTRY_PASSWORD"

    - echo "GITLAB_USER_EMAIL = $GITLAB_USER_EMAIL"

    - echo "gitlab-ci-token = $gitlab-ci-token"

    - kubectl --kubeconfig=$kubeconfig_url create secret docker-registry docker-login-$CI_PROJECT_NAME --docker-server=$CI_REGISTRY --docker-username=$CI_REGISTRY_USER --docker-password=$CI_REGISTRY_PASSWORD --docker-email=$GITLAB_USER_EMAIL -n $NAMESPACE

    - sleep 5

  script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE megacom-$CI_PROJECT_NAME-web  helm/

      --values helm/values-web.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

    - sleep 15



    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE megacom-$CI_PROJECT_NAME-mrunner  helm/

      --values helm/values-mrunner.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

    - sleep 20



    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE megacom-$CI_PROJECT_NAME-node  helm/

      --values helm/values-node.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

    - sleep 25



    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE megacom-$CI_PROJECT_NAME-scheduler  helm/

      --values helm/values-scheduler.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

    - sleep 30



  after_script:

    - *git_tag_variable

    - kubectl --kubeconfig=$kubeconfig_url get pod -n $NAMESPACE

    - kubectl --kubeconfig=$kubeconfig_url get service -n $NAMESPACE

    - kubectl --kubeconfig=$kubeconfig_url get ingress -n $NAMESPACE

    - rm -rf $kubeconfig_url





2.Создать деплой токен — думаю оно правильнее:




Создаю Deploy Tokens






меняем немного .gitlab-ci.yml




variables:

  NAMESPACE: test-cache-builder

  kubeconfig_url: /home/gitlab-runner/.kube/config 

  PWD: $(pwd)

 

stages:

  - deploy_to_kuber

  - helm_install

  - delete_kubeconfig

 

.autorizate_to_gitlab: &autorizate_to_gitlab |

    docker logout $CI_REGISTRY

    docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY

.git_tag_variable: &git_tag_variable |

    git fetch --tags

    export TAG=$(git describe --tags --abbrev=0)

    echo $TAG

.info: &info |

    kubectl --kubeconfig=$kubeconfig_url get pod -n $NAMESPACE

    kubectl --kubeconfig=$kubeconfig_url get service -n $NAMESPACE

    kubectl --kubeconfig=$kubeconfig_url get ingress -n $NAMESPACE

 

deploy_to_kuber:

  stage: deploy_to_kuber

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - *autorizate_to_gitlab

    - *git_tag_variable

    - mkdir -p `echo $kubeconfig_url | awk -F '/' 'sub(FS $NF,x)'`

    - echo $kubeconfig | base64 -d > $kubeconfig_url

    - kubectl create namespace $NAMESPACE --kubeconfig=$kubeconfig_url || echo "all OK - namespace =  $NAMESPACE alredy exist"

    - kubectl --kubeconfig=$kubeconfig_url delete secret docker-login-$CI_PROJECT_NAME -n $NAMESPACE || echo "error secret not exist"

    - kubectl --kubeconfig=$kubeconfig_url create secret docker-registry docker-login-$CI_PROJECT_NAME --docker-server="$CI_REGISTRY" --docker-username="$CI_DEPLOY_USER" --docker-password="$CI_DEPLOY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL" -n $NAMESPACE

  script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

 

helm_install-node:

  stage: helm_install

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

  script:

    - *autorizate_to_gitlab

    - *git_tag_variable

    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE test-$CI_PROJECT_NAME-node  helm/

      --values helm/values-node.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

  after_script:

    - *git_tag_variable

    - *info





helm_install-scheduler:

  stage: helm_install

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

  script:

    - *autorizate_to_gitlab

    - *git_tag_variable

    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE test-$CI_PROJECT_NAME-scheduler  helm/

      --values helm/values-scheduler.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

  after_script:

    - *git_tag_variable

    - *info





helm_install-mrunner:

  stage: helm_install

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

  script:

    - *autorizate_to_gitlab

    - *git_tag_variable

    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE test-$CI_PROJECT_NAME-mrunner  helm/

      --values helm/values-mrunner.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

  after_script:

    - *git_tag_variable

    - *info





helm_install-web:

  stage: helm_install

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

  script:

    - *autorizate_to_gitlab

    - *git_tag_variable

    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE test-$CI_PROJECT_NAME-web  helm/

      --values helm/values-web.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

  after_script:

    - *git_tag_variable

    - *info



delete_kubeconfig:

  stage: delete_kubeconfig

  tags:

    - runer-gitnexus-shell

  only:

    - master

  script:

    - rm -rf $kubeconfig_url





этим самым мы получаем pipeline в следующем виде:





рассмотрим что поменяли, старый вариант:




kubectl —kubeconfig=$kubeconfig_url create secret docker-registry docker-login-$CI_PROJECT_NAME —docker-server=$CI_REGISTRY —docker-username=$CI_REGISTRY_USER —docker-password=$CI_REGISTRY_PASSWORD —docker-email=$GITLAB_USER_EMAIL -n $NAMESPACE




новый вариант:




kubectl —kubeconfig=$kubeconfig_url create secret docker-registry docker-login-$CI_PROJECT_NAME —docker-server=»$CI_REGISTRY» —docker-username=»$CI_DEPLOY_USER» —docker-password=»$CI_DEPLOY_PASSWORD» —docker-email=»$GITLAB_USER_EMAIL» -n $NAMESPACE




как видим мы изменили CI_REGISTRY_USER  на CI_DEPLOY_USER    и CI_REGISTRY_PASSWORD  на CI_DEPLOY_PASSWORD




в таком варианте стало нормально выкачиваться.




3.Использование условий




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




правим шаблоны, приводя их к следующему виду:




[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/templates/deployment.yaml




---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: {{ .Values.deployment_name }}

  namespace: {{ .Values.namespace }}

  labels:

    app: {{ .Values.app_name }}



spec:

  replicas: {{ .Values.replica_number }}

  selector:

    matchLabels:

      app: {{ .Values.app_name }} # по вот этому лейблу репликасет цепляет под

# тут описывается каким мокаром следует обновлять поды

  strategy:

    rollingUpdate:

      maxSurge: 1  # указывает на какое количество реплик можно увеличить

      maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить

#т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под)

    type: RollingUpdate

## тут начинается описание контейнера

  template:

    metadata:

      labels:

        app: {{ .Values.app_name }}  # по вот этому лейблу репликасет цепляет под

#       name_elk: elk-log-{{ .Values.namespace }} #это имя будет записываться в ELK

    spec:

      containers:

        - image: "{{ .Values.image_app.repository }}:{{ .Values.image_app.tag }}"

          imagePullPolicy: Always

          name: {{ .Values.app_name }}

          ports:

            - containerPort: {{ .Values.deployment_port }}

# тут начинаются проверки по доступности

          {{- if .Values.readinessProbe.enabled }}

          readinessProbe: # проверка готово ли приложение

            failureThreshold: {{ .Values.readinessProbe.failureThreshold }} #указывает количество провалов при проверке

            httpGet:  # по сути дёргает курлом на 8080 порт

              path: {{ .Values.readinessProbe.path }}

              port: {{ .Values.readinessProbe.port }}

            periodSeconds: {{ .Values.readinessProbe.periodSeconds }}  #как часто должна проходить проверка (в секундах)

            successThreshold: {{ .Values.readinessProbe.successThreshold }}  #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок

            timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}  #таймаут на выполнение пробы 1 секунда

            initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}

          {{- end}}

          {{- if .Values.livenessProbe.enabled }}

          livenessProbe: #проверка на жизнь приложения, живо ли оно

            failureThreshold: {{ .Values.livenessProbe.failureThreshold }}

            httpGet:

              path: {{ .Values.livenessProbe.path }}

              port: {{ .Values.livenessProbe.port }}

            periodSeconds: {{ .Values.livenessProbe.periodSeconds }}

            successThreshold: {{ .Values.livenessProbe.successThreshold }}

            timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}

            initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}  #означает что первую проверку надо сделать только после 10 секунд

          {{- end}}

# тут начинается описание лимитов для пода

          resources:

            requests: #количество ресурсов которые резервируются для pod на ноде

              cpu: {{ .Values.requests_cpu_app }}

              memory: {{ .Values.requests_memory_app }}

            limits: #количество ресурсов которые pod может использовать(верхняя граница)

              cpu: {{ .Values.limits_cpu_app }}

              memory: {{ .Values.limits_memory_app }}

      imagePullSecrets:

      - name: {{ .Values.secret_name_gitlab_login }}





[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/templates/ingress.yaml




---

{{- if .Values.ingress.enabled }}

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: {{ .Values.ingress.ingress_name }}

  namespace: {{ .Values.ingress.namespace }}

spec:

  rules:

  - host: {{ .Values.ingress.domain }}  #тут указывается наш домен

    http:

      paths:

     # - path: "/ui/test"

     #   backend:

     #     serviceName: {{ .Values.service_name }}

     #     servicePort: 8083

      - path: "/"

        backend:

          serviceName: {{ .Values.service_name }}

          servicePort: {{ .Values.service_port }}

{{- end}}





сервис я оставил без изменений:




[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/templates/service.yaml




---

kind: Service

apiVersion: v1

metadata:

  name: {{ .Values.service_name }}

  namespace: {{ .Values.namespace }}

spec:

  selector:

    app: {{ .Values.app_name }}

  ports:

    - protocol: TCP

      port: {{ .Values.service_port }}

      targetPort: {{ .Values.deployment_port }}





ну и правим наши values
[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/values-mrunner.yaml




#неймспейс в котором запускаемся

namespace: megacom-cache-builder



#имя деплоймента

deployment_name: deployment-cache-builder-mrunner



deployment_port: 8888

service_port: 8888



#имя сервиса

service_name: service-cache-builder-mrunner





ingress:

  enabled: true

  #имя ingress

  ingress_name: ingress-cache-builder-mrunner

  #указываем наш домен по которому будет слушать ingress

  domain: cb-mrunner.prod.megacom.local



#количество реплик деплоймента минимальное количество

replica_number: 1



#имя лейбла сервиса

app_name: cache-builder-mrunner



#имя образа для сервиса

image_app:

  repository: gitnexus.megacom.local:4567/cache-builder/cache-builder/mrunner

  tag: "v5"



#количество ресурсов которые резервируются для pod на ноде проц и оперативка

requests_cpu_app: 50m

requests_memory_app: 60Mi

#количество ресурсов которые pod может использовать(верхняя граница)

limits_cpu_app: 400m

limits_memory_app: 500Mi



#имя секрета под которым воркер ноды будут выкачивать образа из gitlab

secret_name_gitlab_login: docker-login-cache-builder



#включаем или выключаем livenessProbe readinessProbe

readinessProbe:

  enabled: false

  failureThreshold: 3

  path: /monitoring

  port: 8080

  periodSeconds: 20

  successThreshold: 1

  timeoutSeconds: 1

  initialDelaySeconds: 20



livenessProbe:

  enabled: false

  failureThreshold: 3

  path: /monitoring

  port: 8080

  periodSeconds: 20

  successThreshold: 1

  timeoutSeconds: 1

  initialDelaySeconds: 10




[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/values-node.yaml




#неймспейс в котором запускаемся

namespace: megacom-cache-builder



#имя деплоймента

deployment_name: deployment-cache-builder-node



deployment_port: 7777

service_port: 7777



#имя сервиса

service_name: service-cache-builder-node





ingress:

  enabled: true

  #имя ingress

  ingress_name: ingress-cache-builder-node

  #указываем наш домен по которому будет слушать ingress

  domain: cbapi.prod.megacom.local



#количество реплик деплоймента минимальное количество

replica_number: 1



#имя лейбла сервиса

app_name: cache-builder-node



#имя образа для сервиса

image_app:

  repository: gitnexus.megacom.local:4567/cache-builder/cache-builder/node

  tag: "v5"



#количество ресурсов которые резервируются для pod на ноде проц и оперативка

requests_cpu_app: 50m

requests_memory_app: 60Mi

#количество ресурсов которые pod может использовать(верхняя граница)

limits_cpu_app: 400m

limits_memory_app: 500Mi



#имя секрета под которым воркер ноды будут выкачивать образа из gitlab

secret_name_gitlab_login: docker-login-cache-builder



#включаем или выключаем livenessProbe readinessProbe

readinessProbe:

  enabled: false

  failureThreshold: 3

  path: /monitoring

  port: 8080

  periodSeconds: 20

  successThreshold: 1

  timeoutSeconds: 1

  initialDelaySeconds: 20



livenessProbe:

  enabled: false

  failureThreshold: 3

  path: /monitoring

  port: 8080

  periodSeconds: 20

  successThreshold: 1

  timeoutSeconds: 1

  initialDelaySeconds: 10





[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/values-scheduler.yaml




#неймспейс в котором запускаемся

namespace: megacom-cache-builder



#имя деплоймента

deployment_name: deployment-cache-builder-scheduler



deployment_port: 7777

service_port: 7777



#имя сервиса

service_name: service-cache-builder-scheduler





ingress:

  enabled: false

  #имя ingress

  ingress_name:

  #указываем наш домен по которому будет слушать ingress

  domain:





#количество реплик деплоймента минимальное количество

replica_number: 1



#имя лейбла сервиса

app_name: cache-builder-scheduler



#имя образа для сервиса

image_app:

  repository: gitnexus.megacom.local:4567/cache-builder/cache-builder/scheduler

  tag: "v5"



#количество ресурсов которые резервируются для pod на ноде проц и оперативка

requests_cpu_app: 50m

requests_memory_app: 60Mi

#количество ресурсов которые pod может использовать(верхняя граница)

limits_cpu_app: 400m

limits_memory_app: 500Mi



#имя секрета под которым воркер ноды будут выкачивать образа из gitlab

secret_name_gitlab_login: docker-login-cache-builder



#включаем или выключаем livenessProbe readinessProbe

readinessProbe:

  enabled: false

  failureThreshold: 3

  path: /monitoring

  port: 8080

  periodSeconds: 20

  successThreshold: 1

  timeoutSeconds: 1

  initialDelaySeconds: 20



livenessProbe:

  enabled: false

  failureThreshold: 3

  path: /monitoring

  port: 8080

  periodSeconds: 20

  successThreshold: 1

  timeoutSeconds: 1

  initialDelaySeconds: 10





[root@prod-vsrv-kubemaster1 cache-builder]# cat helm/values-web.yaml




#неймспейс в котором запускаемся

namespace: megacom-cache-builder



#имя деплоймента

deployment_name: deployment-cache-builder-web



deployment_port: 8080

service_port: 8080



#имя сервиса

service_name: service-cache-builder-web





ingress:

  enabled: true

  #имя ingress

  ingress_name: ingress-cache-builder-web

  #указываем наш домен по которому будет слушать ingress

  domain: cb.prod.megacom.local



#количество реплик деплоймента минимальное количество

replica_number: 1



#имя лейбла сервиса

app_name: cache-builder-web



#имя образа для сервиса

image_app:

  repository: gitnexus.megacom.local:4567/cache-builder/cache-builder/web

  tag: "v5"



#количество ресурсов которые резервируются для pod на ноде проц и оперативка

requests_cpu_app: 50m

requests_memory_app: 60Mi

#количество ресурсов которые pod может использовать(верхняя граница)

limits_cpu_app: 400m

limits_memory_app: 500Mi



#имя секрета под которым воркер ноды будут выкачивать образа из gitlab

secret_name_gitlab_login: docker-login-cache-builder



#включаем или выключаем livenessProbe readinessProbe

readinessProbe:

  enabled: false

  failureThreshold: 3

  path: /monitoring

  port: 8080

  periodSeconds: 20

  successThreshold: 1

  timeoutSeconds: 1

  initialDelaySeconds: 20



livenessProbe:

  enabled: false

  failureThreshold: 3

  path: /monitoring

  port: 8080

  periodSeconds: 20

  successThreshold: 1

  timeoutSeconds: 1

  initialDelaySeconds: 10





[root@prod-vsrv-kubemaster1 cache-builder]# cat .gitlab-ci.yml




остаётся без изменений:




variables:

  NAMESPACE: megacom-cache-builder

  kubeconfig_url: /home/gitlab-runner/.kube/config

  PWD: $(pwd)



stages:

  - deploy_to_kuber

  - helm_install

  - delete_kubeconfig





.autorizate_to_gitlab: &autorizate_to_gitlab |

    docker logout $CI_REGISTRY

    docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY

.git_tag_variable: &git_tag_variable |

    git fetch --tags

    export TAG=$(git describe --tags --abbrev=0)

    echo $TAG

.info: &info |

    kubectl --kubeconfig=$kubeconfig_url get pod -n $NAMESPACE

    kubectl --kubeconfig=$kubeconfig_url get service -n $NAMESPACE

    kubectl --kubeconfig=$kubeconfig_url get ingress -n $NAMESPACE



deploy_to_kuber:

  stage: deploy_to_kuber

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - mkdir -p `echo $kubeconfig_url | awk -F '/' 'sub(FS $NF,x)'`

    - echo $kubeconfig | base64 -d > $kubeconfig_url

    - kubectl create namespace $NAMESPACE --kubeconfig=$kubeconfig_url || echo "all OK - namespace =  $NAMESPACE alredy exist"

    - kubectl --kubeconfig=$kubeconfig_url delete secret docker-login-$CI_PROJECT_NAME -n $NAMESPACE || echo "error secret not exist"

    - kubectl --kubeconfig=$kubeconfig_url create secret docker-registry docker-login-$CI_PROJECT_NAME --docker-server="$CI_REGISTRY" --docker-username="$CI_DEPLOY_USER" --docker-password="$CI_DEPLOY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL" -n $NAMESPACE

  script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE



helm_install-node:

  stage: helm_install

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

  script:

    - *git_tag_variable

    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE megacom-$CI_PROJECT_NAME-node  helm/

      --values helm/values-node.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

  after_script:

    - *info





helm_install-scheduler:

  stage: helm_install

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

  script:

    - *git_tag_variable

    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE megacom-$CI_PROJECT_NAME-scheduler  helm/

      --values helm/values-scheduler.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

  after_script:

    - *info





helm_install-mrunner:

  stage: helm_install

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

  script:

    - *git_tag_variable

    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE megacom-$CI_PROJECT_NAME-mrunner  helm/

      --values helm/values-mrunner.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

  after_script:

    - *info





helm_install-web:

  stage: helm_install

  tags:

    - runer-gitnexus-shell

  only:

    - master

  before_script:

    - kubectl --kubeconfig=$kubeconfig_url get secret -n $NAMESPACE

  script:

    - *git_tag_variable

    - helm  upgrade --install --atomic --timeout 3m

      --kubeconfig=$kubeconfig_url -n $NAMESPACE megacom-$CI_PROJECT_NAME-web  helm/

      --values helm/values-web.yaml

      --set-string image_app.tag=$TAG

      --set-string namespace=$NAMESPACE

      --set-string secret_name_gitlab_login=docker-login-$CI_PROJECT_NAME

  after_script:

    - *info



delete_kubeconfig:

  stage: delete_kubeconfig

  tags:

    - runer-gitnexus-shell

  only:

    - master

  script:

    - rm -rf $kubeconfig_url

    - *info




Источник: https://sidmid.ru/kubernetes-gitlab-ci-cd-http-basic-access-denied/



Kubernetes — создать политику безопасности — RBAC

Политика безопасности пода Kubernetes – это ресурс, который контролирует безопасность спецификации этого пода.




Используя определение объекта PodSecurityPolicy, вы можете управлять такими вещами, как:




  • Возможность запуска привилегированных контейнеров



  • Повышение привилегий



  • Доступ к типам томов



  • Доступ к файловым системам хоста



  • Использование хост-сети




Как создать политику безопасности пода Kubernetes
Давайте создадим политику безопасности пода Kubernetes, которая предотвращает создание привилегированных модулей и контролирует доступ к томам.
Во-первых, мы должны создать файл YAML.
В терминале введите команду:
nano psp.yaml
В этот файл вставьте следующее:




apiVersion: policy/v1beta1

kind: PodSecurityPolicy

metadata:

  name: psp

spec:

  privileged: false

  seLinux:

    rule: RunAsAny

  supplementalGroups:

    rule: RunAsAny

  runAsUser:

    rule: RunAsAny

  fsGroup:

    rule: RunAsAny

  volumes:

  - '*'




В этом файле мы запрещаем создание привилегированных модулей с помощью строки:




privileged: false




Мы также разрешаем следующее (через правило RunAsAny):




  • SeLinux – позволяет любому пользователю управлять SELinux в модулях.



  • Linux groups – дополнительные группы



  • runAsUser – позволяет пользователям запускать точки входа в контейнер с другим именем пользователя



  • fsGroup – тома, которые поддерживают управление собственностью




Сохраните и закройте файл.




Теперь мы должны применить политику.




Это делается с помощью команды:




kubectl apply -f psp.yaml




Вывод:




podsecurity.policy/psp created




В любой момент вы можете изменить файл YAML и выполнить ту же команду, чтобы переконфигурировать политику.




Убедитесь, что ваша политика доступна, введя команду:




kubectl get psp




В выводе будут перечислены детали:




Created with GIMP




Как назначить политику безопасности Kubernetes поду




Теперь, когда вы создали свою политику, возникает законный вопрос как ее назначить?




Это делается с помощью управления доступом на основе ролей (RBAC).




Создайте конфигурацию RBAC для политики с помощью команды:




nano rbac-psp.yaml




В этот файл вставьте следующее:




kind: ClusterRole

apiVersion: rbac.authorization.k8s.io/v1

metadata:

  name: psp:psp

rules:

- apiGroups:

  - extensions

  resources:

  - podsecuritypolicies

  resourceNames:

  - psp

  verbs:

  - use

---



kind: ClusterRoleBinding

apiVersion: rbac.authorization.k8s.io/v1

metadata:

  name: psp:psp

subjects:

- kind: Group

  name: system:authenticated

  apiGroup: rbac.authorization.k8s.io

roleRef:

  kind: ClusterRole

  name: psp:psp

  apiGroup: rbac.authorization.k8s.io




Приведенный выше файл создаст роль кластера с именем psp, которая может использовать нашу новую политику, которую мы назвали psp.




Это также создаст привязку роли на уровне кластера, которая предоставляет доступ к роли psp: psp каждому аутентифицированному пользователю.




Сохраните и закройте файл.




Создайте эту политику с помощью команды:




kubectl apply -f rbac-psp.yaml




Теперь мы создали политику и контроль RBAC.




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




Введите команду:




kubectl auth can-i use psp/psp




Выход должен сказать «yes».




Конечно, система должна сказать «yes», так как я пользователь с правами администратора.




Но что, если мы проверим это с другим пользователем?




Сделайте это с помощью команды:




kubectl auth can-i use psp/psp




Теперь вы должны увидеть «no» в ответе.




Вы только что создали политику безопасности пода Kubernetes, присвоили ей RBAC и протестировали ее, чтобы убедиться, что политика действительно работает.




Источник: https://sidmid.ru/kubernetes-создать-политику-безопасности-rbac/



2023-01-02T05:56:31
DevOps

Установка и настройка Pushgateway для Prometheus

По умолчанию, метрики в Prometheus попадают методом pull — система обращается к агентам (exporter) и забирает данные. Это рекомендованный способ, но мы можем настроить получение метрик методом push с помощью Pushgateway. Схема работы следующая: метрика отправляется скриптом на сервер Pushgateway, а Prometheus забирает данные уже с него.




Установка Pushgateway




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




Переходим на официальную страницу загрузки Pushgateway. Копируем ссылку для скачивания бинарника под Linux:





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




wget https://github.com/prometheus/pushgateway/releases/download/v1.3.1/pushgateway-1.3.1.linux-amd64.tar.gz




Распаковываем архив:




tar zxvf pushgateway-*.tar.gz




Копируем бинарник в каталог /usr/local/bin:




cp pushgateway-*/pushgateway /usr/local/bin/




Создаем пользователя pushgateway:




useradd —no-create-home —shell /bin/false pushgateway




Задаем владельца для нашего бинарника:




chown pushgateway:pushgateway /usr/local/bin/pushgateway




Для возможности запуска Pushgateway в качестве сервиса, создаем юнит-файл:




vi /etc/systemd/system/pushgateway.service




[Unit]

Description=Pushgateway Service

After=network.target



[Service]

User=pushgateway

Group=pushgateway

Type=simple

ExecStart=/usr/local/bin/pushgateway 

    --web.listen-address=":9091" 

    --web.telemetry-path="/metrics" 

    --persistence.file="/tmp/metric.store" 

    --persistence.interval=5m 

    --log.level="info" 

    --log.format="json"

ExecReload=/bin/kill -HUP $MAINPID

Restart=on-failure



[Install]

WantedBy=multi-user.target




* в данном примете мы запустим pushgateway на порту 9091. Также мы указали уровень и формат логов — сами логи можно будет увидеть в файлах /var/log/syslog (Ubuntu) или /var/log/messages (CentOS).




Перечитываем конфигурацию systemd:




systemctl daemon-reload




Разрешаем автозапуск сервиса и стартуем его:




systemctl enable pushgateway —now




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




systemctl status pushgateway




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





Pushgateway готов к работе. Переходим к настройке Prometheus.




Настройка Prometheus




Необходимо добавить задание в Prometheus для подключения к серверу Pushgateway и получения с него метрик. Это делается по такому же принципу, что и получение метрик с экспортеров.




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




vi /etc/prometheus/prometheus.yml




В секцию scrape_configs добавим задание:




...

scrape_configs:

  ...

  - job_name: 'pushgateway'

    honor_labels: true

    static_configs:

      - targets: ['localhost:9091']




* в данном задании мы говорим серверу Prometheus забирать метрики с сервера localhost (локальный сервер) на порту 9091.




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




systemctl restart prometheus




Проверяем, что сервис работает корректно:




systemctl status prometheus




Можно попробовать отправить метрики в Pushgateway.




Отправка метрик методом push в Pushgateway




Отправку данных можно выполнить http-запросом из bash, например, с помощью пакета curl. Синтаксис следующий:




echo «<Название для метрики> <Значение метрики>» | curl —data-binary @- http://<IP-адрес сервера pushgateway>:9091/metrics/job/<Тег для job>/instance/<Тег для instance>




Например:




echo «Temperature +15» | curl —data-binary @- http://localhost:9091/metrics/job/temperature_metrics/instance/localhost




* в данном примере мы передадим на локальный сервер pushgateway (localhost:9091) метрику Temperature со значением +15.




Теперь мы можем перейти в браузере по адресу http://<IP-адрес сервера pushgateway>:9091/metrics и увидеть отправленную ранее метрику:





Для удаления метрики можно использовать также curl с типом запроса delete, например:




curl -X DELETE http://localhost:9091/metrics/job/temperature_metrics/instance/localhost




Также, удалить группу метрик можно в веб-интерфейсе Pushgateway.




Скрипт на Python




В качестве примера, рассмотрим скрипт, написанный на Python. Для начала, необходимо установить модуль prometheus_client:




pip3 install prometheus_client




Сам скрипт будет выглядеть таким образом:




#!/usr/bin/env python3

# -*- encoding: utf-8 -*-



from prometheus_client import CollectorRegistry, Gauge, push_to_gateway



registry = CollectorRegistry()

g = Gauge('temperature_metrics', 'Description metric', registry=registry)

g.set(22)

push_to_gateway('localhost:9091', job='temperature_lobby', registry=registry)




в данном примере мы отправим в Prometheus через Pushgateway метрику temperature_metrics со значением 22 и job-тегом temperature_lobby.




Источник: https://sidmid.ru/установка-и-настройка-pushgateway-для-prometheus/



2023-01-02T05:42:02
DevOps

Kubernetes — Автоскейлинг приложений при помощи Prometheus и KEDA

Kubernetes позволяет автоматически масштабировать приложения (то есть Pod в развертывании или ReplicaSet) декларативным образом с использованием спецификации Horizontal Pod Autoscaler.




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




Вместо горизонтального автомасштабирования подов, применяется Kubernetes Event Driven Autoscaling (KEDA) — оператор Kubernetes с открытым исходным кодом. Он изначально интегрируется с Horizontal Pod Autoscaler, чтобы обеспечить плавное автомасштабирование (в том числе до/от нуля) для управляемых событиями рабочих нагрузок. Код доступен на GitHub.




Краткий обзор работы системы





На схеме — краткое описание того, как все работает:




  1. Приложение предоставляет метрики количества обращений к HTTP в формате Prometheus.



  2. Prometheus настроен на сбор этих показателей.



  3. Скейлер Prometheus в KEDA настроен на автоматическое масштабирование приложения на основе количества обращений к HTTP.




Теперь подробно расскажу о каждом элементе.




KEDA и Prometheus




Prometheus — набор инструментов для мониторинга и оповещения систем с открытым исходным кодом, часть Cloud Native Computing Foundation. Собирает метрики из разных источников и сохраняет в виде данных временных рядов. Для визуализации данных можно использовать Grafana или другие инструменты визуализации, работающие с API Kubernetes.




KEDA поддерживает концепцию скейлера — он действует как мост между KEDA и внешней системой. Реализация скейлера специфична для каждой целевой системы и извлекает из нее данные. Затем KEDA использует их для управления автоматическим масштабированием.




Скейлеры поддерживают нескольких источников данных, например, Kafka, Redis, Prometheus. То есть KEDA можно применять для автоматического масштабирования развертываний Kubernetes, используя в качестве критериев метрики Prometheus.




KEDA Prometheus ScaledObject




Скейлер действует как мост между KEDA и внешней системой, из которой нужно получать метрики. ScaledObject — настраиваемый ресурс, его необходимо развернуть для синхронизации развертывания с источником событий, в данном случае с Prometheus.




ScaledObject содержит информацию о масштабировании развертывания, метаданные об источнике события (например, секреты для подключения, имя очереди), интервал опроса, период восстановления и другие данные. Он приводит к соответствующему ресурсу автомасштабирования (определение HPA) для масштабирования развертывания.




Когда объект ScaledObject удаляется, соответствующее ему определение HPA очищается.




Вот определение ScaledObject для нашего примера, в нем используется скейлер Prometheus:




apiVersion: keda.k8s.io/v1alpha1

kind: ScaledObject

metadata:

 name: prometheus-scaledobject

 namespace: default

 labels:

  deploymentName: go-prom-app

spec:

 scaleTargetRef:

   deploymentName: go-prom-app

 pollingInterval: 15

 cooldownPeriod:  30

 minReplicaCount: 1

 maxReplicaCount: 10

 triggers:

 - type: prometheus

  metadata:

    serverAddress:

http://prometheus-service.default.svc.cluster.local:9090

    metricName: access_frequency

    threshold: '3'

    query: sum(rate(http_requests[2m]))




Учтите следующие моменты:




  1. Он указывает на Deployment с именем go-prom-app.



  2. Тип триггера — Prometheus. Адрес сервера Prometheus упоминается вместе с именем метрики, пороговым значением и запросом PromQL, который будет использоваться. Запрос PromQL — sum(rate(http_requests[2m])).



  3. Согласно pollingInterval, KEDA запрашивает цель у Prometheus каждые пятнадцать секунд. Поддерживается минимум один под (minReplicaCount), а максимальное количество подов не превышает maxReplicaCount (в данном примере — десять).




Можно установить minReplicaCount равным нулю. В этом случае KEDA активирует развертывание с нуля до единицы, а затем предоставляет HPA для дальнейшего автоматического масштабирования. Возможен и обратный порядок, то есть масштабирование от единицы до нуля. В примере мы не выбрали ноль, поскольку это HTTP-сервис, а не система по запросу.




Магия внутри автомасштабирования




Пороговое значение используют в качестве триггера для масштабирования развертывания. В нашем примере запрос PromQL sum(rate (http_requests [2m])) возвращает агрегированное значение скорости HTTP-запросов (количество запросов в секунду), ее измеряют за последние две минуты.




Поскольку пороговое значение равно трем, значит, будет один под, пока значение sum(rate (http_requests [2m])) меньше трех. Если же значение возрастает, добавляется дополнительный под каждый раз, когда sum(rate (http_requests [2m])) увеличивается на три. Например, если значение от 12 до 14, то количество подов — четыре.




Теперь давайте попробуем настроить!




Установка KEDA




Вы можете развернуть KEDA несколькими способами, они перечислены в документации. Я использую монолитный YAML:




[root@kub-master-1 ~]# wget https://github.com/kedacore/keda/releases/download/v2.1.0/keda-2.1.0.yaml
[root@kub-master-1 ~]# kubectl apply -f keda-2.1.0.yaml




ну или можно установить через helm




helm repo add kedacore https://kedacore.github.io/charts
helm repo update
kubectl create namespace keda
helm install keda kedacore/keda —namespace keda




я ставил через монолитный файл.
проверим что всё поднялось:




[root@kub-master-1 ~]# kubectl get all -n keda

NAME                                          READY   STATUS    RESTARTS   AGE

pod/keda-metrics-apiserver-57cbdb849f-w7rfg   1/1     Running   0          70m

pod/keda-operator-58cb545446-5rblj            1/1     Running   0          70m



NAME                             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE

service/keda-metrics-apiserver   ClusterIP   10.100.134.31   <none>        443/TCP,80/TCP   70m



NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE

deployment.apps/keda-metrics-apiserver   1/1     1            1           70m

deployment.apps/keda-operator            1/1     1            1           70m



NAME                                                DESIRED   CURRENT   READY   AGE

replicaset.apps/keda-metrics-apiserver-57cbdb849f   1         1         1       70m

replicaset.apps/keda-operator-58cb545446            1         1         1       70m





3. Пример работы




создаём namespace




kubectl create ns my-site




запускаем обычное приложение например apache:




[root@kub-master-1 ~]# cat my-site.yaml




---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: my-deployment-apache

  namespace: my-site

spec:

  replicas: 1

  selector:

    matchLabels:

      app: apache # по вот этому лейблу репликасет цепляет под

# тут описывается каким мокаром следует обновлять поды

  strategy:

    rollingUpdate:

      maxSurge: 1  # указывает на какое количество реплик можно увеличить

      maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить

#т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под)

    type: RollingUpdate

## тут начинается описание контейнера

  template:

    metadata:

      labels:

        app: apache  # по вот этому лейблу репликасет цепляет под

    spec:

      containers:

        - image: httpd:2.4.43

          name: apache

          ports:

            - containerPort: 80

# тут начинаются проверки по доступности

          readinessProbe: # проверка готово ли приложение

            failureThreshold: 3 #указывает количество провалов при проверке

            httpGet:  # по сути дёргает курлом на 80 порт

              path: /

              port: 80

            periodSeconds: 10 #как часто должна проходить проверка (в секундах)

            successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок

            timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда

          livenessProbe: #проверка на жизнь приложения, живо ли оно

            failureThreshold: 3

            httpGet:

              path: /

              port: 80

            periodSeconds: 10

            successThreshold: 1

            timeoutSeconds: 1

            initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд



# тут начинается описание лимитов для пода

          resources:

            requests: #количество ресурсов которые резервируются для pod на ноде

              cpu: 60m

              memory: 200Mi

            limits: #количество ресурсов которые pod может использовать(верхняя граница)

              cpu: 120m

              memory: 300Mi




[root@kub-master-1 ~]# cat my-site-service.yaml




---

apiVersion: v1

kind: Service

metadata:

  name: my-service-apache # имя сервиса

  namespace: my-site

spec:

  ports:

  - port: 80  # принимать на 80

    targetPort: 80 # отправлять на 80

  selector:

    app: apache  #отправлять на все поды с данным лейблом

  type: ClusterIP




[root@kub-master-1 ~]# cat my-site-ingress.yaml




---

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: my-ingress

  namespace: my-site

spec:

  rules:

  - host: test.ru  #тут указывается наш домен

    http:

      paths:  #список путей которые хотим обслуживать(он дефолтный и все запросы будут отпаврляться на бэкенд, т.е. на сервис my-service-apache)

      - backend:

          serviceName: my-service-apache  #тут указывается наш сервис 

          servicePort: 80 #порт на котором сервис слушает

#        path: /  все запросы на корень '/' будут уходить на наш сервис





применяем:




[root@kub-master-1 ~]# kubectl apply -f my-site.yaml -f my-site-service.yaml -f my-site-ingress.yaml




проверяем:




[root@kub-worker-1 ~]# curl test.ru
<html><body><h1>It works!</h1></body></html>




[root@kub-master-1 ~]# kubectl get all -n my-site




NAME                                        READY   STATUS    RESTARTS   AGE

pod/my-deployment-apache-859486bd8c-k6bql   1/1     Running   0          20m



NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE

service/my-service-apache   ClusterIP   10.100.255.190   <none>        80/TCP    20m



NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE

deployment.apps/my-deployment-apache   1/1     1            1           20m



NAME                                              DESIRED   CURRENT   READY   AGE

replicaset.apps/my-deployment-apache-859486bd8c   1         1         1       20m





будем автоскейлить — для примера по метрике nginx nginx_ingress_controller_requests




запрос в prometheus будет следующий:




sum(irate( nginx_ingress_controller_requests{namespace=»my-site»}[3m] )) by (ingress)*10




т.е. считаем общее количество запросов в неймспейс my-site за 3 минуты




создаём keda сущность:




[root@kub-master-1 ~]# cat hpa-keda.yaml




apiVersion: keda.sh/v1alpha1

kind: ScaledObject

metadata:

  name: prometheus-scaledobject

  namespace: my-site

spec:

  scaleTargetRef:

    name: my-deployment-apache

  minReplicaCount: 1   # Optional. Default: 0

  maxReplicaCount: 8 # Optional. Default: 100

  triggers:

  - type: prometheus

    metadata:

      serverAddress: http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090

      metricName: nginx_ingress_controller_requests

      threshold: '100'

      query: sum(irate(nginx_ingress_controller_requests{namespace="my-site"}[3m])) by (ingress)*10




тут мы указываем в каком namespace нам запускаться:
namespace: my-site




указываем цель, т.е. наш deployment:
name: my-deployment-apache




задаём минимальное и максимальное количество реплик
minReplicaCount: 1 # значение по умолчанию: 0
maxReplicaCount: 8 # значение по умолчанию: 100




есть ещё 2 стандартные переменные отвечающие за то когда поды будут подыматься и убиваться:
pollingInterval: 30 # Optional. Default: 30 seconds
cooldownPeriod: 300 # Optional. Default: 300 seconds




указываем адрес нашего prometheus




serverAddress: http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090
адрес идёт в виде сервис.неймспейс.svc.имя_кластера




указываем нашу метрику:
metricName: nginx_ingress_controller_requests




указываем пороговое значение при котором начнётся автоскейлинг:
threshold: ‘100’




и соответственно наш запрос в prometheus:
query:




всё можно применять:




[root@kub-master-1 ~]# kubectl apply -f hpa-keda.yaml




проверяем:




[root@kub-master-1 ~]# kubectl get horizontalpodautoscalers.autoscaling -n my-site

NAME                               REFERENCE                         TARGETS       MINPODS   MAXPODS   REPLICAS   AGE

keda-hpa-prometheus-scaledobject   Deployment/my-deployment-apache   0/100 (avg)   1         8         1          68m





[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS    RESTARTS   AGE

my-deployment-apache-859486bd8c-v59b8   1/1     Running   0          37m





а теперь накрутим запросов:




[root@kub-worker-1 ~]# for i in {1..5000}; do curl test.ru; done




проверяем:




[root@kub-master-1 ~]# kubectl get horizontalpodautoscalers.autoscaling -n my-site

NAME                               REFERENCE                         TARGETS            MINPODS   MAXPODS   REPLICAS   AGE

keda-hpa-prometheus-scaledobject   Deployment/my-deployment-apache   34858m/100 (avg)   1         8         7          71m





как видим количество запросов превысило наш лимит и стали создаваться новые поды:




[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS    RESTARTS   AGE

my-deployment-apache-859486bd8c-6885f   1/1     Running   0          49s

my-deployment-apache-859486bd8c-6mcq4   1/1     Running   0          64s

my-deployment-apache-859486bd8c-cdb6z   1/1     Running   0          64s

my-deployment-apache-859486bd8c-kpwb8   1/1     Running   0          64s

my-deployment-apache-859486bd8c-rmw8d   1/1     Running   0          49s

my-deployment-apache-859486bd8c-v59b8   1/1     Running   0          39m

my-deployment-apache-859486bd8c-xmv28   1/1     Running   0          49s





прекращаем запросы и спустя 5 минут, указанное в переменной cooldownPeriod ненужные поды будут убиты:




[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS        RESTARTS   AGE

my-deployment-apache-859486bd8c-6885f   0/1     Terminating   0          6m35s

my-deployment-apache-859486bd8c-6mcq4   1/1     Running       0          6m50s

my-deployment-apache-859486bd8c-cdb6z   0/1     Terminating   0          6m50s

my-deployment-apache-859486bd8c-kpwb8   0/1     Terminating   0          6m50s

my-deployment-apache-859486bd8c-rmw8d   0/1     Terminating   0          6m35s

my-deployment-apache-859486bd8c-v59b8   0/1     Terminating   0          44m

my-deployment-apache-859486bd8c-xmv28   0/1     Terminating   0          6m35s



[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS    RESTARTS   AGE

my-deployment-apache-859486bd8c-6mcq4   1/1     Running   0          7m48s





Источник: https://sidmid.ru/kubernetes-автоскейлинг-приложений-при-помощ/