Amazon Managed Service for Prometheus 实战
作者 | 顾暑晨 翻译
来源 | 新钛云服(ID:newtyun)
转载请联系授权(微信ID:zlm935177782)
Amazon Prometheus托管服务(AMP)是与Prometheus兼容的监控服务,用于容器基础架构和应用程序指标监控,让用户可以轻松并安全地监控大规模容器环境。Prometheus支持各种度量标准收集机制,其中包括许多库和服务器,这些库和服务器可帮助从第三方系统导出特定于应用程序的度量标准作为Prometheus的度量标准。
你还可以使用AWS Distro for OpenTelemetry从环境中提取应用程序指标。借助AMP,你可以使用与当今相同的开源Prometheus数据模型和查询语言来监视容器的工作负载和性能。使用该服务不需要任何前期投资,你只需为获取的指标数量付费。
在容器环境中使用Prometheus的用户在管理高可用性、可扩展性、服务器环境安全性、长期存储的基础架构以及访问控制方面面临挑战。
AMP通过提供与AWS Identity and Access Management(IAM)紧密集成的完全托管环境来控制身份验证和授权,从而解决了这些问题。你可以按照以下两个简单步骤开始使用AMP:
- 创建一个AMP工作区
- 配置Prometheus服务器以远程写入AMP工作区
配置完成后,你将能够使用完全托管的AMP环境来获取,存储和查询指标。在此文章中,我们将逐步介绍设置AMP从部署到Amazon EKS集群的容器化工作负载中收集自定义Prometheus指标所需的步骤,然后使用Grafana对其进行查询和可视化。
基础架构
下图说明了适用于Prometheus的Amazon Managed Service的总体架构及其与其他组件的交互。
设置工作区以收集Prometheus指标
首先,你需要创建一个工作区。工作区是概念性的位置,你可以在其中提取,存储和查询从应用程序工作负载(与其他AMP工区间隔离)中收集的Prometheus指标。可以在同一AWS账户内的每个区域中创建一个或多个工作区,并且每个工作区可用于从多个工作负载中提取指标,这些工作负载以Prometheus兼容格式导出指标。
用户管理的具有以下权限的IAM策略应与管理工作区的IAM用户关联:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"aps:CreateWorkspace",
"aps:DeleteWorkspace",
"aps:DescribeWorkspace",
"aps:ListWorkspaces",
"aps:UpdateWorkspaceAlias"
],
"Resource": "*"
}
]
}
从AWS管理控制台创建一个工作区,如下所示:
△创建工作区
△工作区列表
接下来,作为可选步骤,你将创建接口VPC端点,以便让VPC内部署的资源安全地访问托管服务。这将确保托管服务提取的数据只保留在你的AWS账户的VPC中。你可以按照以下说明使用AWS CLI进行此操作。确保将占位符字符串(例如VPC_ID,AWS_REGION和其他字符串)替换为适当的值。
aws ec2 create-vpc-endpoint \
--vpc-id <VPC_ID> \
--service-name com.amazonaws.<AWS_REGION>.aps-workspaces \
--security-group-ids <SECURITY_GROUP_IDS> \
--vpc-endpoint-type Interface \
--subnet-ids <SUBNET_IDS>
在以上命令中,SECURITY_GROUP_IDS表示与VPC接口终端节点关联的安全组列表,以允许终端节点网络接口与VPC中的资源(例如Amazon EKS集群的工作节点)之间进行通信。SUBNET_IDS代表这些资源所在的子网列表。
配置权限
指标收集器(例如部署到Amazon EKS集群的Prometheus服务器)从集群中运行的容器化工作负载中抓取运行指标,并将其发送给AMP进行长期存储以及随后通过监控工具进行查询。
数据是使用HTTP请求发送的,必须使用AWS Signature版本4算法并且使用有效的AWS凭证对HTTP请求进行签名,以对托管服务的每个客户端请求进行身份验证和授权。为了简化此过程,将请求发送到一个AWS签名代理实例,该实例会将请求转发到托管服务。
可以将AWS Signing代理部署到Amazon EKS集群以在Kubernetes服务帐户的身份下运行。借助服务帐户(IRSA)的IAM角色,你可以将IAM角色与Kubernetes服务帐户关联,从而为使用该服务帐户的任何Pod提供AWS权限。通过使用IRSA安全配置AWS Signing代理,以帮助将Prometheus指标收集到AMP中,这遵循了最小特权原则。
将占位符变量YOUR_EKS_CLUSTER_NAME替换为Amazon EKS集群的名称后,可以使用以下所示的Shell脚本执行以下操作。
- 创建具有IAM策略的IAM角色,该IAM策略具有远程写入AMP工作区的权限
- 创建一个带有IAM角色注释的Kubernetes服务帐户
- 在IAM角色和Amazon EKS集群中托管的OIDC提供者之间创建信任关系
该脚本要求你已经安装了CLI工具kubectl和eksctl,并配置了它们对Amazon EKS集群的访问权限。
##!/bin/bash
CLUSTER_NAME=YOUR_EKS_CLUSTER_NAME
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
OIDC_PROVIDER=$(aws eks describe-cluster --name $CLUSTER_NAME --query "cluster.identity.oidc.issuer" --output text | sed -e "s/^https:\/\///")
PROM_SERVICE_ACCOUNT_NAMESPACE=prometheus
GRAFANA_SERVICE_ACCOUNT_NAMESPACE=grafana
SERVICE_ACCOUNT_NAME=iamproxy-service-account
SERVICE_ACCOUNT_IAM_ROLE=EKS-AMP-ServiceAccount-Role
SERVICE_ACCOUNT_IAM_ROLE_DESCRIPTION="IAM role to be used by a K8s service account with write access to AMP"
SERVICE_ACCOUNT_IAM_POLICY=AWSManagedPrometheusWriteAccessPolicy
SERVICE_ACCOUNT_IAM_POLICY_ARN=arn:aws:iam::$AWS_ACCOUNT_ID:policy/$SERVICE_ACCOUNT_IAM_POLICY
#
# Setup a trust policy designed for a specific combination of K8s service account and namespace to sign in from a Kubernetes cluster which hosts the OIDC Idp.
# If the IAM role already exists, then add this new trust policy to the existing trust policy
#
echo "Creating a new trust policy"
read -r -d '' NEW_TRUST_RELATIONSHIP <<EOF
[
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:sub": "system:serviceaccount:${GRAFANA_SERVICE_ACCOUNT_NAMESPACE}:${SERVICE_ACCOUNT_NAME}"
}
}
},
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:sub": "system:serviceaccount:${PROM_SERVICE_ACCOUNT_NAMESPACE}:${SERVICE_ACCOUNT_NAME}"
}
}
}
]
EOF
#
# Get the old trust policy, if one exists, and append it to the new trust policy
#
OLD_TRUST_RELATIONSHIP=$(aws iam get-role --role-name $SERVICE_ACCOUNT_IAM_ROLE --query 'Role.AssumeRolePolicyDocument.Statement[]' --output json)
COMBINED_TRUST_RELATIONSHIP=$(echo $OLD_TRUST_RELATIONSHIP$NEW_TRUST_RELATIONSHIP | jq -s add)
echo "Appending to the existing trust policy"
read -r -d '' TRUST_POLICY <<EOF
{
"Version": "2012-10-17",
"Statement": ${COMBINED_TRUST_RELATIONSHIP}
}
EOF
echo "${TRUST_POLICY}" > TrustPolicy.json
#
# Setup the permission policy grants write permissions for all AWS StealFire workspaces
#
read -r -d '' PERMISSION_POLICY <<EOF
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":[
"aps:RemoteWrite",
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata"
],
"Resource":"*"
}
]
}
EOF
echo "${PERMISSION_POLICY}" > PermissionPolicy.json
#
# Create an IAM permission policy to be associated with the role, if the policy does not already exist
#
SERVICE_ACCOUNT_IAM_POLICY_ID=$(aws iam get-policy --policy-arn $SERVICE_ACCOUNT_IAM_POLICY_ARN --query 'Policy.PolicyId' --output text)
if [ "$SERVICE_ACCOUNT_IAM_POLICY_ID" = "" ];
then
echo "Creating a new permission policy $SERVICE_ACCOUNT_IAM_POLICY"
aws iam create-policy --policy-name $SERVICE_ACCOUNT_IAM_POLICY --policy-document file://PermissionPolicy.json
else
echo "Permission policy $SERVICE_ACCOUNT_IAM_POLICY already exists"
fi
#
# If the IAM role already exists, then just update the trust policy.
# Otherwise create one using the trust policy and permission policy
#
SERVICE_ACCOUNT_IAM_ROLE_ARN=$(aws iam get-role --role-name $SERVICE_ACCOUNT_IAM_ROLE --query 'Role.Arn' --output text)
if [ "$SERVICE_ACCOUNT_IAM_ROLE_ARN" = "" ];
then
echo "$SERVICE_ACCOUNT_IAM_ROLE role does not exist. Creating a new role with a trust and permission policy"
#
# Create an IAM role for Kubernetes service account
#
SERVICE_ACCOUNT_IAM_ROLE_ARN=$(aws iam create-role \
--role-name $SERVICE_ACCOUNT_IAM_ROLE \
--assume-role-policy-document file://TrustPolicy.json \
--description "$SERVICE_ACCOUNT_IAM_ROLE_DESCRIPTION" \
--query "Role.Arn" --output text)
#
# Attach the trust and permission policies to the role
#
aws iam attach-role-policy --role-name $SERVICE_ACCOUNT_IAM_ROLE --policy-arn $SERVICE_ACCOUNT_IAM_POLICY_ARN
else
echo "$SERVICE_ACCOUNT_IAM_ROLE_ARN role already exists. Updating the trust policy"
#
# Update the IAM role for Kubernetes service account with a with the new trust policy
#
aws iam update-assume-role-policy --role-name $SERVICE_ACCOUNT_IAM_ROLE --policy-document file://TrustPolicy.json
fi
echo $SERVICE_ACCOUNT_IAM_ROLE_ARN
# EKS cluster hosts an OIDC provider with a public discovery endpoint.
# Associate this Idp with AWS IAM so that the latter can validate and accept the OIDC tokens issued by Kubernetes to service accounts.
# Doing this with eksctl is the easier and best approach.
#
eksctl utils associate-iam-oidc-provider --cluster $CLUSTER_NAME --approve
上面显示的脚本创建了一个名为EKS-AMP-ServiceAccount-Role的IAM角色,并将其附加到Prometheus和grafana命名空间下名为iamproxy-service-account的Kubernetes服务帐户中。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"aps:RemoteWrite",
"aps:QueryMetrics",
"aps:GetSeries",
"aps:GetLabels",
"aps:GetMetricMetadata"
],
"Resource": "*"
}
]
}
部署Prometheus服务器
适用于Prometheus的Amazon Managed Service不会直接从Kubernetes集群中的容器化工作负载中抓取运行指标。它要求用户在其集群中部署和管理标准Prometheus服务器或OpenTelemetry代理(例如适用于OpenTelemetry Collector的AWS Distro)来执行此任务。本文中实现的Prometheus服务器,该服务器使用Helm图表部署到Amazon EKS集群,如下所示:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
kubectl create ns prometheus
helm install prometheus-for-amp prometheus-community/prometheus -n prometheus
现在可以使用以下YAML清单将AWS Signing代理部署到Amazon EKS集群。现在,将占位符变量{AWS_REGION}替换为适当的AWS区域名称,将$ {IAM_PROXY_PROMETHEUS_ROLE_ARN}替换为你创建的EKS-AMP-ServiceAccount-Role的ARN,并将占位符{WORKSPACE_ID}替换为之前创建的AMP工作区ID。签名代理引用了ECR中公共存储库中的Docker映像。
创建一个名为amp_ingest_override_values.yaml的文件,其中包含以下内容:
serviceAccounts:
server:
name: "iamproxy-service-account"
annotations:
eks.amazonaws.com/role-arn: "${IAM_PROXY_PROMETHEUS_ROLE_ARN}"
server:
sidecarContainers:
aws-sigv4-proxy-sidecar:
image: public.ecr.aws/aws-observability/aws-sigv4-proxy:1.0
args:
- --name
- aps
- --region
- ${AWS_REGION}
- --host
- aps-workspaces.${AWS_REGION}.amazonaws.com
- --port
- :8005
ports:
- name: aws-sigv4-proxy
containerPort: 8005
statefulSet:
enabled: "true"
remoteWrite:
- url: http://localhost:8005/workspaces/${WORKSPACE_ID}/api/v1/remote_write
执行以下命令修改Prometheus服务器配置,用以部署签名代理并配置remoteWrite端点
helm upgrade --install prometheus-for-amp prometheus-community/prometheus -n prometheus -f ./amp_ingest_override_values.yaml
通过以上配置,Prometheus服务器现在可以从群集中部署的服务中抓取指标,并通过AWS签名代理将其发送到Amazon Managed Service for Prometheus中的指定工作区。
现在,已将装有Prometheus客户端库的应用程序作为副本集部署到Amazon EKS集群。它使用名为http_requests_total的Prometheus计数器跟踪传入的HTTP请求的数量,并通过HTTP在端点/ metrics处公开此数据。调用此端点将提供以下输出,该输出由Prometheus服务器定期进行抓取。
# HELP http_requests_total Total number of HTTP requests.
# TYPE http_requests_total counter
http_requests_total{job="recommender",path="/user/product",} 86.0
http_requests_total{job="recommender",path="/popular/product",} 128.0
http_requests_total{job="recommender",path="/popular/category",} 345.0
使用Grafana可视化指标
可以使用Grafana可视化在Amazon Managed Service for Prometheus的工作区中收集的指标。Grafana v7.3.x添加了一项新功能来支持AWS Signature版本4(SigV4)身份验证,我们将在此处使用该版本。使用Helm图表将自我管理的Grafana安装部署到Amazon EKS集群,如下所示:
helm repo add grafana https://grafana.github.io/helm-charts
kubectl create ns grafana
helm install grafana-for-amp grafana/grafana -n grafana
更新你的Grafana服务器以使用AWS签名代理
创建一个新文件,并将其命名为amp_query_override_values.yaml。该文件将用于更新你的Grafana部署,以启用AWS Signing代理用来认证的Sigv4协议。
serviceAccount:
name: "iamproxy-service-account"
annotations:
eks.amazonaws.com/role-arn: "${IAM_PROXY_PROMETHEUS_ROLE_ARN}"
grafana.ini:
auth:
sigv4_auth_enabled: true
现在执行以下命令来更新你的Grafana环境:
helm upgrade --install grafana-for-amp grafana/grafana -n grafana -f ./amp_query_override_values.yaml
你现在可以通过使用以下命令将端口转发到http://localhost:5001来访问Grafana。将字符串GRAFANA_POD_NAME替换为你刚创建的实际Grafana POD名称。
kubectl port-forward -n grafana pods/GRAFANA_POD_NAME 5001:3000
接下来,使用上述URL从Internet浏览器打开Grafana,然后使用管理员用户名登录。密码是从Kubernetes secret处获取的,如下所示:
kubectl get secrets grafana-for-amp -n grafana -o jsonpath='{.data.admin-password}'|base64 --decode
在可视化Grafana中的指标之前,必须使用一个或多个数据源对其进行配置。在这里,我们将在Amazon Managed Service for Prometheus中将工作区指定为数据源,如下所示。在URL字段中,指定AMP工作区详细信息页面中显示的Endpoint –query URL,在URL末尾不带/api/v1/query字符串。
△配置AMP数据源
现在,你可以查询存储在托管服务工作区中的Prometheus Counter http_requests_total的指标数据,并使用Prometheus查询以可视化方式显示过去5分钟内HTTP请求的速率,如下所示:
sum(rate(http_requests_total{exported_job=”recommender”}[5m])) by (path)
下图说明了如何根据Prometheus Counter中捕获的不同路径标签在Grafana中可视化该指标:
△PromQL和指标可视化
除了从应用程序工作负载中收集的服务指标外,我们还可以查询Prometheus捕获的Kubernetes集群中所有容器和节点的系统指标。例如,Prometheus计数器node_network_transmit_bytes_total捕获从群集的每个节点传输的数据量。下图使用Prometheus查询将每个节点的数据传输速率可视化,如下所示:
sum(rate(node_network_transmit_bytes_total[5m])) by (instance)
△PromQL和指标数据可视化
结束语
Prometheus是一种非常流行的开源监控工具,提供强大的查询功能并广泛支持各种工作负载。这篇文章概述了使用Amazon Managed Service for Prometheus从部署到Amazon EKS集群的应用程序工作负载中安全地获取,存储和查询Prometheus指标所涉及的步骤。Amazon Managed Service for Prometheus也可以与任何与Prometheus兼容的监控和报警服务一起使用,以从其他容器环境(例如Amazon ECS,AWS上的自我管理的Kubernetes或本地基础架构)收集指标。Amazon Managed Service for Prometheus中的工作区可用作Grafana的有效数据源。因此,用户可以使用自我管理的Grafana安装可视化这些指标,也可以使用Amazon Managed Service for Grafana。