在 AWS 上部署 Loki Helm Chart
本指南介绍了如何使用 Helm chart 在 AWS 上以微服务模式部署一个最小可用的 Loki。要完成本指南,您需要具备在 AWS 上部署资源的必要工具和权限,例如:
- EKS (Amazon Elastic Kubernetes Service) 的完全访问权限
- S3 (Amazon Simple Storage Service) 的完全访问权限
- 创建 IAM (Identity Access Management) 角色和策略的足够权限
有两种方法可以将 Loki 认证并连接到 AWS S3。我们将引导您完成推荐的方法,即通过 IAM 角色授予访问权限。
注意事项
注意
本指南截至最近一次更新(2024 年 10 月 31 日)时是准确的。由于云提供商会频繁更新其服务和产品,因此最佳实践是在创建存储桶和分配角色之前,参考 AWS S3 文档。
IAM 角色:本指南中创建的 IAM 角色是一个基本角色,允许 Loki 读取和写入 S3 存储桶。您可以根据您的需求添加更精细的权限。
认证:Grafana Loki 带有一个基本的认证层。在此示例中,Loki 网关 (NGINX) 使用基本认证暴露在互联网上。NGINX 也可以替换为其他开源反向代理。更多信息请参阅认证。
数据保留:在
values.yaml
文件中,数据保留期设置为 28 天。您可以根据您的需求调整此设置。成本:在 AWS 上运行 Loki 将产生费用。请务必监控您的使用情况和成本,以避免任何意外账单。在本指南中,我们使用了一个包含 3 个节点和 m5.xlarge 实例的简单 EKS 集群。您可以根据您的工作负载调整实例类型和节点数量。
前提条件
- Helm 3 或更高版本。请参阅安装 Helm。这应该安装在您的本地机器上。
- 在 AWS 上运行的 Kubernetes 集群。一个简单的入门方法是使用 EKSctl。请参阅EKSctl 入门。
- Kubectl 安装在您的本地机器上。请参阅安装和设置 kubectl。
- (可选) AWS CLI 安装在您的本地机器上。请参阅安装 AWS CLI。如果您计划使用 EKSctl 创建 EKS 集群并在本地修改 IAM 角色和策略,则需要此工具。
EKS 最低要求
注意
这些 EKS 要求是使用本指南部署 Loki 所需的最低规格。您可以根据您的 AWS 环境和工作负载调整插件和实例类型。如果您选择这样做,我们无法保证此示例配置仍能满足您的需求。
在本指南中,我们使用
m5.xlarge
实例部署 Loki。这是在大多数场景下都适用的实例类型。但是,您可以根据您的具体需求修改实例类型和数量。
在 EKS 上部署 Loki 的最低要求是:
- Kubernetes 版本
1.30
或更高。 - EKS 集群需要
3
个节点。 - 实例类型取决于您的工作负载。生产集群的良好起点是
m7i.2xlarge
。
本指南中使用的 EKSctl 集群配置文件如下:
# A simple example of ClusterConfig object:
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: <INSERT-CLUSTER-NAME>
region: <INSERT-REGION-FOR-CLUSTER>
version: "1.31"
iam:
withOIDC: true
addons:
- name: aws-ebs-csi-driver
managedNodeGroups:
- name: loki-workers
instanceType: m7i.2xlarge
desiredCapacity: 3
minSize: 2
maxSize: 3
amiFamily: AmazonLinux2023
iam:
withAddonPolicies:
ebs: true
volumeSize: 80
volumeType: gp3
ebsOptimized: true
EKS 集群中还必须安装以下插件:
- Amazon EBS CSI Driver:使 Kubernetes 能够动态配置和管理 EBS 卷作为应用程序的持久存储。我们使用它为 Loki 提供节点卷。
- CoreDNS:为 Kubernetes 集群提供内部 DNS 服务,确保服务和 Pod 可以使用 DNS 名称相互通信。
- kube-proxy:维护节点上的网络规则,使集群内的 Pod 和服务能够相互通信。
您还必须在 EKS 集群上安装 OIDC (OpenID Connect) provider。这是 IAM 角色和策略正常工作所必需的。如果您使用 EKSctl,可以使用以下命令安装 OIDC provider:
提示
如果您使用上面的 EKSctl 配置文件创建集群,则无需运行此命令。OIDC provider 会自动安装。
eksctl utils associate-iam-oidc-provider --cluster loki --approve
创建 S3 存储桶
警告
请勿使用默认存储桶名称;
chunk
、ruler
和admin
。为每个存储桶选择一个唯一的名称。更多信息请参阅以下安全更新。
在部署 Loki 之前,您需要创建两个 S3 存储桶;一个用于存储日志(块),另一个用于存储警报规则。您可以使用 AWS 管理控制台或 AWS CLI 创建存储桶。存储桶名称必须是全局唯一的。
注意
GEL 客户需要第三个存储桶来存储管理员数据。OSS 用户不需要此存储桶。
aws s3api create-bucket --bucket <YOUR CHUNK BUCKET NAME e.g. `loki-aws-dev-chunks`> --region <S3 region your account is on, e.g. `eu-west-2`> --create-bucket-configuration LocationConstraint=<S3 region your account is on, e.g. `eu-west-2`> \
aws s3api create-bucket --bucket <YOUR RULER BUCKET NAME e.g. `loki-aws-dev-ruler`> --region <S3 REGION your account is on, e.g. `eu-west-2`> --create-bucket-configuration LocationConstraint=<S3 REGION your account is on, e.g. `eu-west-2`>
请务必将 region
和 bucket
名称替换为您期望的值。稍后在本指南中,我们将再次讨论存储桶策略。
定义 IAM 角色和策略
将 Loki 连接到 AWS S3 的推荐方法是使用 IAM 角色。这种方法比在 Loki 配置中直接存储访问密钥和 secret 密钥更安全。可以使用 AWS CLI 或 AWS 管理控制台创建角色和策略。以下步骤展示了如何使用 AWS CLI 创建角色和策略。
创建一个新目录并导航到该目录。请确保在此目录中创建文件。本指南中的所有命令都假定您位于此目录中。
创建一个名为
loki-s3-policy.json
的文件,内容如下:{ "Version": "2012-10-17", "Statement": [ { "Sid": "LokiStorage", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::< CHUNK BUCKET NAME >", "arn:aws:s3:::< CHUNK BUCKET NAME >/*", "arn:aws:s3:::< RULER BUCKET NAME >", "arn:aws:s3:::< RULER BUCKET NAME >/*" ] } ] }
请确保将占位符替换为您之前创建的存储桶名称。
使用 AWS CLI 创建 IAM 策略
aws iam create-policy --policy-name LokiS3AccessPolicy --policy-document file://loki-s3-policy.json
创建一个名为
trust-policy.json
的信任策略文档,内容如下:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::< ACCOUNT ID >:oidc-provider/oidc.eks.<INSERT REGION>.amazonaws.com/id/< OIDC ID >" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "oidc.eks.<INSERT REGION>.amazonaws.com/id/< OIDC ID >:sub": "system:serviceaccount:loki:loki", "oidc.eks.<INSERT REGION>.amazonaws.com/id/< OIDC ID >:aud": "sts.amazonaws.com" } } } ] }
请务必将占位符替换为您的 AWS 帐户 ID、区域以及 OIDC ID(您可以在 EKS 集群配置中找到)。
使用 AWS CLI 创建 IAM 角色
aws iam create-role --role-name LokiServiceAccountRole --assume-role-policy-document file://trust-policy.json
将策略附加到角色
aws iam attach-role-policy --role-name LokiServiceAccountRole --policy-arn arn:aws:iam::<Account ID>:policy/LokiS3AccessPolicy
请务必将占位符替换为您的 AWS 帐户 ID。
部署 Helm Chart
在部署 Loki Helm Chart 之前,我们需要将 Grafana chart 仓库添加到 Helm 中。此仓库包含 Loki Helm Chart。
将 Grafana chart 仓库添加到 Helm
helm repo add grafana https://grafana.github.io/helm-charts
更新 chart 仓库
helm repo update
为 Loki 创建一个新的命名空间
kubectl create namespace loki
Loki 基本认证
Loki 默认不带任何认证。由于我们将在 AWS 上部署 Loki 并将网关暴露到互联网,我们建议至少添加基本认证。在本指南中,我们将为 Loki 设置用户名和密码。
首先,我们需要使用用户名和密码创建一个
.htpasswd
文件。您可以使用htpasswd
命令创建该文件:提示
如果您的机器上没有安装
htpasswd
命令,您可以根据您的操作系统使用brew
、apt-get
或yum
进行安装。htpasswd -c .htpasswd <username>
这将创建一个名为
auth
的文件,其中包含用户名loki
。系统将提示您输入密码。使用
.htpasswd
文件创建一个 Kubernetes Secretkubectl create secret generic loki-basic-auth --from-file=.htpasswd -n loki
这将在
loki
命名空间中创建一个名为loki-basic-auth
的 Secret。我们将在 Loki Helm chart 配置中引用此 Secret。为 canary 创建一个
canary-basic-auth
Secretkubectl create secret generic canary-basic-auth \ --from-literal=username=<USERNAME> \ --from-literal=password=<PASSWORD> \ -n loki
我们创建一个字面量 Secret,其中包含 Loki canary 用于向 Loki 网关进行认证的用户名和密码。请务必将占位符替换为您期望的用户名和密码。
Loki Helm Chart 配置
创建一个 values.yaml
文件,选择最符合您需求的配置选项。下面是在微服务模式下 Loki Helm Chart 的 values.yaml
文件示例。
loki:
schemaConfig:
configs:
- from: "2024-04-01"
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24h
storage_config:
aws:
region: <S3 BUCKET REGION> # for example, eu-west-2
bucketnames: <CHUNK BUCKET NAME> # Your actual S3 bucket name, for example, loki-aws-dev-chunks
s3forcepathstyle: false
ingester:
chunk_encoding: snappy
pattern_ingester:
enabled: true
limits_config:
allow_structured_metadata: true
volume_enabled: true
retention_period: 672h # 28 days retention
compactor:
retention_enabled: true
delete_request_store: s3
ruler:
enable_api: true
storage:
type: s3
s3:
region: <S3 BUCKET REGION> # for example, eu-west-2
bucketnames: <RULER BUCKET NAME> # Your actual S3 bucket name, for example, loki-aws-dev-ruler
s3forcepathstyle: false
alertmanager_url: http://prom:9093 # The URL of the Alertmanager to send alerts (Prometheus, Mimir, etc.)
querier:
max_concurrent: 4
storage:
type: s3
bucketNames:
chunks: "<CHUNK BUCKET NAME>" # Your actual S3 bucket name (loki-aws-dev-chunks)
ruler: "<RULER BUCKET NAME>" # Your actual S3 bucket name (loki-aws-dev-ruler)
# admin: "<Insert s3 bucket name>" # Your actual S3 bucket name (loki-aws-dev-admin) - GEL customers only
s3:
region: <S3 BUCKET REGION> # eu-west-2
#insecure: false
# s3forcepathstyle: false
serviceAccount:
create: true
annotations:
"eks.amazonaws.com/role-arn": "arn:aws:iam::<Account ID>:role/LokiServiceAccountRole" # The service role you created
deploymentMode: Distributed
ingester:
replicas: 3
zoneAwareReplication:
enabled: false
querier:
replicas: 3
maxUnavailable: 2
queryFrontend:
replicas: 2
maxUnavailable: 1
queryScheduler:
replicas: 2
distributor:
replicas: 3
maxUnavailable: 2
compactor:
replicas: 1
indexGateway:
replicas: 2
maxUnavailable: 1
ruler:
replicas: 1
maxUnavailable: 1
# This exposes the Loki gateway so it can be written to and queried externaly
gateway:
service:
type: LoadBalancer
basicAuth:
enabled: true
existingSecret: loki-basic-auth
# Since we are using basic auth, we need to pass the username and password to the canary
lokiCanary:
extraArgs:
- -pass=$(LOKI_PASS)
- -user=$(LOKI_USER)
extraEnv:
- name: LOKI_PASS
valueFrom:
secretKeyRef:
name: canary-basic-auth
key: password
- name: LOKI_USER
valueFrom:
secretKeyRef:
name: canary-basic-auth
key: username
# Enable minio for storage
minio:
enabled: false
backend:
replicas: 0
read:
replicas: 0
write:
replicas: 0
singleBinary:
replicas: 0
注意
请确保将占位符替换为您的实际值。
为 Loki 部署定义有效的 values.yaml
文件至关重要。为了消除配置错误的风险,让我们分解一下在部署到 AWS 时需要注意的配置选项:
Loki 配置 vs Values 配置
values.yaml
文件包含一个名为loki
的部分,该部分直接表示 Loki 配置文件。- 此部分定义了 Loki 配置,包括 schema、存储和 querier 配置。
- 对于 chunks 而言,需要关注的关键配置是
storage_config
部分,您可以在其中定义 S3 存储桶区域和名称。这会告诉 Loki 存储 chunks 的位置。 ruler
部分定义了 ruler 的配置,包括 S3 存储桶区域和名称。这会告诉 Loki 存储警报和记录规则的位置。- 有关完整的 Loki 配置,请参阅Loki 配置文档。
存储
- 定义 Helm chart 存储数据的位置。
- 将类型设置为
s3
,因为我们使用的是 Amazon S3。 - 配置 chunks 和 ruler 的存储桶名称以匹配之前创建的存储桶。
s3
部分指定了存储桶的区域。
Service Account
serviceAccount
部分用于定义 Loki service account 的 IAM 角色。- 这是链接之前创建的 IAM 角色的地方。
网关
- 定义 Loki 网关的暴露方式。
- 在此配置中,我们使用
LoadBalancer
服务类型。
部署 Loki
现在您已经创建了 values.yaml
文件,可以使用 Helm chart 部署 Loki。
使用新创建的
values.yaml
文件进行部署helm install --values values.yaml loki grafana/loki -n loki --create-namespace
创建一个名为
loki
的命名空间很重要,因为我们的信任策略设置为允许loki
命名空间中的loki
service account 使用该 IAM 角色。这是可配置的,但请务必更新您的 service account。验证部署
kubectl get pods -n loki
您应该会看到 Loki 的 Pod 正在运行。
NAME READY STATUS RESTARTS AGE loki-canary-crqpg 1/1 Running 0 10m loki-canary-hm26p 1/1 Running 0 10m loki-canary-v9wv9 1/1 Running 0 10m loki-chunks-cache-0 2/2 Running 0 10m loki-compactor-0 1/1 Running 0 10m loki-distributor-78ccdcc9b4-9wlhl 1/1 Running 0 10m loki-distributor-78ccdcc9b4-km6j2 1/1 Running 0 10m loki-distributor-78ccdcc9b4-ptwrb 1/1 Running 0 10m loki-gateway-5f97f78755-hm6mx 1/1 Running 0 10m loki-index-gateway-0 1/1 Running 0 10m loki-index-gateway-1 1/1 Running 0 10m loki-ingester-zone-a-0 1/1 Running 0 10m loki-ingester-zone-b-0 1/1 Running 0 10m loki-ingester-zone-c-0 1/1 Running 0 10m loki-querier-89d4ff448-4vr9b 1/1 Running 0 10m loki-querier-89d4ff448-7nvrf 1/1 Running 0 10m loki-querier-89d4ff448-q89kh 1/1 Running 0 10m loki-query-frontend-678899db5-n5wc4 1/1 Running 0 10m loki-query-frontend-678899db5-tf69b 1/1 Running 0 10m loki-query-scheduler-7d666bf759-9xqb5 1/1 Running 0 10m loki-query-scheduler-7d666bf759-kpb5q 1/1 Running 0 10m loki-results-cache-0 2/2 Running 0 10m loki-ruler-0 1/1 Running 0 10m
查找 Loki 网关服务
Loki 网关服务是一个 LoadBalancer 服务,它将 Loki 网关暴露给互联网。您将在这里写入日志和查询日志。默认使用 NGINX 作为网关。
注意
Loki 网关服务已暴露到互联网。在本教程中,我们使用用户名和密码提供了基本认证。更多信息请参阅认证文档。
要查找 Loki 网关服务,请运行以下命令:
kubectl get svc -n loki
您应该会看到带有外部 IP 地址的 Loki 网关服务。这就是您将用于写入日志和查询日志的地址。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
loki-gateway LoadBalancer 10.100.201.74 12345678975675456-1433434453245433545656563.eu-west-2.elb.amazonaws.com 80:30707/TCP 46m
恭喜!您已成功使用 Helm Chart 在 AWS 上部署了 Loki。在结束之前,让我们测试一下部署。
测试您的 Loki 部署
k6 是测试 Loki 部署的最快方法之一。它允许您向 Loki 写入日志并查询日志。要开始使用 k6,请按照以下步骤操作:
在您的本地机器上安装带有 Loki 扩展的 k6。请参阅安装 k6 和 xk6-loki 扩展。
创建一个名为
aws-test.js
的文件,内容如下:import {sleep, check} from 'k6'; import loki from 'k6/x/loki'; /** * URL used for push and query requests * Path is automatically appended by the client * @constant {string} */ const username = '<USERNAME>'; const password = '<PASSWORD>'; const external_ip = '<EXTERNAL-IP>'; const credentials = `${username}:${password}`; const BASE_URL = `http://${credentials}@${external_ip}`; /** * Helper constant for byte values * @constant {number} */ const KB = 1024; /** * Helper constant for byte values * @constant {number} */ const MB = KB * KB; /** * Instantiate config and Loki client */ const conf = new loki.Config(BASE_URL); const client = new loki.Client(conf); /** * Define test scenario */ export const options = { vus: 10, iterations: 10, }; export default () => { // Push request with 10 streams and uncompressed logs between 800KB and 2MB var res = client.pushParameterized(10, 800 * KB, 2 * MB); // Check for successful write check(res, { 'successful write': (res) => res.status == 204 }); // Pick a random log format from label pool let format = randomChoice(conf.labels["format"]); // Execute instant query with limit 1 res = client.instantQuery(`count_over_time({format="${format}"}[1m])`, 1) // Check for successful read check(res, { 'successful instant query': (res) => res.status == 200 }); // Execute range query over last 5m and limit 1000 res = client.rangeQuery(`{format="${format}"}`, "5m", 1000) // Check for successful read check(res, { 'successful range query': (res) => res.status == 200 }); // Wait before next iteration sleep(1); } /** * Helper function to get random item from array */ function randomChoice(items) { return items[Math.floor(Math.random() * items.length)]; }
将
<EXTERNAL-IP>
替换为 Loki 网关服务的外部 IP 地址。此脚本将向 Loki 写入日志并从 Loki 查询日志。它将写入 800KB 到 2MB 之间的随机格式日志,并查询过去 5 分钟内的随机格式日志。
运行测试
./k6 run aws-test.js
这将运行测试并输出结果。您应该会看到测试正在向 Loki 写入日志并从 Loki 查询日志。
现在您已成功在 AWS 上以微服务模式部署了 Loki,您可能希望探索以下内容: