Kustomize 生产实战 - 注入监控 APM Agent

本文涉及的产品
应用实时监控服务-应用监控,每月50GB免费额度
应用实时监控服务-用户体验监控,每月100OCU免费额度
简介: Kustomize 生产实战 - 注入监控 APM Agent

Kustomize 简介

Kubernetes 原生配置管理工具 , 它自定义引入了一种无需模板的方式来定制应用程序配置,从而简化了对现成应用程序的使用。目前,在kubectl 中内置了,通过 apply -k 即可使用。

Kustomize 遍历 Kubernetes 清单以添加、删除或更新配置选项,而无需分叉。它既可以作为独立的二进制文件使用,也可以作为 kubectl 的原生特性使用。

Kustomize 优势

  • 📢 完全声明式的配置定制方法
  • 🍸 原生构建进 kubectl
  • 🎶 管理任意数量的独特定制的 Kubernetes 配置
  • ☸ 作为独立的二进制文件提供,用于扩展和集成到其他服务
  • 📃 定制使用的每个工件都是纯 YAML,并且可以被验证和处理
  • 🔁 Kustomize 支持 fork/modify/rebase 工作流
  • 🔧 GitOps 工具(如 ArgoCD) 对其的完美支持

Kustomize 可以做什么

📚️ Reference:

👉️URL: https://mp.weixin.qq.com/s/gmwkoqZpKbq1hM0B8XxQNw

在 Kubernetes 中我们使用 YAML 文件来声明我们的应用应该如何部署到底层的集群中,这些 YAML 文件中包含应用定义、治理需要的标签、日志、安全上下文定义、资源依赖关系等,当我们应用扩展到成百上千个 Pod 以后,管理这些 YAML 文件就会成为一场噩梦了。

最典型的就是,有很多项目要管理,同时又有多套不同的部署环境:开发环境、测试环境、UAT 环境、生产环境。甚至可能有不同的公有云 Kubernetes 发行版。那么每一套环境都需要一套各种各样的 YAML 文件, 但是它们直接只有部分细节有差异。比如:镜像 Tag,服务 Name,Label,有没有存储等。

如果全是手动,维护工作量非常巨大,同时也容易出错。

Kustomize 相比 Helm, 更适合解决这种场景的痛点:有一个基础(base)的模板管理一个项目的所有基础 YAML,更多高级的需求通过 overlay 来实现叠加覆盖。

另外还有一类典型场景,就是融合来自不同用户的配置数据(例如来自 devops/SRE 和 developers).

同时也可以结合 helm, 进行一些更高级的配置。

今天就以一个典型场景为例:生产环境 Deployment 自动注入商业(如:AppDynamics) 或开源 (SkyWalking/pinpoint) 的开箱即用的 Java Agent.

实战 - 通过 Kustomize 注入监控 APM Agent

背景概述

以 Java 为例,这里的 APM Agent 包是商业(如:AppDynamics) 或开源 (SkyWalking/pinpoint) 产品提供的开箱即用的 Agent jar 包。

在 Kubernetes 场景中,出于以下几点考虑:

  1. 和应用镜像分离;
  2. 复用

Agent jar 包做成了一个通用镜像,通过 init container 方式拷贝到运行中的应用容器中,并通过配置环境变量进行参数的自动设置。

✍️ 笔者注:

其实商业 APM 都有 Helm 或 Operator 实现自动化安装配置的功能,但是实际使用中体验不佳,不太适合我们的实际场景。

通过 Kustomize 注入监控 APM Agent 步骤

步骤简述如下:(以 AppDynamics Java Agent 为例)

  1. 获取原始的 Deployment yaml 文件(通过 kubectlkubectl neat 插件)
  2. 通过 Kustomize 对每个 Deployment 通过patches实现以下步骤:
  1. 注入initContainers:appd-agent-attach-java, 该initContainers有:
  1. volumeMounts: 把 java agent jar 包挂载到 volume 实现共享;
  1. 在 Deployment -> 应用自己的 container 中,加入以下参数:
  1. volumeMounts: 把 java agent jar 包挂载到 volume 实现共享;
  2. 加入各种 AppD Java agent 需要的 env 信息;
  1. volumes 通过 tmpdir 实现共享。

Kustomize 目录结构

目录结构如下:

inject-appd-agent/
├── base
│   └── kustomization.yaml      
├── overlays
    └── prod
        ├── appd_agent.yaml   
        └── kustomization.yaml
BASH

其中,后续所有需要注入 APM Agent 的应用的 Deployment, 都放在 base 目录中。

base/kustomization.yaml

resources:
  - ./foo-deployment.yml
YAML

🐾注意:

这里提一句,目前的 resources 是不支持文件通配符 (file glob) 匹配的,具体 issue 可以见这里:

但是有个临时解决方案,就是通过执行命令:kustomize edit add resource base/*.yml 运行后会遍历 file blob, 将结果一个个加到 kustomization.yaml 中。

运行后的文件可能是这样:

resources:
  - ./foo-deployment.yml
  - ./bar-deployment.yml
  - ./a-deployment.yml
  - ./b-deployment.yml
  - ./c-deployment.yml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
YAML

overlays/prod/kustomization.yaml

bases:
  - ../../base
# patchesStrategicMerge:
#   - appd_agent.yaml
patches:
  - path: appd_agent.yaml
    target:
      kind: Deployment
YAML

🐾 注意:

这里没用 patchesStrategicMerge, 而是用了patches. 目的就是为了批量 patch. 上面 YAML 的意思是,将appd_agent.yaml 应用于所有的 Deployment manifests 中。

overlays/prod/appd_agent.yaml

具体内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: not-important
spec:
  template:
    spec:
      containers:
        - name: app
          volumeMounts:
            - mountPath: /opt/appdynamics-java
              name: appd-agent-repo-java
          env:
            - name: APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY
              value: xxxxxxxxxxxxxxxxxxxxxxxxxxxx
            - name: APPDYNAMICS_CONTROLLER_HOST_NAME
              value: 192.168.1.10
            - name: APPDYNAMICS_CONTROLLER_PORT
              value: '8090'
            - name: APPDYNAMICS_CONTROLLER_SSL_ENABLED
              value: 'false'
            - name: APPDYNAMICS_AGENT_ACCOUNT_NAME
              value: my_account
            - name: APPDYNAMICS_AGENT_APPLICATION_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: APPDYNAMICS_AGENT_TIER_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: APPDYNAMICS_AGENT_REUSE_NODE_NAME_PREFIX
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: JAVA_TOOL_OPTIONS
              value:
                ' -Dappdynamics.agent.accountAccessKey=$(APPDYNAMICS_AGENT_ACCOUNT_ACCESS_KEY)
                -Dappdynamics.agent.reuse.nodeName=true -Dappdynamics.socket.collection.bci.enable=true
                -javaagent:/opt/appdynamics-java/javaagent.jar'
            - name: APPDYNAMICS_NETVIZ_AGENT_HOST
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: status.hostIP
            - name: APPDYNAMICS_NETVIZ_AGENT_PORT
              value: '3892'
      initContainers:
        - command:
            - cp
            - -r
            - /opt/appdynamics/.
            - /opt/appdynamics-java
          image: appdynamics/appdynamics-java-agent:1.8-21.11.3.33314
          imagePullPolicy: IfNotPresent
          name: appd-agent-attach-java
          resources:
            limits:
              cpu: 200m
              memory: 75M
            requests:
              cpu: 100m
              memory: 50M
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /opt/appdynamics-java
              name: appd-agent-repo-java
      volumes:
        - name: appd-agent-repo-java
YAML

上面内容就不详细说明了,具体可以参考这篇文章,了解 APM Agent 注入的几种思路:

🐾 注意:

实践中,上面内容有几点需要注意的:

  1. spec/template/spec/containers/name这里往往是应用的名字,如foo, 如果appd_agent.yaml的内容要正确地 patch, 也需要写上同样的 container name; 这对于一个应用来说不是什么问题,但是对于批量自动化 /GitOps 来说,就非常不方便。
  1. 我之前想用 Kustomize 中的 nameReference 来实现,但是没搞出来,有知道的可以教教我
  2. ✔️20220706 11:00 update: Kustomize 出于安全考虑, 是严格按照 metadata.name 进行 merge 的, 所以通过 Kustomize 无法解决; 但是可以通过 yq(类似 jq, 但是针对 yaml)来解决, 示例命令为: i=foo yq -i '.spec.template.spec.containers[0].name="strenv(i)"' appd_agent.yaml
  1. 之前的环境变量,手动部署的时候如这个:
- name: APPDYNAMICS_AGENT_APPLICATION_NAME
  value: foo
YAML
  1. 直接写死,这样不便于批量自动化 /GitOps. 解决办法就是利用 Kubernetes env 的 valueFrom 能力。改为如下就可以了。
valueFrom:
  fieldRef:
    fieldPath: metadata.name
YAML
  1. appd_agent.yaml 的 Deployment name 是无所谓的,因为仍会是被 patch 清单的名字;另外 appd_agent.yaml 也不要带 namespace, 方便批量自动化 /GitOps, 可以适应所有 NameSpace.

自动化脚本

最后,自动化脚本 demo 如下:(假设脚本位于 /inject-appd-agent/scripts/ 目录下)

#!/bin/bash
# USAGE:
# bash inject-appd-agent.sh default
# NAMESPACE=default
NAMESPACE=$1
# only get deploy name
deployments=$(kubectl get deploy --no-headers=true -o custom-columns=:.metadata.name -n "${NAMESPACE}")
for i in ${deployments}; do
    # get deploy yaml
    cd ../base && kubectl get deploy -n "${NAMESPACE}" "${i}" -o yaml | kubectl neat >./"${i}.yml"
    # add the deploy yaml to base
    kustomize edit add resource ./"${i}.yml"
    # change appd_agent.yaml .spec.template.spec.containers[0].name
    #   = <the deploy name>
    cd ../overlays/prod && DEPLOY="${i}" yq -i '.spec.template.spec.containers[0].name = strenv(DEPLOY)' ./appd_agent.yaml
    # dry run
    # kustomize build . >../../examples/output/"${i}.yml"
    # deploy rollout
    kubectl apply -k .
    # remove the deploy yaml resource from base
    cd ../../base && kustomize edit remove resource ./"${i}.yml"
done
# clean up
kustomize edit remove resource ./*.yml
cd ../overlays/prod && yq -i '.spec.template.spec.containers[0].name = "app"' ./appd_agent.yaml
BASH

运行上面脚本,即可实现对所有 Deployment 自动注入 AppD Java Agent, 并 Rollout 生效。

🎉🎉🎉

📚️ Reference

相关实践学习
通过云拨测对指定服务器进行Ping/DNS监测
本实验将通过云拨测对指定服务器进行Ping/DNS监测,评估网站服务质量和用户体验。
相关文章
|
2月前
|
移动开发 监控 Android开发
Android & iOS 使用 ARMS 用户体验监控(RUM)的最佳实践
本文主要介绍了 ARMS 用户体验监控的基本功能特性,并介绍了在几种常见场景下的最佳实践。
371 14
|
2月前
|
SQL 分布式计算 监控
Hadoop-20 Flume 采集数据双写至本地+HDFS中 监控目录变化 3个Agent MemoryChannel Source对比
Hadoop-20 Flume 采集数据双写至本地+HDFS中 监控目录变化 3个Agent MemoryChannel Source对比
72 3
|
19天前
|
监控 开发工具 Android开发
ARMS 用户体验监控正式发布原生鸿蒙应用 SDK
阿里云 ARMS 用户体验监控(RUM)推出了针对原生鸿蒙应用的 SDK。SDK 使用 ArkTS 语言开发,支持页面采集、资源加载采集、异常采集及自定义采集等功能,能够全面监控鸿蒙应用的表现。集成简单,只需几步即可将 SDK 接入项目中,为鸿蒙应用的开发者提供了强有力的支持。
|
1月前
|
存储 Prometheus 运维
在云原生环境中,阿里云ARMS与Prometheus的集成提供了强大的应用实时监控解决方案
在云原生环境中,阿里云ARMS与Prometheus的集成提供了强大的应用实时监控解决方案。该集成结合了ARMS的基础设施监控能力和Prometheus的灵活配置及社区支持,实现了全面、精准的系统状态、性能和错误监控,提升了应用的稳定性和管理效率。通过统一的数据视图和高级查询功能,帮助企业有效应对云原生挑战,促进业务的持续发展。
42 3
|
1月前
|
Prometheus 监控 Java
深入探索:自制Agent监控API接口耗时实践
在微服务架构中,监控API接口的调用耗时对于性能优化至关重要。通过监控接口耗时,我们可以识别性能瓶颈,优化服务响应速度。本文将分享如何自己动手实现一个Agent来统计API接口的调用耗时,提供一种实用的技术解决方案。
53 3
|
1月前
|
监控 数据可视化 Java
深入探索:自制Agent监控API接口耗时
在微服务架构中,监控API接口的调用耗时对于性能优化至关重要。通过监控这些指标,我们可以识别瓶颈,优化系统性能。本文将分享如何自己动手实现一个Agent来统计API接口的调用耗时,提供一种有效的监控解决方案。
47 2
|
3月前
|
监控 Linux
Zabbix 5.0 LTS的agent服务部署实战篇
文章介绍了如何在CentOS 7.6操作系统上部署Zabbix 5.0 LTS版本的agent服务,包括配置软件源、安装agent、修改配置文件、启动服务,并在Zabbix web界面添加监控。
154 4
Zabbix 5.0 LTS的agent服务部署实战篇
|
3月前
|
监控 关系型数据库 MySQL
zabbix agent集成percona监控MySQL的插件实战案例
这篇文章是关于如何使用Percona监控插件集成Zabbix agent来监控MySQL的实战案例。
88 2
zabbix agent集成percona监控MySQL的插件实战案例
|
4月前
|
数据采集 运维 监控
ARMS自定义监控
【8月更文挑战第25天】
123 3
|
16天前
|
机器学习/深度学习 人工智能 自然语言处理
Gemini 2.0:谷歌推出的原生多模态输入输出 + Agent 为核心的 AI 模型
谷歌最新推出的Gemini 2.0是一款原生多模态输入输出的AI模型,以Agent技术为核心,支持多种数据类型的输入与输出,具备强大的性能和多语言音频输出能力。本文将详细介绍Gemini 2.0的主要功能、技术原理及其在多个领域的应用场景。
121 20
Gemini 2.0:谷歌推出的原生多模态输入输出 + Agent 为核心的 AI 模型

热门文章

最新文章