- PVSM.RU - https://www.pvsm.ru -

Развертывание в Docker и Kubernetes образа StatsD+Grafana

В начале моего изучения Docker и Kubernetes мне нехватало простого и понятного примера, с которым можно было бы «поиграться», изучая особенности этой среды. Этой статьей хотелось бы закрыть этот пробел. Здесь я расскажу об интеграции .NET Core приложения с Telegraf и Grafana, о том, как шлются метрики и как деплоить в Docker и Kubernetes. Примеры в статье расчитаны на тех, кто начинает изучать данную область, но базовыми понятиями желательно обладать, чтобы полностью понять статью. В ней описано, как развернуть контейнер, в котором есть StatsD, InfluxDB и Grafana, а также, как отправлять метрики различных типов из приложения.

Примеры в этой статье выполнялись на Kubernetes, идущем с Docker for Windows. Но если у вас Windows Home Edition, то вам не удастся его поставить. Если у вас Windows Professional, то проблем возникнуть не должно. Тут [1] есть пара советов по установке kubernetes на Windows. На Linux должно всё работать нормально, проверял на Ubuntu, 18.04 LTS.

Демонстрация

Сперва, давайте посмотрим, как всё, о чем буду рассказывать, выглядит в действии. В этом примере вы запустите два приложения: одно отправляет запросы другому, второе выполняет некоторую сложную задачу, и оба приложения отправляют некоторые StatsD метрики, которые вы увидите в Grafana. Перед выполнением шагов, описанных здесь, вам необходимо убедиться, что Kubernetes установлен на вашем компьютере. Далее просто следуйте приведенным ниже инструкциям, и вы увидите некоторый результат. Правда, некоторые настройки вам нужно будет выполнить самостоятельно.

$ git clone https://github.com/xtrmstep/DockerNetSample
$ cd .DockerNetSample
$ kubectl apply -f .srcStatsDServerk8s-deployment.yaml
$ .build.ps1
$ .run.ps1

Теперь в браузере можно загрузить URL localhost [2]:3003 и, используя учетные данные root/root, можно получить доступ к интерфейсу Grafana. Метрики уже отправляются, и вы можете попробовать добавить свой дэшбоард. После некоторой настройки вы можете получить что-то вроде этого.

Развертывание в Docker и Kubernetes образа StatsD+Grafana - 1

Когда вы решите всё остановить и очистить ресурсы, просто закройте два окна с рабочими процессами и выполните следующие команды, которые очистят объекты в Kubernetes:

$ kubectl delete svc stats-tcp
$ kubectl delete svc stats-udp
$ kubectl delete deployment stats

Теперь давайте поговорим, что произошло.

Вы задеплоили StatsD, InfluxDb и Grafana на локальный Kubernetes

Не так давно открыл для себя, что DockerHub имеет много полезных и уже подготовленных образов. В своём примере я использую один из таких. Репозиторий с образом вы можете найти здесь [3]. Этот образ содержит InfluxDB, Telegraf (StatsD) и Grafana, которые уже настроены для совместной работы. Есть два распространенных способа деплоя образов: первый — это используя docker-compose в Docker, и второй — это деплой на Kubernetes. Оба способа дают возможность деплоить сразу несколько компонетов (образов), описывать настройки сети и другие параметры. Я кратко расскажу о docker-compose, но более детально остановлюсь на развертывании в Kubernetes. Кстати, недавно стало возможным деплоить docker-compose в Kubernetes [4].

Развертывание с помощью Docker-Compose

Docker-compose распространяется вместе с Docker для Windows. Но вам нужно проверить, какую версию вы можете использовать в своем YAML. Для этого надо узнать версию установленного Docker и по матрице совместимости [5] найти нужную версию. Я установил Docker версии 19.03.5, поэтому я могу использовать файл версии 3.x. Но я буду использовать 2 для совместимости с прошлыми версиями Docker. Вся необходимая информация для написание docker-compose файлы уже есть в описании репозитория: имя образа и порты.

version: '2'
services:
  stats:
    image: samuelebistoletti/docker-statsd-influxdb-grafana:latest
    ports:
      - "3003:3003"
      - "3004:8888"
      - "8086:8086"
      - "8125:8125/udp"

В секции ports я делаю видимыми порты из контейнера через порты хост-системы. Если я этого не сделаю, я не смогу получить доступ к ресурсам в контейнере из хост-системы, потому что они будут видны только внутри Docker. Грубо говоря, я не смогу загрузить Grafana в браузере. Подробнее о маппинге портов вы можете почитать здесь [6]. После составления файла, можно его задеплоить. По умолчанию, docker-compose ищет файл docker-compose.yaml в текущей папке, поэтому вы можете запустить его с минимальными параметрами, просто выполнив команду docker-compose up. Это развернет контейнер в Docker. Я буду использовать дополнительные параметры для явного указания файла и запуска контейнера в фоновом режиме.

$ docker-compose -f docker-compose.yaml up -d
$ docker-compose stop

Развёртывание в Kubernetes

На первый взгляд, развертывание в Kubernetes выглядит несколько сложнее, поскольку вам необходимо определить Deployment, Service и другие параметры. Я прибегаю к небольшой хитрости, которая экономит мне время на написание YAML-файлов для Kubernetes. Сначала я деплою все в минимальной конфигурации в кластер, используя kubectl. А затем экспортирую нужные мне объекты, как YAML и уже потом дописываю необходимые настройки.

Заметка о Kubernetes, устанавливаемом на виртуальных машинах в GCP
Я пытался использовать Kubernetes, который развернут на Compute Engine в GCP и столкнулся с проблемой при развертывании сервиса LoadBalancer. Он остаётся в состоянии pending и не получает внешний IP-адрес. Это обстоятельство препятствует доступу к сервису из Интернета, даже если вы настроили сеть. Для этого есть решение, которое требует установки ingress сервиса и использования NodePort, согласно совету на Stackoverflow [7].

Развёртывание с kubectl

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

$ kubectl run stats --image=samuelebistoletti/docker-statsd-influxdb-grafana:latest --image-pull-policy=Always

Эта команда создаст Deployment, который, в свою очередь, создаст Pod и ReplicaSet в k8s. Чтобы получить доступ к Grafana, мне нужно создать сервис и выставить порты. Это можно сделать с помощью службы NodePort или LoadBalancer. В большинстве случаев вы будете создавать службы LoadBlancer. Почитать больше об этом можно тут [8].

$ kubectl expose deployment stats --type=LoadBalancer --port=3003 --target-port=3003

Эта команда также сопоставит порт хоста 3003 (--port) с портом в контейнере (--target-port). После выполнения команды вы сможете получить доступ к Grafana, загрузив URL localhost [2]:3003 в браузере. Вы можете проверить созданные объекты в k8s с помощью этой команды:

$ kubectl get all

Вы должны увидеть что-то, как на это картинке:

Развертывание в Docker и Kubernetes образа StatsD+Grafana - 2

Экспорт YAML конфигурации

На данный момент, развернутая система ещё не то, что мне нужно, но я могу использовать её, как черновик. Экспортируем конфигурацию YAML:

$ kubectl get deployment,service stats -o yaml --export > exported.yaml

Экспортированный файл будет содержать определения Deployment и Service с текущей конфигурацией. Мне нужно будет удалить ненужные настройки и добавить маппинг портов. Окончательный минималистский вариант может выглядеть следующим образом:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: stats
spec:
  replicas: 1
  selector:
    matchLabels:
      run: stats
  template:
    metadata:
      labels:
        run: stats
    spec:
      containers:
      - image: samuelebistoletti/docker-statsd-influxdb-grafana:latest
        imagePullPolicy: Always
        name: stats
---
apiVersion: v1
kind: Service
metadata:
  name: stats-tcp
spec:
  type: LoadBalancer
  ports:
    - name: grafana
      protocol: TCP
      port: 3003
      targetPort: 3003
    - name: influxdb-admin
      protocol: TCP
      port: 3004
      targetPort: 8888
    - name: influxdb
      protocol: TCP
      port: 8086
      targetPort: 8086
  selector:
    run: stats
---
apiVersion: v1
kind: Service
metadata:
  name: stats-udp
spec:
  type: LoadBalancer
  ports:
    - name: telegraf
      protocol: UDP
      port: 8125
      targetPort: 8125
  selector:
    run: stats

Заметка об использовании протоколов TCP/UDP
Вы не сможете создать службу типа LoadBalancer, которая поддерживает протоколы TCP и UDP. Это известное ограничение, и сообщество пытается найти какое-то решение [9]. Между тем вы можете создать два отдельных сервиса для каждого из типов протоколов.

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

$ kubectl delete svc stats
$ kubectl delete deployment stats

$ kubectl apply -f k8s-deployment.yaml

Вы только что задеплоили образ в Kubernetes с правильными настройками портов. Используя URL, упоминавшийся выше, вы можете открыть Grafana, но теперь еще можно слать и метрики StatsD. В следующем разделе я немного расскажу про метрики.

StatsD протокол

Протокол StatsD очень прост, вы, даже, можете создать свою собственную клиентскую библиотеку, если это очень нужно. Здесь [10] вы можете прочитать больше о датаграммах StatsD. Этот протокол поддерживает такие метрики, как счетчики (counter), время (timing), измерения (gauge) и т.д.

counter.name:1|c
timing.name:320|ms
gauge.name:333|g

Counters используются для подсчета количества некоторых событий. Обычно, вы просто всегда увеличиваете некоторый счетчик (bucket в StatsD). Агрегация делается на более низком уровне, поэтому когда вы будете получать значение за секунды, минуты, вам не придется заниматься дополнительными подсчетами, и в Grafana вы увидите число в секундах, минутах и так далее, как пожелаете.

Timing используется для измерения продолжительности какого-либо процесса. Например, этот показатель просто идеально подходит для измерения продолжительности веб-запроса.

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

Метрики в .NET Core сервисе

Вам понадобится пакет NuGet JustEat.StatsD [11]. Он имеет хорошее описание на GitHub. Так что, просто следуйте его инструкциям, чтобы сделать свою собственную конфигурацию и зарегистрироваться в IoC.

В качестве примера, давайте возьмем API, где некоторый метод, когда вызван, ставит расчет в очередь потоков, используя ThreadPool. Логика API допускает только определенное количество параллельно выполняемых вычислений. Допустим, вы хотите знать следующее о вашем сервисе:

  • Сколько запросов приходит?
  • Сколько запросов ожидает, прежде чем ThreadPool выдаст поток?
  • Сколько времени занимает операция?
  • Насколько быстро заканчиваются свободные потоки в API?

Вот как может выглядеть сбор метрик в коде:

public override async Task<FactorialReply> Factorial(FactorialRequest request, ServerCallContext context)
{
    // Obtain the number of available threads in ThreadPool
    ThreadPool.GetAvailableThreads(out var availableThreads, out _);
    // The number of available threads is the example of Gauge metric
    // Send gauge metric to StatsD (using JustEat.StatsD nuget)
    _stats.Gauge(availableThreads, "GaugeAvailableThreads");
    
    // Increment a counter metric for incoming requests
    _stats.Increment("CountRequests");
    
    // The method _stats.Time() will calculate the time while the _semaphoreSlim.WaitAsync() were waiting
    // and send the metric to StatsD
    await _stats.Time("TimeWait", async f => await _semaphoreSlim.WaitAsync());

    try
    {
        // Again measure time length of calculation and send it to StatsD 
        var result = await _stats.Time("TimeCalculation", async t => await CalculateFactorialAsync(request.Factor));

        // Increment a counter of processed requests
        _stats.Increment("CountProcessed");

        return await Task.FromResult(new FactorialReply
        {
            Result = result
        });
    }
    finally
    {
        _semaphoreSlim.Release();
    }
}

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

Автор: Aleksandr Goida

Источник [12]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/net/345138

Ссылки в тексте:

[1] Тут: http://binary-notes.ru/hints-about-installation-of-kubernates-on-windows-and-deploying-to-cluster/

[2] localhost: http://localhost

[3] здесь: https://github.com/samuelebistoletti/docker-statsd-influxdb-grafana

[4] деплоить docker-compose в Kubernetes: https://www.docker.com/blog/simplifying-kubernetes-with-docker-compose-and-friends/

[5] матрице совместимости: https://docs.docker.com/compose/compose-file/compose-versioning/

[6] здесь: https://docs.docker.com/compose/compose-file/compose-file-v2/#ports

[7] совету на Stackoverflow: https://stackoverflow.com/questions/44110876/kubernetes-service-external-ip-pending

[8] тут: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types

[9] сообщество пытается найти какое-то решение: https://github.com/kubernetes/kubernetes/issues/23880

[10] Здесь: https://github.com/statsd/statsd/blob/master/docs/metric_types.md

[11] JustEat.StatsD: https://github.com/justeat/JustEat.StatsD

[12] Источник: https://habr.com/ru/post/486172/?utm_source=habrahabr&utm_medium=rss&utm_campaign=486172