使用 Amazon CloudWatch Container Insights 轻松监控容器化应用程序
我们需要精准和高效地监控容器化应用程序。可以借助 Amazon CloudWatch Container Insights 来应对从应用程序中收集和汇总指标的复杂性。Container Insights 会根据您的容器性能指标的变化提供实时数据,使您能够及时做出正确决策,保持稳定的应用程序性能。
本教程以本课程系列第一部分中创建的 Amazon EKS 集群为基础,详细介绍如何设置 Amazon CloudWatch Container Insights。上一个教程中的集群配置中包括了关联到服务账户的 IAM 角色 (IRSA) 和 OpenID Connect (OIDC) 端点的 Amazon CloudWatch IAM 策略。有关如何创建集群,请参阅构建预配置运行高流量微服务的 Amazon EKS 集群。或者,在现有集群上添加本教程试验所需的组件。具体操作指导,请见 Amazon EKS 官方文档中的验证前提条件部分。
在此实验中,您将配置 Amazon EKS 集群、部署容器化应用程序并使用 Container Insights 监控应用程序的性能。Container Insights 可以实时监控轻量级应用程序(如微服务)以及更复杂的系统(如数据库或用户身份认证系统)。
注意:Amazon CloudWatch Container Insights 不包括在亚马逊云科技免费套餐内,因此 使用 Container Insights 资源会产生相关费用。
前提条件
在开始本教程之前,您需要:
- 安装最新版本的 kubectl。运行以下命令检查您的 kubectl 版本:kubectl version --short。
- 安装最新版本的 eksctl。运行以下命令检查您的 eksctl 版本:eksctl info。
步骤 1:在 Amazon EKS 上设置 Container Insights
您需要完成一些设置,使 CloudWatch Container Insights 从 Amazon Elastic Kubernetes Service (Amazon EKS) 上的容器化应用程序和微服务中收集、汇总和总结指标和日志。Container Insights 支持运行 Amazon EKS 容器的 Amazon EC2 和 Fargate。您可以通过以下几种方法在 Amazon EKS 集群上设置 Container Insights:使用 CloudWatch 代理、使用 "quick start" 设置 或手动设置。本次试验使用快速开始设置步骤。
快速开始设置
首先,设置以下环境变量,并确保 ClusterName 和 RegionName 取值正确。在以下示例中,my-cluster 是 Amazon EKS 集群的名称,而 us-east-2 是日志发布的区域。请务必将值替换为实际值。建议将日志区域指定为您的集群所在区域,以尽量减少亚马逊云科技出站数据传输成本。此外,指定 FluentBitHttpPort 端口号为 2020。该端口通常用于监控,便于集成现有工具;设置FluentBitReadFromHead 值为 Off,指定从末尾开始读取日志。这对于管理大型日志文件和优化性能至关重要。
export ClusterName=managednodes-quickstart
export LogRegion=us-east-2
export FluentBitHttpPort='2020'
export FluentBitReadFromHead='Off'
以下环境变量设置表示从头部或尾部开始读取日志。注意,不能同时设置从头部和尾部开始读取日志。
[[ ${FluentBitReadFromHead} = 'On' ]] && FluentBitReadFromTail='Off'|| FluentBitReadFromTail='On'
设置以下环境变量,决定是否启用 Fluent Bit HTTP 服务器。在此命令中默认启用 FluentBitHttpServer 以监控插件指标。
[[ -z ${FluentBitHttpPort} ]] && FluentBitHttpServer='Off' || FluentBitHttpServer='On'
运行以下命令下载并检查 Fluent Bit Daemonset 的内容:
curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluent-bit-quickstart.yaml | sed 's/{{cluster_name}}/'${ClusterName}'/;s/{{region_name}}/'${LogRegion}'/;s/{{http_server_toggle}}/"'${FluentBitHttpServer}'"/;s/{{http_server_port}}/"'${FluentBitHttpPort}'"/;s/{{read_from_head}}/"'${FluentBitReadFromHead}'"/;s/{{read_from_tail}}/"'${FluentBitReadFromTail}'"/'> cwagent-fluent-bit-quickstart.yaml
为集群配置一个服务账户 IAM 角色,然后为该角色关联策略。运行以下命令为 fluent-bit 创建 IAM 角色和服务账户:
eksctl create iamserviceaccount --name fluent-bit \
--namespace amazon-cloudwatch \
--cluster ${ClusterName} --role-name fluent-bit \
--attach-policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy \
--approve --region ${LogRegion} \
--override-existing-serviceaccounts
运行以下命令将 Fluent Bit Daemonset 部署到集群中:
kubectl apply -f cwagent-fluent-bit-quickstart.yaml
运行以下命令验证是否已部署代理:
kubectl get pods -n amazon-cloudwatch
步骤 2:在集群中部署容器应用程序
在这一步中,使用名为workload.yaml 的清单文件,在 Kubernetes 集群中部署一个全面的容器化应用程序环境。
- 创建一个名为 workload.yaml 的 Kubernetes 清单文件,并将以下内容粘贴进去。
apiVersion: v1
kind: Namespace
metadata:
labels:
kubernetes.io/metadata.name: quickstart
name: quickstart
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: "quickstart-nginx-deployment"
namespace: "quickstart"
spec:
selector:
matchLabels:
app: "quickstart-nginx"
replicas: 3
template:
metadata:
labels:
app: "quickstart-nginx"
role: "backend"
spec:
dnsPolicy: Default
enableServiceLinks: false
automountServiceAccountToken: false
securityContext:
seccompProfile:
type: RuntimeDefault
containers:
- image: public.ecr.aws/nginx/nginx:latest
imagePullPolicy: Always
name: "quickstart-nginx"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
ports:
- containerPort: 80
command: ["/bin/sh"]
args: ["-c", "echo PodName: $MY_POD_NAME NodeName: $MY_NODE_NAME podIP: $MY_POD_IP> /usr/share/nginx/html/index.html && exec nginx -g 'daemon off;'"]
env:
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
volumeMounts:
- name: cache
mountPath: /var/cache/nginx
- name: usr
mountPath: /var/run
- name: tmp
mountPath: /usr/share/nginx/html
volumes:
- name: cache
emptyDir: {}
- name: tmp
emptyDir: {}
- name: usr
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: quickstart-nginx-service
namespace: quickstart
spec:
type: NodePort
selector:
app: "quickstart-nginx"
role: "backend"
ports:
- port: 80
targetPort: 80
---
apiVersion: v1
kind: Pod
metadata:
name: load
namespace: quickstart
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
automountServiceAccountToken: false
containers:
- name: load
image: public.ecr.aws/docker/library/busybox:1.36.1
imagePullPolicy: Always
command: ["/bin/sh"]
args: ["-c", "while sleep 0.5; do wget -q -O- http://quickstart-nginx-service; done"]
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
- 部署 workload.yaml 中定义的 Kubernetes 资源。
kubectl apply -f workload.yaml
- 输出结果应如下所示:
namespace/quickstart created
deployment.apps/quickstart-nginx-deployment created
service/quickstart-nginx-service created
pod/load created
- 运行以下命令检查已部署的 Nginx 容器的状态,确认其是否正在运行:
kubectl get all -n quickstart
NAME READY STATUS RESTARTS AGE
pod/load 1/1 Running 0 15s
pod/quickstart-nginx-deployment-7cd757dc7b-9fss6 1/1 Running 0 16s
pod/quickstart-nginx-deployment-7cd757dc7b-fv592 1/1 Running 0 16s
pod/quickstart-nginx-deployment-7cd757dc7b-wpw4x 1/1 Running 0 16s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/quickstart-nginx-service NodePort 10.100.233.21 <none> 80:31243/TCP 16s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/quickstart-nginx-deployment 3/3 3 3 17s
NAME DESIRED CURRENT READY AGE
replicaset.apps/quickstart-nginx-deployment-7cd757dc7b 3 3 3 17s
- 运行以下命令查看“负载” Pod 的实时日志。该 Pod 正在不断向 Nginx 服务发出请求。按 Ctrl+C 停止。
kubectl logs -f load -n quickstart
PodName: quickstart-nginx-deployment-7cd757dc7b-wpw4x NodeName: ip-192-168-141-57.us-east-2.compute.internal podIP: 192.168.136.230
PodName: quickstart-nginx-deployment-7cd757dc7b-fv592 NodeName: ip-192-168-177-109.us-east-2.compute.internal podIP: 192.168.164.31
PodName: quickstart-nginx-deployment-7cd757dc7b-fv592 NodeName: ip-192-168-177-109.us-east-2.compute.internal podIP: 192.168.164.31
PodName: quickstart-nginx-deployment-7cd757dc7b-9fss6 NodeName: ip-192-168-119-7.us-east-2.compute.internal podIP: 192.168.112.25
步骤 3:使用 CloudWatch Logs Insights 查询和分析容器日志
您可以使用 CloudWatch Logs Insights 来交互式地查询和分析 Amazon CloudWatch Logs 中应用程序的容器日志。Fluent Bit 将集群中容器的日志发送到 CloudWatch Logs。在上面的步骤 1 中,我们已经将 Fluent Bit 设为 DaemonSet,用来向 CloudWatch Logs 发送日志。如果 DaemonSet 不存在,Fluent Bit 将创建以下日志组:
/aws/containerinsights/Cluster_Name/application 其中包括集群中每个工作节点上 /var/log/containers 中的所有日志文件。
运行 CloudWatch Logs Insights 示例查询:
- 打开 CloudWatch 控制台。
- 在导航栏中,点击 Logs(日志),然后点击 Log groups(日志组)。
- 点击日志组 /aws/containerinsights/CLUSTER_NAME/application。其中 CLUSTER_NAME 表示您的 EKS 集群的实际名称。
- 在日志详情中(右上角),点击 View in Logs Insights(在 Logs Insights 中查看)。
- 删除 CloudWatch Log Insight 查询编辑器中的默认查询语句。然后,输入以下命令并运行查询:
fields @timestamp, kubernetes.pod_name as PodName, kubernetes.host as WorkerNode, kubernetes.namespace_name as Namespace, log
| filter PodName like 'quickstart-nginx-deployment'
| sort @timestamp desc
| limit 200
- 通过时间间隔选择器选择您想查询的时间段。例如:
步骤 4:使用 Container Insights 监控应用程序性能
监控您的容器化应用程序的性能对于保持最佳功能性、识别潜在问题和了解系统行为至关重要。在这一步中,您将利用 Amazon CloudWatch 的 Container Insights 功能了解您的容器性能情况。
在 Container Insights 控制面板上查看指标
本小节介绍如何访问 Amazon CloudWatch Container Insights 控制面板,查看指标。该控制面板提供了您的 Amazon EKS 和 Kubernetes 集群性能的集中视图,帮助您实时洞察各项指标,如 CPU 利用率、内存占用率和网络活动等。您可以快速导航到您想要监控的集群和资源,使您能及时查看容器化应用的运行状况和性能表现。
- 访问 https://console.thinkwithwp.com/cloudwatch/ 进入 CloudWatch 控制台。
- 在左侧导航栏中,点击 Insights(洞察) 下拉菜单,然后选择 Container Insights(容器洞察)。
- 从 Container Insights(容器洞察)下的下拉菜单中,选择 Performance Monitoring(性能监控)。
- 从 EKS Clusters(EKS 集群)下拉菜单中,选择您的集群名。
- 您可以根据筛选条件,如 EKS Clusters 和 EKS Pods,筛选要查看监控数据的资源。例如:
查看其他 Amazon EKS 和 Kubernetes 容器洞察指标
本小节介绍如何在 Amazon CloudWatch 中查看更多 Amazon EKS 和 Kubernetes 特有的指标集。这些特有指标,如 pod_cpu_utilization_over_pod_limit,能够为您提供关于容器化应用程序及其底层基础设施的深入洞察数据。无论您是想要分析 CPU 利用率、内存占用率还是网络指标,您都可以自定义视图,查看您关注的指标。
探究应用程序所需资源超出其资源配置的场景
- 运行以下命令创建一个名为 geo-api.yaml 的 Kubernetes 清单文件,部署一个名为 geo-api 的简单后端应用程序:
apiVersion: apps/v1
kind: Deployment
metadata:
name: geo-api
spec:
selector:
matchLabels:
run: geo-api
replicas: 1
template:
metadata:
labels:
run: geo-api
spec:
containers:
- name: geo-api
image: registry.k8s.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 250m
memory: "12Mi"
requests:
cpu: 125m
memory: "10Mi"
---
apiVersion: v1
kind: Service
metadata:
name: geo-api
labels:
run: geo-api
spec:
ports:
- port: 80
selector:
run: geo-api
该部署将创建一个包含 1 个容器的 Pod。并为该容器定义了需要 0.125 CPU 和 10 MiB 内存资源的请求。该容器资源限制为 0.25 CPU 和 12MiB 内存。
- 运行以下命令部署应用程序:
kubectl apply -f geo-api.yaml
- 运行以下命令为运行在容器中的 Web 服务器创建负载:
kubectl create deployment geo-api-load \
--image=busybox \
--replicas=2 -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://geo-api; done"
- 查询 Pod 状态:
kubectl get pods
输出结果应如下所示:
NAME READY STATUS RESTARTS AGE
geo-api-load-c9c7bf98c-4rrn8 0/1 ContainerCreating 0 0s
geo-api-load-c9c7bf98c-kzsjs 0/1 ContainerCreating 0 0s
geo-api-load-c9c7bf98c-4rrn8 1/1 Running 0 1s
geo-api-load-c9c7bf98c-kzsjs 1/1 Running 0 2s
geo-api-76f6dcf999-ptpz5 1/1 Running 20 (5m8s ago) 118m
geo-api-76f6dcf999-ptpz5 0/1 OOMKilled 20 (5m13s ago) 118m
输出显示 geo-api Pod 的状态是 Running。但有时可能会是 OOMKilled。
运行以下命令获取容器状态的详细信息:
kubectl get pod geo-api-76f6dcf999-ptpz5 --output=yaml | grep -i lastState -A7
输出内容表明容器因为内存不足 (OOM) 被停止:
lastState:
terminated:
containerID: containerd://4bbdfee06a3d3daca0e74f14f18f8a66ac0a415c79720eae44ea9ad4c46bcb37
exitCode: 137
finishedAt: "2023-08-26T12:48:37Z"
reason: OOMKilled
startedAt: "2023-08-26T12:47:27Z"
name: geo-api
- 去 Container Insights 上查看这个 Pod 的相关指标:
- 访问 https://console.thinkwithwp.com/cloudwatch/ 进入 CloudWatch 控制台。
- 在导航栏中,点击 Metrics(指标),然后选择 All metrics(所有指标)。
- 选择 ContainerInsights 指标命名空间。在搜索栏中选择 ClusterName,Namespace,和 PodName,将 PodName="geo-api" 粘贴到搜索框。
- 选择以下指标,查看该 Pod 使用的 CPU 单元占配额的百分比,及使用的内存占配额的百分比:
- pod_cpu_utilization_over_pod_limit
- pod_memory_utilization_over_pod_limit
图表显示 Pod 中的容器已经用完其 CPU 和内存配额。您需要及时添加足够的资源以防止 Pod 中的容器被终止。
清理资源
为避免持续产生费用,建议您及时删除试验过程中创建的资源。您可以使用以下命令删除容器应用程序,并删除用于 Container Insights 的 CloudWatch 代理和 Fluent Bit:
# Delete workloads
kubectl delete -f workload.yaml -n quickstart
kubectl delete -f geo-api.yaml
# Delete the the CloudWatch agent and Fluentbit for Container Insights
kubectl delete -f cwagent-fluent-bit-quickstart.yaml
总结
您已经成功地为 Container Insights 设置了 CloudWatch 代理和 Fluent Bit,用于监控 Amazon EKS 集群中的示例容器化工作负载。遵循这些指导步骤,您可以建立起一套可靠的监控与日志记录方案,帮助您监控集群中部署的应用程序性能。