[{"data":1,"prerenderedAt":1009},["ShallowReactive",2],{"article-\u002Farticles\u002Fargocd-gitops":3},{"id":4,"title":5,"body":6,"date":995,"description":24,"excerpt":996,"extension":997,"meta":998,"navigation":999,"path":1000,"seo":1001,"stem":1002,"tags":1003,"__hash__":1008},"articles\u002Farticles\u002Fargocd-gitops.md","GitOps 與 Argo CD：為什麼部署要從「推」改成「拉」",{"type":7,"value":8,"toc":985},"minimark",[9,14,18,57,65,97,101,111,138,145,152,174,177,181,190,421,424,455,459,465,538,552,570,579,583,590,651,658,662,665,670,678,681,686,693,926,929,934,937,941,944,965,968,981],[10,11,13],"h2",{"id":12},"push-模式的問題","Push 模式的問題",[15,16,17],"p",{},"最常見的 Kubernetes 部署方式，是在 CI Pipeline 的最後一步直接部署：",[19,20,25],"pre",{"className":21,"code":22,"language":23,"meta":24,"style":24},"language-bash shiki shiki-themes github-dark","helm upgrade --install order-api .\u002Fcharts\u002Forder-api -f envs\u002Fprod\u002Fvalues.yaml\n","bash","",[26,27,28],"code",{"__ignoreMap":24},[29,30,33,37,41,45,48,51,54],"span",{"class":31,"line":32},"line",1,[29,34,36],{"class":35},"svObZ","helm",[29,38,40],{"class":39},"sU2Wk"," upgrade",[29,42,44],{"class":43},"sDLfK"," --install",[29,46,47],{"class":39}," order-api",[29,49,50],{"class":39}," .\u002Fcharts\u002Forder-api",[29,52,53],{"class":43}," -f",[29,55,56],{"class":39}," envs\u002Fprod\u002Fvalues.yaml\n",[15,58,59,60,64],{},"這叫 ",[61,62,63],"strong",{},"Push 模式","：由 Pipeline 把變更「推」進叢集。它可以運作，但隨著叢集與服務變多，問題會一一浮現：",[66,67,68,75,85,91],"ul",{},[69,70,71,74],"li",{},[61,72,73],{},"CI 系統要握有叢集的管理權限","：每一個 Pipeline 都要有能改正式環境的憑證，CI 系統一旦被入侵，所有叢集都暴露",[69,76,77,80,81,84],{},[61,78,79],{},"叢集的實際狀態沒人知道","：有人半夜手動 ",[26,82,83],{},"kubectl edit"," 調整了設定解決問題，事後沒有改回設定檔，下次部署時又被覆蓋回去，問題重現",[69,86,87,90],{},[61,88,89],{},"「現在線上是什麼版本」要去叢集裡查","：沒有一個地方可以一眼看出每個環境部署了什麼",[69,92,93,96],{},[61,94,95],{},"回滾要重跑 Pipeline","：而且要記得當時是用哪一個 commit、哪一份 values 部署的",[10,98,100],{"id":99},"gitopsgit-是唯一的真相","GitOps：Git 是唯一的真相",[15,102,103,106,107,110],{},[61,104,105],{},"GitOps"," 的核心想法是：",[61,108,109],{},"叢集應該是什麼樣子，完全由 Git 上的檔案描述","。OpenGitOps 定義了四個原則：",[112,113,114,120,126,132],"ol",{},[69,115,116,119],{},[61,117,118],{},"宣告式（Declarative）","：系統的期望狀態以宣告式的設定描述（Kubernetes Manifest、Helm values）",[69,121,122,125],{},[61,123,124],{},"版本化且不可變（Versioned and Immutable）","：期望狀態存在 Git 中，每一次變更都有紀錄，可以追溯、可以回到任何一個版本",[69,127,128,131],{},[61,129,130],{},"自動拉取（Pulled Automatically）","：由叢集內的代理程式主動從 Git 拉取期望狀態，而不是由外部推入",[69,133,134,137],{},[61,135,136],{},"持續調和（Continuously Reconciled）","：代理程式持續比對「期望狀態」與「實際狀態」，發現不一致就修正",[15,139,140],{},[141,142],"img",{"alt":143,"src":144},"GitOps 與 Argo CD 流程示意圖：CI Pipeline 建置測試並把映像推到 Image Registry，再更新 Git 上 values.yaml 的 image.tag；工程師調整設定也是發 PR 到 Git；Argo CD 從 Git 拉取期望狀態，比對期望與實際，不一致就同步到 dev 與 prod 叢集；如果有人手動 kubectl scale 把 replicas 改成 8，Argo CD 會標示 OutOfSync，開啟 selfHeal 時自動改回 Git 上的 replicas 4","\u002Fimages\u002Farticles\u002Fargocd-gitops.svg",[15,146,147,148,151],{},"在 GitOps 的流程裡，",[61,149,150],{},"CI 和 CD 被拆開","了：",[66,153,154,164],{},[69,155,156,159,160,163],{},[61,157,158],{},"CI"," 只負責建置、測試、推送映像，最後",[61,161,162],{},"更新 Git 上的映像版本號","（發一個 commit 或 PR），不碰叢集",[69,165,166,169,170,173],{},[61,167,168],{},"CD"," 由叢集內的 ",[61,171,172],{},"Argo CD"," 負責：它看到 Git 變了，就把叢集同步成 Git 描述的狀態",[15,175,176],{},"部署變成「改 Git」，回滾變成「revert 一個 commit」，稽核變成「看 Git log」。",[10,178,180],{"id":179},"argo-cd-的核心概念application","Argo CD 的核心概念：Application",[15,182,183,184,189],{},"Argo CD 用一個 CRD ",[61,185,186],{},[26,187,188],{},"Application"," 描述「把哪個 Git 路徑的內容，部署到哪個叢集的哪個 Namespace」：",[19,191,195],{"className":192,"code":193,"language":194,"meta":24,"style":24},"language-yaml shiki shiki-themes github-dark","apiVersion: argoproj.io\u002Fv1alpha1\nkind: Application\nmetadata:\n  name: order-api-prod\n  namespace: argocd\nspec:\n  project: trading\n  source:\n    repoURL: https:\u002F\u002Fgit.example.com\u002Fplatform\u002Fdeploy.git\n    targetRevision: main\n    path: charts\u002Forder-api\n    helm:\n      valueFiles:\n        - ..\u002F..\u002Fenvs\u002Fprod\u002Forder-api\u002Fvalues.yaml\n  destination:\n    server: https:\u002F\u002Fprod-cluster.example.com\n    namespace: order\n  syncPolicy:\n    automated:\n      prune: true\n      selfHeal: true\n    syncOptions:\n      - CreateNamespace=true\n","yaml",[26,196,197,210,221,230,241,252,260,271,279,290,301,312,320,328,337,345,356,367,375,383,394,404,412],{"__ignoreMap":24},[29,198,199,203,207],{"class":31,"line":32},[29,200,202],{"class":201},"s4JwU","apiVersion",[29,204,206],{"class":205},"s95oV",": ",[29,208,209],{"class":39},"argoproj.io\u002Fv1alpha1\n",[29,211,213,216,218],{"class":31,"line":212},2,[29,214,215],{"class":201},"kind",[29,217,206],{"class":205},[29,219,220],{"class":39},"Application\n",[29,222,224,227],{"class":31,"line":223},3,[29,225,226],{"class":201},"metadata",[29,228,229],{"class":205},":\n",[29,231,233,236,238],{"class":31,"line":232},4,[29,234,235],{"class":201},"  name",[29,237,206],{"class":205},[29,239,240],{"class":39},"order-api-prod\n",[29,242,244,247,249],{"class":31,"line":243},5,[29,245,246],{"class":201},"  namespace",[29,248,206],{"class":205},[29,250,251],{"class":39},"argocd\n",[29,253,255,258],{"class":31,"line":254},6,[29,256,257],{"class":201},"spec",[29,259,229],{"class":205},[29,261,263,266,268],{"class":31,"line":262},7,[29,264,265],{"class":201},"  project",[29,267,206],{"class":205},[29,269,270],{"class":39},"trading\n",[29,272,274,277],{"class":31,"line":273},8,[29,275,276],{"class":201},"  source",[29,278,229],{"class":205},[29,280,282,285,287],{"class":31,"line":281},9,[29,283,284],{"class":201},"    repoURL",[29,286,206],{"class":205},[29,288,289],{"class":39},"https:\u002F\u002Fgit.example.com\u002Fplatform\u002Fdeploy.git\n",[29,291,293,296,298],{"class":31,"line":292},10,[29,294,295],{"class":201},"    targetRevision",[29,297,206],{"class":205},[29,299,300],{"class":39},"main\n",[29,302,304,307,309],{"class":31,"line":303},11,[29,305,306],{"class":201},"    path",[29,308,206],{"class":205},[29,310,311],{"class":39},"charts\u002Forder-api\n",[29,313,315,318],{"class":31,"line":314},12,[29,316,317],{"class":201},"    helm",[29,319,229],{"class":205},[29,321,323,326],{"class":31,"line":322},13,[29,324,325],{"class":201},"      valueFiles",[29,327,229],{"class":205},[29,329,331,334],{"class":31,"line":330},14,[29,332,333],{"class":205},"        - ",[29,335,336],{"class":39},"..\u002F..\u002Fenvs\u002Fprod\u002Forder-api\u002Fvalues.yaml\n",[29,338,340,343],{"class":31,"line":339},15,[29,341,342],{"class":201},"  destination",[29,344,229],{"class":205},[29,346,348,351,353],{"class":31,"line":347},16,[29,349,350],{"class":201},"    server",[29,352,206],{"class":205},[29,354,355],{"class":39},"https:\u002F\u002Fprod-cluster.example.com\n",[29,357,359,362,364],{"class":31,"line":358},17,[29,360,361],{"class":201},"    namespace",[29,363,206],{"class":205},[29,365,366],{"class":39},"order\n",[29,368,370,373],{"class":31,"line":369},18,[29,371,372],{"class":201},"  syncPolicy",[29,374,229],{"class":205},[29,376,378,381],{"class":31,"line":377},19,[29,379,380],{"class":201},"    automated",[29,382,229],{"class":205},[29,384,386,389,391],{"class":31,"line":385},20,[29,387,388],{"class":201},"      prune",[29,390,206],{"class":205},[29,392,393],{"class":43},"true\n",[29,395,397,400,402],{"class":31,"line":396},21,[29,398,399],{"class":201},"      selfHeal",[29,401,206],{"class":205},[29,403,393],{"class":43},[29,405,407,410],{"class":31,"line":406},22,[29,408,409],{"class":201},"    syncOptions",[29,411,229],{"class":205},[29,413,415,418],{"class":31,"line":414},23,[29,416,417],{"class":205},"      - ",[29,419,420],{"class":39},"CreateNamespace=true\n",[15,422,423],{},"每個 Application 都有兩個狀態：",[66,425,426,439],{},[69,427,428,431,432,435,436],{},[61,429,430],{},"Sync Status","：叢集的實際狀態和 Git 是否一致——",[26,433,434],{},"Synced"," 或 ",[26,437,438],{},"OutOfSync",[69,440,441,444,445,448,449,448,452],{},[61,442,443],{},"Health Status","：部署出去的資源是否健康——Deployment 的 Pod 都 Ready 了嗎？",[26,446,447],{},"Healthy","、",[26,450,451],{},"Progressing",[26,453,454],{},"Degraded",[10,456,458],{"id":457},"同步策略automatedpruneselfheal","同步策略：automated、prune、selfHeal",[15,460,461,464],{},[26,462,463],{},"syncPolicy"," 決定 Argo CD 發現不一致時要做什麼：",[466,467,468,484],"table",{},[469,470,471],"thead",{},[472,473,474,478,481],"tr",{},[475,476,477],"th",{},"設定",[475,479,480],{},"作用",[475,482,483],{},"沒開的話",[485,486,487,504,521],"tbody",{},[472,488,489,495,501],{},[490,491,492],"td",{},[26,493,494],{},"automated",[490,496,497,498],{},"Git 有變更時",[61,499,500],{},"自動同步",[490,502,503],{},"只標示 OutOfSync，要人按下 Sync",[472,505,506,511,518],{},[490,507,508],{},[26,509,510],{},"prune: true",[490,512,513,514,517],{},"Git 上",[61,515,516],{},"刪掉","的資源，叢集裡也刪掉",[490,519,520],{},"資源會留在叢集裡變成孤兒",[472,522,523,528,535],{},[490,524,525],{},[26,526,527],{},"selfHeal: true",[490,529,530,531,534],{},"叢集被",[61,532,533],{},"手動修改","時，自動改回 Git 的狀態",[490,536,537],{},"只標示 OutOfSync，不主動修正",[15,539,540,543,544,547,548,551],{},[26,541,542],{},"selfHeal"," 是 GitOps 最有感的一點：有人手動 ",[26,545,546],{},"kubectl scale --replicas=8","，Argo CD 幾秒內就會把它改回 Git 上的 ",[26,549,550],{},"replicas: 4","。這逼著所有變更都必須走 Git——想改副本數，就去改 values 檔發 PR。",[553,554,555],"blockquote",{},[15,556,557,558,561,562,565,566,569],{},"例外：和 HPA 一起使用時，副本數是由 HPA 動態決定的，Argo CD 不應該把它改回去。可以在 Application 中用 ",[26,559,560],{},"ignoreDifferences"," 忽略 Deployment 的 ",[26,563,564],{},"\u002Fspec\u002Freplicas","，或是乾脆不在 Manifest 中設定 ",[26,567,568],{},"replicas","。",[15,571,572,573,575,576,578],{},"正式環境要不要開 ",[26,574,494],{},"，各團隊的選擇不同：有些團隊在正式環境只開 ",[26,577,542],{}," 防止漂移，同步仍然由人在確認後按下，把「合併 PR」和「真正上線」拆成兩個決策點。",[10,580,582],{"id":581},"sync-wave控制資源的部署順序","Sync Wave：控制資源的部署順序",[15,584,585,586,589],{},"一個應用程式可能包含資料庫 Migration Job、ConfigMap、Deployment，它們之間有先後順序：Migration 要先跑完，新版的程式才能啟動。Argo CD 用 ",[61,587,588],{},"Sync Wave"," 控制順序，數字小的先部署，等它健康了才進下一波：",[19,591,593],{"className":192,"code":592,"language":194,"meta":24,"style":24},"metadata:\n  annotations:\n    argocd.argoproj.io\u002Fsync-wave: \"-1\"   # Migration Job：先跑\n---\nmetadata:\n  annotations:\n    argocd.argoproj.io\u002Fsync-wave: \"0\"    # Deployment：後跑（預設 0）\n",[26,594,595,601,608,622,627,633,639],{"__ignoreMap":24},[29,596,597,599],{"class":31,"line":32},[29,598,226],{"class":201},[29,600,229],{"class":205},[29,602,603,606],{"class":31,"line":212},[29,604,605],{"class":201},"  annotations",[29,607,229],{"class":205},[29,609,610,613,615,618],{"class":31,"line":223},[29,611,612],{"class":201},"    argocd.argoproj.io\u002Fsync-wave",[29,614,206],{"class":205},[29,616,617],{"class":39},"\"-1\"",[29,619,621],{"class":620},"sAwPA","   # Migration Job：先跑\n",[29,623,624],{"class":31,"line":232},[29,625,626],{"class":35},"---\n",[29,628,629,631],{"class":31,"line":243},[29,630,226],{"class":201},[29,632,229],{"class":205},[29,634,635,637],{"class":31,"line":254},[29,636,605],{"class":201},[29,638,229],{"class":205},[29,640,641,643,645,648],{"class":31,"line":262},[29,642,612],{"class":201},[29,644,206],{"class":205},[29,646,647],{"class":39},"\"0\"",[29,649,650],{"class":620},"    # Deployment：後跑（預設 0）\n",[15,652,653,654,657],{},"搭配 ",[26,655,656],{},"argocd.argoproj.io\u002Fhook: PreSync"," 這類 Hook，還可以定義只在同步前或同步後執行的 Job，例如部署前的資料庫備份、部署後的冒煙測試。",[10,659,661],{"id":660},"多叢集多環境怎麼規劃","多叢集、多環境怎麼規劃",[15,663,664],{},"當環境與服務一多，Application 的數量會快速增加。常見的規劃方式：",[15,666,667],{},[61,668,669],{},"Helm Chart 共用，環境差異只放在 values",[19,671,676],{"className":672,"code":674,"language":675,"meta":24},[673],"language-text","deploy\u002F\n├── charts\u002F\n│   └── order-api\u002F            ← 共用的 Chart\n└── envs\u002F\n    ├── dev\u002Forder-api\u002Fvalues.yaml\n    ├── uat\u002Forder-api\u002Fvalues.yaml\n    └── prod\u002Forder-api\u002Fvalues.yaml\n","text",[26,677,674],{"__ignoreMap":24},[15,679,680],{},"環境之間的差異（副本數、資源、網域、外部服務位址）集中在 values 檔，比對兩個環境的差異就是比對兩個檔案。",[15,682,683],{},[61,684,685],{},"用 ApplicationSet 產生 Application",[15,687,688,689,692],{},"不需要為「每個服務 × 每個環境」手寫一份 Application。",[26,690,691],{},"ApplicationSet"," 可以依 Git 目錄結構或叢集清單自動產生：",[19,694,696],{"className":192,"code":695,"language":194,"meta":24,"style":24},"apiVersion: argoproj.io\u002Fv1alpha1\nkind: ApplicationSet\nmetadata:\n  name: order-api\nspec:\n  generators:\n    - list:\n        elements:\n          - env: dev\n            cluster: https:\u002F\u002Fdev-cluster.example.com\n          - env: prod\n            cluster: https:\u002F\u002Fprod-cluster.example.com\n  template:\n    metadata:\n      name: \"order-api-{{env}}\"\n    spec:\n      project: trading\n      source:\n        repoURL: https:\u002F\u002Fgit.example.com\u002Fplatform\u002Fdeploy.git\n        targetRevision: main\n        path: charts\u002Forder-api\n        helm:\n          valueFiles: [\"..\u002F..\u002Fenvs\u002F{{env}}\u002Forder-api\u002Fvalues.yaml\"]\n      destination:\n        server: \"{{cluster}}\"\n        namespace: order\n",[26,697,698,706,715,721,730,736,743,753,760,773,783,794,802,809,816,826,833,842,849,858,867,876,883,897,905,916],{"__ignoreMap":24},[29,699,700,702,704],{"class":31,"line":32},[29,701,202],{"class":201},[29,703,206],{"class":205},[29,705,209],{"class":39},[29,707,708,710,712],{"class":31,"line":212},[29,709,215],{"class":201},[29,711,206],{"class":205},[29,713,714],{"class":39},"ApplicationSet\n",[29,716,717,719],{"class":31,"line":223},[29,718,226],{"class":201},[29,720,229],{"class":205},[29,722,723,725,727],{"class":31,"line":232},[29,724,235],{"class":201},[29,726,206],{"class":205},[29,728,729],{"class":39},"order-api\n",[29,731,732,734],{"class":31,"line":243},[29,733,257],{"class":201},[29,735,229],{"class":205},[29,737,738,741],{"class":31,"line":254},[29,739,740],{"class":201},"  generators",[29,742,229],{"class":205},[29,744,745,748,751],{"class":31,"line":262},[29,746,747],{"class":205},"    - ",[29,749,750],{"class":201},"list",[29,752,229],{"class":205},[29,754,755,758],{"class":31,"line":273},[29,756,757],{"class":201},"        elements",[29,759,229],{"class":205},[29,761,762,765,768,770],{"class":31,"line":281},[29,763,764],{"class":205},"          - ",[29,766,767],{"class":201},"env",[29,769,206],{"class":205},[29,771,772],{"class":39},"dev\n",[29,774,775,778,780],{"class":31,"line":292},[29,776,777],{"class":201},"            cluster",[29,779,206],{"class":205},[29,781,782],{"class":39},"https:\u002F\u002Fdev-cluster.example.com\n",[29,784,785,787,789,791],{"class":31,"line":303},[29,786,764],{"class":205},[29,788,767],{"class":201},[29,790,206],{"class":205},[29,792,793],{"class":39},"prod\n",[29,795,796,798,800],{"class":31,"line":314},[29,797,777],{"class":201},[29,799,206],{"class":205},[29,801,355],{"class":39},[29,803,804,807],{"class":31,"line":322},[29,805,806],{"class":201},"  template",[29,808,229],{"class":205},[29,810,811,814],{"class":31,"line":330},[29,812,813],{"class":201},"    metadata",[29,815,229],{"class":205},[29,817,818,821,823],{"class":31,"line":339},[29,819,820],{"class":201},"      name",[29,822,206],{"class":205},[29,824,825],{"class":39},"\"order-api-{{env}}\"\n",[29,827,828,831],{"class":31,"line":347},[29,829,830],{"class":201},"    spec",[29,832,229],{"class":205},[29,834,835,838,840],{"class":31,"line":358},[29,836,837],{"class":201},"      project",[29,839,206],{"class":205},[29,841,270],{"class":39},[29,843,844,847],{"class":31,"line":369},[29,845,846],{"class":201},"      source",[29,848,229],{"class":205},[29,850,851,854,856],{"class":31,"line":377},[29,852,853],{"class":201},"        repoURL",[29,855,206],{"class":205},[29,857,289],{"class":39},[29,859,860,863,865],{"class":31,"line":385},[29,861,862],{"class":201},"        targetRevision",[29,864,206],{"class":205},[29,866,300],{"class":39},[29,868,869,872,874],{"class":31,"line":396},[29,870,871],{"class":201},"        path",[29,873,206],{"class":205},[29,875,311],{"class":39},[29,877,878,881],{"class":31,"line":406},[29,879,880],{"class":201},"        helm",[29,882,229],{"class":205},[29,884,885,888,891,894],{"class":31,"line":414},[29,886,887],{"class":201},"          valueFiles",[29,889,890],{"class":205},": [",[29,892,893],{"class":39},"\"..\u002F..\u002Fenvs\u002F{{env}}\u002Forder-api\u002Fvalues.yaml\"",[29,895,896],{"class":205},"]\n",[29,898,900,903],{"class":31,"line":899},24,[29,901,902],{"class":201},"      destination",[29,904,229],{"class":205},[29,906,908,911,913],{"class":31,"line":907},25,[29,909,910],{"class":201},"        server",[29,912,206],{"class":205},[29,914,915],{"class":39},"\"{{cluster}}\"\n",[29,917,919,922,924],{"class":31,"line":918},26,[29,920,921],{"class":201},"        namespace",[29,923,206],{"class":205},[29,925,366],{"class":39},[15,927,928],{},"新增一個環境，只要在清單中加一筆。",[15,930,931],{},[61,932,933],{},"應用程式原始碼和部署設定分開兩個 Repo",[15,935,936],{},"CI 更新映像版本時會 commit 到部署設定的 Repo。如果兩者放在同一個 Repo，CI 的 commit 又會觸發一次 CI，很容易形成迴圈；權限上，能改程式碼的人也不一定該能改正式環境的設定。",[10,938,940],{"id":939},"使用情境證券系統導入-gitops","使用情境：證券系統導入 GitOps",[15,942,943],{},"在證券系統導入 Argo CD 時，主要想解決的是「正式環境的實際狀態不透明」和「部署權限散落在各個 Pipeline」：",[66,945,946,949,956,962],{},[69,947,948],{},"各服務的 Helm Chart 與各環境的 values 集中在部署 Repo，正式環境的每一次變更都是一個經過審核的 PR",[69,950,951,952,955],{},"CI 只負責建置映像並更新 values 中的 ",[26,953,954],{},"image.tag","，不再持有叢集的管理權限",[69,957,958,959,961],{},"正式環境開啟 ",[26,960,542],{},"，手動調整會被自動修正，避免設定漂移",[69,963,964],{},"搭配 Centralized Pipeline Library，開發人員不需要自己撰寫部署腳本",[10,966,967],{"id":967},"一句話總結",[15,969,970,971,973,974,977,978,980],{},"GitOps 讓 Git 成為叢集期望狀態的唯一真相，CI 只負責產出映像並更新 Git，叢集內的 Argo CD 持續拉取、比對、同步；用 ",[26,972,494],{}," 自動部署、",[26,975,976],{},"prune"," 清掉被刪除的資源、",[26,979,542],{}," 修正手動漂移，再用 Sync Wave 控制部署順序、ApplicationSet 管理多環境，部署、回滾、稽核都回到 Git 上完成。",[982,983,984],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":24,"searchDepth":212,"depth":212,"links":986},[987,988,989,990,991,992,993,994],{"id":12,"depth":212,"text":13},{"id":99,"depth":212,"text":100},{"id":179,"depth":212,"text":180},{"id":457,"depth":212,"text":458},{"id":581,"depth":212,"text":582},{"id":660,"depth":212,"text":661},{"id":939,"depth":212,"text":940},{"id":967,"depth":212,"text":967},"2025-02-17",null,"md",{},true,"\u002Farticles\u002Fargocd-gitops",{"title":5,"description":24},"articles\u002Fargocd-gitops",[105,172,1004,1005,1006,1007],"Kubernetes","Helm","CI\u002FCD","DevOps","RzkH9X8s1ou6pcXdbeKUHly-NDBEkKDwxIUxPqu8PtI",1792959150229]