日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

實戰:如何優雅的從 Skywalking 切換到 OpenTelemetry

來源: 責編: 時間:2024-04-08 09:01:34 188觀看
導讀背景最近公司將我們之前使用的鏈路工具切換為了 OpenTelemetry。我們的技術棧是:OTLP Client──────────?Collect────────?StartRocks(Agent)

5Lv28資訊網——每日最新資訊28at.com

背景

最近公司將我們之前使用的鏈路工具切換為了 OpenTelemetry。5Lv28資訊網——每日最新資訊28at.com

5Lv28資訊網——每日最新資訊28at.com

我們的技術棧是:5Lv28資訊網——每日最新資訊28at.com

OTLP                               Client──────────?Collect────────?StartRocks(Agent)                               ▲                                          │                                          │                                       Jaeger

其中客戶端使用 OpenTelemetry 提供的 Java Agent 進行埋點收集數據,再由 Agent 通過 OTLP(OpenTelemetry Protocol) 協議將數據發往 Collector,在 Collector 中我們可以自行任意處理數據,并決定將這些數據如何存儲(這點在以往的 SkyWalking 體系中是很難自定義的)5Lv28資訊網——每日最新資訊28at.com

這里我們將數據寫入 StartRocks 中,供之后的 UI 層進行查看。5Lv28資訊網——每日最新資訊28at.com

OpenTelemetry 是可觀測系統的新標準,基于它可以兼容以前使用的 Prometheus、 victoriametrics、skywalking 等系統,同時還可以靈活擴展,不用與任何但一生態或技術棧進行綁定。更多關于 OTel 的內容會在今后介紹。5Lv28資訊網——每日最新資訊28at.com

難點

其中有一個關鍵問題就是:如何在線上進行無縫切換5Lv28資訊網——每日最新資訊28at.com

雖然我們內部的發布系統已經支持重新發布后就會切換到新的鏈路,也可以讓業務自行發布然后逐步的切換到新的系統,這樣也是最保險的方式。5Lv28資訊網——每日最新資訊28at.com

但這樣會有幾個問題:5Lv28資訊網——每日最新資訊28at.com

  • 當存在調用依賴的系統沒有全部切換為新鏈路時,再查詢的時候就會出現斷層,整個鏈路無法全部串聯起來。
  • 業務團隊沒有足夠的動力去推動發布,可能切換的周期較長。

所以最好的方式還是由我們在后臺統一發布,對外沒有任何感知就可以一鍵全部切換為 OpenTelemetry。5Lv28資訊網——每日最新資訊28at.com

仔細一看貌似也沒什么難的,無非就是模擬用戶點擊發布按鈕而已。5Lv28資訊網——每日最新資訊28at.com

但這事由我們自動來做就不一樣了,用戶點擊發布的時候會選擇他們認為可以發布的分支進行發布,我們不能自作主張的比如選擇 main 分支,有可能只是合并了但還不具備發布條件。5Lv28資訊網——每日最新資訊28at.com

所以保險的方式還是得用當前項目上一次發布時所使用的 git hash 值重新打包發布。5Lv28資訊網——每日最新資訊28at.com

但這也有幾個問題:5Lv28資訊網——每日最新資訊28at.com

  • 重復打包發布太慢了,線上幾十上百個項目,每打包發布一次就得幾分鐘,雖然可以并發,但考慮到 kubernetes 的壓力也不能調的太高。
  • 保不準業務鏡像中有單獨加入一些環境變量,這樣打包可能會漏。

切換方案

所以思來想去最保險的方法還是將業務鏡像拉取下來,然后手動刪除鏡像中的 skywalking 包以及 JVM 參數,全部替換為 OpenTelemetry 的包和 JVM 參數。5Lv28資訊網——每日最新資訊28at.com

整體的方案如下:5Lv28資訊網——每日最新資訊28at.com

  • 遍歷 namespace 的 pod >0 的 deployment。
  • 遍歷 deployment 中的所有 container,獲得業務鏡像。
  1. 跳過 istio 和日志采集 container,獲取到業務容器。
  2. 判斷該容器是否需要替換,其實就是判斷環境變量中是否有 skywalking ,如果有就需要替換。
  3. 獲取業務容器的鏡像。
  • 基于該 Image 重新構建一個 OpenTelemetry 的鏡像 3.1 新的鏡像包含新的啟動腳本. 3.1.1 新的啟動腳本中會刪除原有的 skywalking agent 3.2 新鏡像會包含 OpenTelemetry 的 jar 包以及我們自定義的 OTel 擴展包 3.3 替換啟動命令為新的啟動腳本。
  • 修改 deployment 中的 JVM 啟動參數。
  • 修改 deployment 的鏡像后滾動更新。
  • 開啟一個 goroutine 定時檢測更新之后是否啟動成功。
  • 如果長時間 (比如五分鐘) 都沒有啟動成功,則執行回滾流程。

具體代碼

因為需要涉及到操作 kubernetes,所以整體就使用 Golang 實現了。5Lv28資訊網——每日最新資訊28at.com

遍歷 deployment 得到需要替換的容器鏡像

func ProcessDeployment(ctx context.Context, finish []string, deployment v1.Deployment, clientSet kubernetes.Interface) error { deploymentName := deployment.Name for _, s := range finish {  if s == deploymentName {   klog.Infof("Skip finish deployment:%s", deploymentName)   return nil  } } // Write finish deployment name to a file defer writeDeploymentName2File(deploymentName, fmt.Sprintf("finish-%s.log", deployment.Namespace)) appName := deployment.GetObjectMeta().GetLabels()["appName"] klog.Infof("Begin to process deployment:%s, appName:%s", deploymentName, appName) upgrade, err := checkContainIstio(ctx, deployment, clientSet) if err != nil {  return err } if upgrade == false {  klog.Infof("Don't have istio, No need to upgrade deployment:%s appName:%s", deploymentName, appName)  return nil } for i, container := range deployment.Spec.Template.Spec.Containers {  if strings.HasPrefix(deploymentName, container.Name) {   // Check if container has sw jvm   for _, envVar := range container.Env {    if envVar.Name == "CATALINA_OPTS" {     if !strings.Contains(envVar.Value, "skywalking") {      klog.Infof("Skip upgrade don't have sw jvm deployment:%s container:%s", deploymentName, container.Name)      return nil     }    }   }   upgrade(container)   // Check newDeployment status   go checkNewDeploymentStatus(ctx, clientSet, newDeployment)   // delete from image   deleteImage(container.Image)  } } return nil}

這個函數需要傳入一個 deployment ,同時還有一個已經完成了的列表進來。5Lv28資訊網——每日最新資訊28at.com

已完成列表用于多次運行的時候可以快速跳過已經執行的 deployment。5Lv28資訊網——每日最新資訊28at.com

checkContainIstio() 函數很簡單,判斷是否包含了 Istio 容器,如果沒有包含說明不是后端應用(可能是前端、大數據之類的任務),就可以直接跳過了。5Lv28資訊網——每日最新資訊28at.com

5Lv28資訊網——每日最新資訊28at.com

而判斷是否需要替換的前提這事判斷環境變量 CATALINA_OPTS 中是否包含了 skywalking 的內容,如果包含則說明需要進行替換。5Lv28資訊網——每日最新資訊28at.com

Upgrade 核心函數

func upgrade(container Container){ klog.Infof("Begin to upgrade deployment:%s container:%s", deploymentName, container.Name) newImageName := fmt.Sprintf("%s-otel-%s", container.Image, generateRandomString(4)) err := BuildNewOtelImage(container.Image, newImageName) if err != nil {  return err } // Update deployment jvm ENV for e, envVar := range container.Env {  if envVar.Name == "CATALINA_OPTS" {   otelJVM := replaceSWAgent2OTel(envVar.Value, appName)   deployment.Spec.Template.Spec.Containers[i].Env[e].Value = otelJVM  } } // Update deployment image deployment.Spec.Template.Spec.Containers[i].Image = newImageName newDeployment, err := clientSet.AppsV1().Deployments(deployment.Namespace).Update(ctx, &deployment, metav1.UpdateOptions{}) if err != nil {  return err } klog.Infof("Finish upgrade deployment:%s container:%s", deploymentName, container.Name)}

這里一共分為以下幾部:5Lv28資訊網——每日最新資訊28at.com

  • 基于老鏡像構建新鏡像。
  • 更新原有的 CATALINA_OPTS 環境變量,也就是替換 skywalking 的參數。
  • 更新 deployment 鏡像,觸發滾動更新。

構建新鏡像

dockerfile = fmt.Sprintf(`FROM %sCOPY %s /home/admin/%sCOPY otel.tar.gz /home/admin/otel.tar.gzRUN tar -zxvf /home/admin/otel.tar.gz -C /home/adminRUN rm -rf /home/admin/skywalking-agentENTRYPOINT ["/bin/sh", "/home/admin/start.sh"]`, fromImage, script, script) idx := strings.LastIndex(newImageName, "/") + 1 dockerFileName := newImageName[idx:] create, err := os.Create(fmt.Sprintf("Dockerfile-%s", dockerFileName)) if err != nil {  return err } defer func() {  create.Close()  os.Remove(create.Name()) }() _, err = create.WriteString(dockerfile) if err != nil {  return err } cmd := exec.Command("docker", "build", ".", "-f", create.Name(), "-t", newImageName) cmd.Stdin = strings.NewReader(dockerfile) if err := cmd.Run(); err != nil {  return err }

其實這里的重點就是構建這個新鏡像,從這個 dockerfile 中也能看出具體的邏輯,也就是上文提到的刪除原有的 skywalking 資源同時將新的 OpenTelemetry 資源打包進去。5Lv28資訊網——每日最新資訊28at.com

最后再將這個鏡像上傳到私服。5Lv28資訊網——每日最新資訊28at.com

5Lv28資訊網——每日最新資訊28at.com

其中的替換 JVM 參數也比較簡單,直接刪除 skywalking 的內容,然后再追加上 OpenTelemetry 需要的參數即可。5Lv28資訊網——每日最新資訊28at.com

定時檢測替換是否成功

func checkNewDeploymentStatus(ctx context.Context, clientSet kubernetes.Interface, newDeployment *v1.Deployment) error { ready := true tick := time.Tick(10 * time.Second) for i := 0; i < 30; i++ {  <-tick  originPodList, err := clientSet.CoreV1().Pods(newDeployment.Namespace).List(ctx, metav1.ListOptions{   LabelSelector: metav1.FormatLabelSelector(&metav1.LabelSelector{    MatchLabels: newDeployment.Spec.Selector.MatchLabels,   }),  })  if err != nil {   return err  }  // Check if there are any Pods  if len(originPodList.Items) == 0 {   klog.Infof("No Pod in deployment:%s, Skip", newDeployment.Name)  }  for _, item := range originPodList.Items {   // Check Pod running   for _, status := range item.Status.ContainerStatuses {    if status.RestartCount > 0 {     ready = false     break    }   }  }  klog.Infof("Check deployment:%s namespace:%s status:%t", newDeployment.Name, newDeployment.Namespace, ready)  if ready == false {   break  } } if ready == false {  // rollback  klog.Infof("=======Rollback deployment:%s namespace:%s", newDeployment.Name, newDeployment.Namespace)  writeDeploymentName2File(newDeployment.Name, fmt.Sprintf("rollback-%s.log", newDeployment.Namespace)) } return nil}

這里會啟動一個 10s 執行一次的定時任務,每次都會檢測是否有容器發生了重啟(正常情況下是不會出現重啟的)5Lv28資訊網——每日最新資訊28at.com

如果檢測了 30 次都沒有重啟的容器,那就說明本次替換成功了,不然就記錄一個日志文件,然后人工處理。5Lv28資訊網——每日最新資訊28at.com

這種通常是原有的鏡像與 OpenTelemetry 不兼容,比如里面寫死了一些 skywalking 的 API,導致啟動失敗。5Lv28資訊網——每日最新資訊28at.com

所以替換任務跑完之后我還會檢測這個 rollback-$namespace 的日志文件,人工處理這些失敗的應用。5Lv28資訊網——每日最新資訊28at.com

分批處理 deployment

最后講講如何單個調用剛才的 ProcessDeployment() 函數。5Lv28資訊網——每日最新資訊28at.com

考慮到不能對 kubernetes 產生影響,所以我們需要限制并發處理 deployment 的數量(我這里的限制是 10 個)。5Lv28資訊網——每日最新資訊28at.com

所以就得分批進行替換,每次替換 10 個,而且其中有一個執行失敗就得暫停后續任務,由人工檢測失敗原因再決定是否繼續處理。5Lv28資訊網——每日最新資訊28at.com

畢竟處理的是線上應用,需要小心謹慎。5Lv28資訊網——每日最新資訊28at.com

所以觸發的代碼如下:5Lv28資訊網——每日最新資訊28at.com

func ProcessDeploymentList(ctx context.Context, data []v1.Deployment, clientSet kubernetes.Interface) error { file, err := os.ReadFile(fmt.Sprintf("finish-%s.log", data[0].Namespace)) if err != nil {  return err } split := strings.Split(string(file), "/n") batchSize := 10 start := 0 for start < len(data) {  end := start + batchSize  if end > len(data) {   end = len(data)  }  batch := data[start:end]  //等待goroutine結束  var wg sync.WaitGroup  klog.Infof("Start process batch size %d", len(batch))  errs := make(chan error, len(batch))  wg.Add(len(batch))  for _, item := range batch {   d := item   go func() {    defer wg.Done()    if err := ProcessDeployment(ctx, split, d, clientSet); err != nil {     klog.Errorf("!!!Process deployment name:%s error: %v", d.Name, err)     errs <- err     return    }   }()  }  go func() {   wg.Wait()   close(errs)  }()  //任何一個失敗就返回  for err := range errs {   if err != nil {    return err   }  }  start = end  klog.Infof("Deal next batch") } return nil}

使用 WaitGroup 來控制一組任務,使用一個 chan 來傳遞異常;這類分批處理的代碼在一些批處理框架中還蠻常見的。5Lv28資訊網——每日最新資訊28at.com

總結

最后只需要查詢某個 namespace 下的所有 deployment 列表傳入這個批處理函數即可。5Lv28資訊網——每日最新資訊28at.com

不過整個過程中還是有幾個點需要注意:5Lv28資訊網——每日最新資訊28at.com

  • 因為需要替換鏡像的前提是要把現有的鏡像拉取到本地,所以跑這個任務的客戶端需要有充足的磁盤,同時和鏡像服務器的網絡條件較好。
  • 不然執行的過程會比較慢,同時磁盤占用滿了也會影響任務。

其實這個功能依然有提升空間,考慮到后續會升級 OpenTelemetry  agent 的版本,甚至也需要增減一些 JVM 參數。5Lv28資訊網——每日最新資訊28at.com

所以最后有一個統一的工具,可以直接升級 Agent,而不是每次我都需要修改這里的代碼。5Lv28資訊網——每日最新資訊28at.com

5Lv28資訊網——每日最新資訊28at.com

后來在網上看到了得物的相關分享,他們可以遠程加載配置來解決這個問題。5Lv28資訊網——每日最新資訊28at.com

這也是一種解決方案,直到我們看到了 OpenTelemetry 社區提供了 Operator,其中也包含了注入 agent 的功能。5Lv28資訊網——每日最新資訊28at.com

apiVersion: opentelemetry.io/v1alpha1  kind: Instrumentation  metadata:    name: my-instrumentation  spec:    exporter:      endpoint: http://otel-collector:4317    propagators:      - tracecontext      - baggage      - b3    sampler:      type: parentbased_traceidratio      argument: "0.25"    java:      image: private/autoinstrumentation-java:1.32.0-1

我們可以使用他提供的 CRD 來配置我們 agent,只要維護好自己的鏡像就好了。5Lv28資訊網——每日最新資訊28at.com

使用起來也很簡單,只要安裝好了 OpenTelemetry-operator ,然后再需要注入 Java Agent 的 Pod 中使用注解:5Lv28資訊網——每日最新資訊28at.com

instrumentation.opentelemetry.io/inject-java: "true"

operator 就會自動從剛才我們配置的鏡像中讀取 agent,然后復制到我們的業務容器。5Lv28資訊網——每日最新資訊28at.com

再配置上環境變量 $JAVA_TOOL_OPTIONS=/otel/javaagent.java, 這是一個 Java 內置的環境變量,應用啟動的時候會自動識別,這樣就可以自動注入 agent 了。5Lv28資訊網——每日最新資訊28at.com

envJavaToolsOptions   = "JAVA_TOOL_OPTIONS"http:// set env valueidx := getIndexOfEnv(container.Env, envJavaToolsOptions)  if idx == -1 {      container.Env = append(container.Env, corev1.EnvVar{         Name:  envJavaToolsOptions,         Value: javaJVMArgument,      })} else {      container.Env[idx].Value = container.Env[idx].Value + javaJVMArgument  }// copy javaagent.jarpod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{      Name:      javaInitContainerName,      Image:     javaSpec.Image,      Command:   []string{"cp", "/javaagent.jar", javaInstrMountPath + "/javaagent.jar"},      Resources: javaSpec.Resources,      VolumeMounts: []corev1.VolumeMount{{         Name:      javaVolumeName,         MountPath: javaInstrMountPath,      }},})

大致的運行原理是當有 Pod 的事件發生了變化(重啟、重新部署等),operator 就會檢測到變化,此時會判斷是否開啟了剛才的注解:5Lv28資訊網——每日最新資訊28at.com

instrumentation.opentelemetry.io/inject-java: "true"

接著會寫入環境變量 JAVA_TOOL_OPTIONS,同時將 jar 包從 InitContainers 中復制到業務容器中。5Lv28資訊網——每日最新資訊28at.com

這里使用到了 kubernetes 的初始化容器,該容器是用于做一些準備工作的,比如依賴安裝、配置檢測或者是等待其他一些組件啟動成功后再啟動業務容器。5Lv28資訊網——每日最新資訊28at.com

目前這個 operator 還處于使用階段,同時部分功能還不滿足(比如支持自定義擴展),今后有時間也可以分析下它的運行原理。5Lv28資訊網——每日最新資訊28at.com

參考鏈接:5Lv28資訊網——每日最新資訊28at.com

  • https://xie.infoq.cn/article/e6def1e245e9d67735bd00dd5。
  • https://github.com/open-telemetry/opentelemetry-operator/#opentelemetry-auto-instrumentation-injection。

本文鏈接:http://www.www897cc.com/showinfo-26-81873-0.html實戰:如何優雅的從 Skywalking 切換到 OpenTelemetry

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Springboot 3.1.x: 快速掌握事件驅動的實用技巧

下一篇: Python深度解析:可變與不可變對象的奧秘

標簽:
  • 熱門焦點
  • 十個簡單但很有用的Python裝飾器

    裝飾器(Decorators)是Python中一種強大而靈活的功能,用于修改或增強函數或類的行為。裝飾器本質上是一個函數,它接受另一個函數或類作為參數,并返回一個新的函數或類。它們通常用
  • 三言兩語說透柯里化和反柯里化

    JavaScript中的柯里化(Currying)和反柯里化(Uncurrying)是兩種很有用的技術,可以幫助我們寫出更加優雅、泛用的函數。本文將首先介紹柯里化和反柯里化的概念、實現原理和應用
  • 猿輔導與新東方的兩種“歸途”

    作者|卓心月 出品|零態LT(ID:LingTai_LT)如何成為一家偉大企業?答案一定是對&ldquo;勢&rdquo;的把握,這其中最關鍵的當屬對企業戰略的制定,且能夠站在未來看現在,即使這其中的
  • 大廠卷向扁平化

    來源:新熵作者丨南枝 編輯丨月見大廠職級不香了。俗話說,兵無常勢,水無常形,互聯網企業調整職級體系并不稀奇。7月13日,淘寶天貓集團啟動了近年來最大的人力制度改革,目前已形成一
  • 認真聊聊東方甄選:如何告別低垂的果實

    來源:山核桃作者:財經無忌爆火一年后,俞敏洪和他的東方甄選依舊是頗受外界關心的&ldquo;網紅&rdquo;。7月5日至9日,為期5天的東方甄選&ldquo;甘肅行&rdquo;首次在自有App內直播,
  • 疑似小米14外觀設計圖曝光:后置相機模組變化不大

    下半年的大幕已經開啟,而誰將成為下半年手機圈的主角就成為了大家關注的焦點,其中被傳有望拿下新一代驍龍8 Gen3旗艦芯片的小米14系列更是備受大家矚
  • 到手價3099元起!iQOO Neo8 Pro今日首銷:安卓性能最強旗艦

    5月23日,iQOO如期舉行了新品發布會,全新的iQOO Neo8系列也正式與大家見面,包含iQOO Neo8和iQOO Neo8 Pro兩個版本,其中標準版搭載高通驍龍8+,而Pro版更
  • 回歸OPPO兩年,一加贏了銷量,輸了品牌

    成為OPPO旗下主打性能的先鋒品牌后,一加屢創佳績。今年618期間,一加手機全渠道銷量同比增長362%,憑借一加 11、一加 Ace 2、一加 Ace 2V三款爆品,一加
  • SN570 NVMe SSD固態硬盤 價格與性能兼具

    SN570 NVMe SSD固態硬盤是西部數據發布的最新一代WD Blue系列的固態硬盤,不僅閃存技術更為精進,性能也得到了進一步的躍升。WD Blue SN570 NVMe SSD的包裝外
Top 主站蜘蛛池模板: 轮台县| 留坝县| 宜阳县| 奈曼旗| 乐东| 平山县| 南昌县| 惠水县| 石城县| 成都市| 江达县| 广元市| 客服| 潮州市| 香格里拉县| 科尔| 邹平县| 桐庐县| 闸北区| 钦州市| 常德市| 镶黄旗| 酉阳| 湟源县| 石城县| 通化县| 瓦房店市| 南溪县| 神木县| 大足县| 汉沽区| 百色市| 张北县| 西青区| 夹江县| 革吉县| 尉氏县| 星子县| 大方县| 烟台市| 玉门市|