• 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 实现共享;
      2. 在 Deployment -> 应用自己的 container 中,加入以下参数:
        1. volumeMounts: 把 java agent jar 包挂载到 volume 实现共享;
        2. 加入各种 AppD Java agent 需要的 env 信息;
      3. volumes 通过 tmpdir 实现共享。

    Kustomize 目录结构

    目录结构如下:

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

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

    base/kustomization.yaml

    resources:
      - ./foo-deployment.yml
    

    🐾注意:
    这里提一句,目前的 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
    

    overlays/prod/kustomization.yaml

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

    🐾 注意:

    这里没用 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
    

    上面内容就不详细说明了,具体可以参考这篇文章,了解 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
    2. 之前的环境变量,手动部署的时候如这个:

      - name: APPDYNAMICS_AGENT_APPLICATION_NAME
        value: foo
      

      直接写死,这样不便于批量自动化/GitOps. 解决办法就是利用 Kubernetes env 的 valueFrom 能力。改为如下就可以了。

      valueFrom:
        fieldRef:
          fieldPath: metadata.name
      
    3. 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
        #   = 
        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
    

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

    🎉🎉🎉

    📚️ Reference

    三人行, 必有我师; 知识共享, 天下为公. 本文由东风微鸣技术博客 EWhisper.cn 编写.

  • 相关阅读:
    java计算机毕业设计酒店预约及管理系统源码+mysql数据库+系统+lw文档+部署
    图片无损放大在线工具分享
    实验室检测管理系统能解决什么问题
    services资源+pod详解
    Oracle数据库:创建表空间,创建新用户,给用户分配对象、角色和系统权限,登录新用户建表
    ngx-datatable的使用
    nvue文件中@click.stop失效
    nginx之基于LNMP搭建论坛
    Android 13.0 第三方无源码apk授予QUERY_ALL_PACKAGES等其他权限的方法
    Netty 学习(一):服务端启动 & 客户端启动
  • 原文地址:https://www.cnblogs.com/east4ming/p/17217760.html