Задача – иметь перед глазами график в Grafana, который будет отображать расходы на AWS.
Есть два варианта – использовать експортер от Prometheus – prom/cloudwatch-exporter, или самописный от nachomillangarcia – prometheus_aws_cost_exporter.
Первый собирает метрики от AWS CloudWatch, в которые данные по биллингу поступают только на следующий день.
Второй написан на Python, ходит к AWS API, получает оттуда данные, и позволяет видеть расходы за сегодняшний день.
Сначала поднимем prometheus_aws_cost_exporter, который будет нам отображать данные по каждому сервису (EC2, RDS, S3, etc) за месяц, а потом добавим prom/cloudwatch-exporter, который будет отображать общий расход денег за сегодня.
Содержание
Запуск prometheus_aws_cost_exporter
Для проверки запускаем в Docker:
[simterm]
root@monitoring-dev:/opt/prometheus# docker run -e METRIC_TODAY_DAILY_COSTS=yes -p 5000:5000 nachomillangarcia/prometheus_aws_cost_exporter:latest ... botocore.exceptions.ClientError: An error occurred (AccessDeniedException) when calling the GetCostAndUsage operation: User: arn:aws:sts::534***385:assumed-role/CloudWatchAgentAccessRole-monitoring-dev/i-030d900fa25f2619b is not authorized to perform: ce:GetCostAndUsage on resource: arn:aws:ce:us-east-1:534***385:/GetCostAndUsage
[/simterm]
Ага – нет прав на выполнение API запроса GetCostAndUsage
.
Используем ЕС2 IAM profiles, см. пост AWS: ротация ключей IAM пользователей, EC2 IAM Roles и Jenkins и документацию тут>>>.
EC2 instance IAM profile
Переходим к ЕС2 с сервером мониторинга, правой кнопкой – Instance Settings > Attach/Replace IAM Role:
Копируем имя роли:
Переходим в IAM, находим её:
И подключенную к ней политику:
Копируем содержимое CloudWatchAgentServerPolicy, и создаём новую политику с правом на выполнение вызова ce:GetCostAndUsage
для ресурсов arn:aws:ce:*:*:/GetCostAndUsage
:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "cloudwatch:PutMetricData", "ec2:DescribeVolumes", "ec2:DescribeTags", "logs:PutLogEvents", "logs:DescribeLogStreams", "logs:DescribeLogGroups", "logs:CreateLogStream", "logs:CreateLogGroup", "ce:GetCostAndUsage" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ssm:GetParameter" ], "Resource": [ "arn:aws:ssm:*:*:parameter/AmazonCloudWatch-*", "arn:aws:ce:*:*:/GetCostAndUsage" ] } ] }
Назовём её monitoring-cloudwatch-access-policy:
Переходим в Roles, создаём новую роль, назовём её monitoring-cloudwatch-access-role, и к ней подключаем созданную политику:
Возвращаемся к инстансу, подключаем новую роль в качеcтве EC2 IAM профиля:
Перезапускаем контейнер с експортером:
[simterm]
root@monitoring-dev:/opt/prometheus# docker run -e METRIC_TODAY_DAILY_COSTS=yes -p 5000:5000 nachomillangarcia/prometheus_aws_cost_exporter:latest * Serving Flask app "app.py" * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
[/simterm]
В последней строке сказано “Running on http://127.0.0.1:5000/” – значит доступен только из контейнера.
Запускаем с опцией --host 0.0.0.0
:
[simterm]
root@monitoring-dev:/opt/prometheus# docker run -e METRIC_TODAY_DAILY_COSTS=yes -p 5000:5000 nachomillangarcia/prometheus_aws_cost_exporter:latest --host 0.0.0.0
[/simterm]
И проверяем метрики:
[simterm]
admin@monitoring-dev:~$ curl -sL localhost:5000/metrics | grep -v \# process_virtual_memory_bytes 373948416.0 process_resident_memory_bytes 39677952.0 process_start_time_seconds 1583405899.25 process_cpu_seconds_total 0.47 process_open_fds 7.0 process_max_fds 1048576.0 python_info{implementation="CPython",major="3",minor="7",patchlevel="0",version="3.7.0"} 1.0 aws_today_daily_costs 625.3538325784
[/simterm]
Окей – работает.
Docker Compose и Prometheus
Наш стек мониторинга запускается из Docker Compose файла:
[simterm]
root@monitoring-dev:/opt/prometheus# cat prometheus-compose.yml | grep image image: prom/prometheus:v2.8.0 image: prom/node-exporter:v0.16.0 image: grafana/grafana:5.4.3 image: prom/cloudwatch-exporter:latest image: prom/cloudwatch-exporter:latest image: prom/cloudwatch-exporter:latest image: prom/blackbox-exporter:v0.14.0 image: prom/alertmanager:v0.16.1 image: grafana/loki:master-125cfbf image: grafana/grafana:6.5.0 image: grafana/promtail:master-2739551
[/simterm]
И експортер хочется добавить сюда же.
Но есть проблема: стек мониторинга работает в сети prometehus:
version: '2.4' networks: prometheus: services: prometheus-server: image: prom/prometheus:v2.8.0 networks: - prometheus ports: - 9090:9090 ...
Експортер запускается на 127.0.0.1:
[simterm]
root@monitoring-dev:/opt/prometheus# docker logs prometheus_aws-exporter_1 ... * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
[/simterm]
Но как из Prometehus достучаться к екпортеру?
Если внутри сети prometheus из контейнера с prometheus-сервером мы обратимся на 127.0.0.1:5000 – мы попадём в контейнер Prometheus, а не експортера.
А что бы попасть на контейнер с екпортером – нам надо в конфиге Prometheus использовать имя типа aws-exporter, как оно задано в Compose файле – тогда Docker сам выполнит разрешение имени aws-exporter в IP контейнера, и зароутит трафик.
Но внутри контейнера приложение-то всё-равно слушает 127.0.0.1 – и даже через внешний IP мы к нему доступ не получим.
Зная из документации експортера, что у нас там Flask – гуглим его переменные, и находим тут>>>:
Click is configured to load default values for command options from environment variables. The variables use the pattern FLASK_COMMAND_OPTION. For example, to set the port for the run command, instead of flask run –port 8000
Пробуем – добавляем в Compose файл переменную FLASK_RUN_HOST
:
... aws-exporter: image: nachomillangarcia/prometheus_aws_cost_exporter networks: - prometheus ports: - 5000:5000 environment: - METRIC_TODAY_DAILY_COSTS=yes - FLASK_RUN_HOST=0.0.0.0 restart: unless-stopped ...
В конфиге Prometheus добавляем новый таргет, используя aws-exporter, как имя хоста, что бы зарезолвить через Docker и его сеть:
... - job_name: 'aws-billing' metrics_path: '/metrics' static_configs: - targets: ['aws-exporter:5000'] ...
Перезапускаем стек, проверяем:
Проверяем метрику aws_today_daily_costs
– данные пошли:
CloudWatch exporter
Запуск екпортера уже описывался:
Prometheus: CloudWatch exporter – сбор метрик из AWS и графики в Grafana
Так что тут просто быстрый пример добавления сборов метрик биллинга.
Запускаем в us-east-1, N. Virgina, т.к. метрики биллинга CloudFormation собирает там (вообще это самый первый регион AWS).
У нас настройки харнятся в файле /etc/prometheus/prometheus-cloudwatch-exporter-us-east-1.yml
, добавляем в него AWS/Billing
:
set_timestamp: false delay_seconds: 60 metrics: - aws_namespace: "AWS/Billing" aws_dimensions: [Currency,ServiceName] aws_dimensions_select: Currency: [USD] aws_metric_name: EstimatedCharges aws_statistics: [Average] range_seconds: 86400 - aws_namespace: AWS/RDS aws_metric_name: FreeStorageSpace aws_dimensions: [DBInstanceIdentifier] ...
Перезапускаем, и проверяем метрику aws_billing_estimated_charges_average
:
Получаем значение по каждому сервису – на сколько денег сервис наработал с начала месяца.
Потом собираем всё в Grafana примерно так:
Можно выбрать только нужные метрики с регуляркой типа aws_billing_estimated_charges_average{service_name =~ "AmazonS3|AmazonRoute53"}
.
Готово.