使用 Helm 將應用程序部署到多個 Kubernetes 集群

Dailymotion 如何使用 Kubernetes:應用程式部署

我們 Dailymotion 三年前開始在生產中使用 Kubernetes。 但跨多個叢集部署應用程式很有趣,因此在過去幾年中我們一直在努力改進我們的工具和工作流程。

從哪裡開始

在這裡,我們將介紹如何在世界各地的多個 Kubernetes 叢集上部署應用程式。

要一次部署多個 Kubernetes 對象,我們使用 ,我們所有的圖表都儲存在一個 git 儲存庫中。 為了從多個服務部署完整的應用程式堆疊,我們使用所謂的摘要圖表。 本質上,這是一個聲明依賴項並允許您使用一個命令初始化 API 及其服務的圖表。

我們還在 Helm 之上編寫了一個小型 Python 腳本來執行檢查、建立圖表、添加機密和部署應用程式。 所有這些任務都是使用 docker 映像在中央 CI 平台上執行的。

讓我們進入正題吧。

筆記。 當您閱讀本文時,Helm 3 的第一個候選版本已經公佈。 主要版本包含大量改進,以解決我們過去遇到的一些問題。

圖表開發工作流程

我們對應用程式使用分支,並決定對圖表應用相同的方法。

  • 分支 開發 用於建立將在開發集群上進行測試的圖表。
  • 當拉取請求提交到 ,他們在分期中被檢查。
  • 最後,我們建立一個拉取請求以將變更提交到分支 產品 並將它們應用到生產中。

每個環境都有自己的私人儲存庫來儲存我們的圖表,我們使用 圖表博物館 具有非常有用的 API。 透過這種方式,我們可以確保在生產中使用圖表之前環境與實際測試之間的嚴格隔離。

不同環境下的圖表儲存庫

值得注意的是,當開發人員將分支推送到 dev 時,他們的圖表版本會自動推送到 dev Chartmuseum。 因此,所有開發人員都使用相同的開發儲存庫,並且您需要仔細指定圖表的版本,以免意外使用其他人的變更。

此外,我們的小 Python 腳本使用 Kubernetes OpenAPI 規範來驗證 Kubernetes 對象 庫貝瓦爾,然後將它們發佈到 Chartmusem 上。

圖表開發工作流程的一般描述

  1. 根據規範設定管道任務 gazr.io 用於品質控制(lint、單元測試)。
  2. 使用部署我們的應用程式的 Python 工具推送 docker 映像。
  3. 透過分支名稱設定環境。
  4. 使用 Kubeval 驗證 Kubernetes yaml 檔案。
  5. 自動增加圖表及其父圖表(依賴正在變更的圖表的圖表)的版本。
  6. 向與其環境相符的圖表博物館提交圖表

管理跨集群的差異

集群聯邦

曾經有一段時間我們使用 Kubernetes 叢集的聯合,其中 Kubernetes 物件可以從單一 API 端點聲明。 但問題出現了。 例如,某些 Kubernetes 物件無法在聯合端點中創建,這使得維護聯合物件和單一叢集的其他物件變得困難。

為了解決這個問題,我們開始獨立管理集群,這大大簡化了流程(我們使用了聯邦的第一個版本;第二個版本中可能發生了一些變化)。

地理分散式平台

我們的平台目前分佈在 6 個區域 - 3 個本地區域和 3 個雲端區域。


分散式部署

全球 Helm 價值觀

4 個全域 Helm 值可讓您識別叢集之間的差異。 我們所有的圖表都有預設最小值。

global:
  cloud: True
  env: staging
  region: us-central1
  clusterName: staging-us-central1

全球價值觀

這些值幫助定義我們的應用程式的上下文,並用於各種目的:監視、追蹤、日誌記錄、進行外部呼叫、擴展等。

  • 「雲端」:我們有一個混合 Kubernetes 平台。 例如,我們的 API 部署在 GCP 區域和我們的資料中心中。
  • “env”:對於非生產環境,某些值可能會發生變化。 例如,資源定義和自動縮放配置。
  • 「region」:此資訊有助於確定叢集的位置,並可用於確定外部服務的附近端點。
  • “clusterName”:如果我們想要為單一叢集定義一個值。

這是一個具體的例子:

{{/* Returns Horizontal Pod Autoscaler replicas for GraphQL*/}}
{{- define "graphql.hpaReplicas" -}}
{{- if eq .Values.global.env "prod" }}
{{- if eq .Values.global.region "europe-west1" }}
minReplicas: 40
{{- else }}
minReplicas: 150
{{- end }}
maxReplicas: 1400
{{- else }}
minReplicas: 4
maxReplicas: 20
{{- end }}
{{- end -}}

頭盔模板範例

此邏輯在幫助程式範本中定義,以避免 Kubernetes YAML 混亂。

申請公告

我們的部署工具是基於多個 YAML 檔案。 以下是我們如何在叢集中聲明服務及其擴展拓撲(副本數量)的範例。

releases:
  - foo.world

foo.world:                # Release name
  services:               # List of dailymotion's apps/projects
    foobar:
      chart_name: foo-foobar
      repo: [email protected]:dailymotion/foobar
      contexts:
        prod-europe-west1:
          deployments:
            - name: foo-bar-baz
              replicas: 18
            - name: another-deployment
              replicas: 3

服務定義

這是定義我們的部署工作流程的所有步驟的概述。 最後一步將應用程式同時部署到多個工作集群。


詹金斯部署步驟

那麼秘密呢?

關於安全性,我們追蹤來自不同地方的所有秘密並將它們儲存在一個獨特的保險庫中 拱頂 在巴黎。

我們的部署工具從 Vault 中提取秘密值,並在部署時間到來時將它們插入 Helm 中。

為此,我們定義了 Vault 中的機密與我們的應用程式所需的機密之間的對應:

secrets:                                                                                                                                                                                                        
     - secret_id: "stack1-app1-password"                                                                                                                                                                                  
       contexts:                                                                                                                                                                                                   
         - name: "default"                                                                                                                                                                                         
           vaultPath: "/kv/dev/stack1/app1/test"                                                                                                                                                               
           vaultKey: "password"                                                                                                                                                                                    
         - name: "cluster1"                                                                                                                                                                           
           vaultPath: "/kv/dev/stack1/app1/test"                                                                                                                                                               
           vaultKey: "password"

  • 我們定義了在 Vault 中記錄機密時要遵循的一般規則。
  • 如果秘密適用 到特定的上下文或集群,您需要新增特定條目。 (這裡上下文 cluster1 有自己的秘密 stack-app1-password 值)。
  • 否則使用該值 默認情況下.
  • 對於此列表中的每一項 庫伯內特的秘密 插入一個鍵值對。 因此,我們圖表中的秘密模板非常簡單。

apiVersion: v1
data:
{{- range $key,$value := .Values.secrets }}
  {{ $key }}: {{ $value | b64enc | quote }}
{{ end }}
kind: Secret
metadata:
  name: "{{ .Chart.Name }}"
  labels:
    chartVersion: "{{ .Chart.Version }}"
    tillerVersion: "{{ .Capabilities.TillerVersion.SemVer }}"
type: Opaque

問題和限制

使用多個儲存庫

現在我們將圖表和應用程式的開發分開。 這意味著開發人員必須在兩個 git 儲存庫中工作:一個用於應用程序,另一個用於定義其到 Kubernetes 的部署。 2 個 git 儲存庫意味著 2 個工作流程,新手很容易感到困惑。

管理通用圖表很麻煩

正如我們已經說過的,通用圖表對於識別依賴關係和快速部署多個應用程式非常有用。 但我們用 --reuse-values以避免每次部署屬於此通用圖表一部分的應用程式時傳遞所有值。

在持續交付工作流程中,我們只有兩個定期變更的值:副本數量和鏡像標籤(版本)。 其他的,更穩定的值是手動改變的,這是相當困難的。 此外,正如我們從自己的經驗中看到的那樣,部署通用圖表時的一個錯誤可能會導致嚴重的失敗。

更新多個設定檔

當開發人員新增應用程式時,他必須更改多個檔案:應用程式聲明、機密清單、將應用程式新增為依賴項(如果該應用程式包含在通用圖表中)。

Vault 中的 Jenkins 權限過於擴展

現在我們有一個 應用角色,它會讀出 Vault 中的所有秘密。

回滾過程不是自動的

要回滾,您需要在多個叢集上執行該命令,這充滿了錯誤。 我們手動執行此操作以確保指定正確的版本 ID。

我們正在邁向 GitOps

我們的目標

我們希望將圖表返回到它部署的應用程式的儲存庫。

工作流程將與開發相同。 例如,當一個分支被推送到master時,會自動觸發部署。 這種方法與目前工作流程的主要差異在於 一切都將在 git 中管理 (應用程式本身及其在 Kubernetes 中的部署方式)。

有幾個優點:

  • 很多 更清晰 對於開發商來說。 了解如何在本機圖表中套用變更會更容易。
  • 可以指定服務部署定義 與程式碼相同的地方 服務。
  • 管理通用圖表的刪除。 該服務將有自己的 Helm 版本。 這將允許您在最小的層級上管理應用程式生命週期(回溯、升級),以免影響其他服務。
  • git 的好處 用於圖表管理:撤銷更改、審核日誌等。如果需要撤銷對圖表的更改,可以使用 git 來執行此操作。 部署自動開始。
  • 您可以考慮使用以下工具來改善您的開發工作流程 斯卡福德,開發人員可以使用它在接近生產的環境中測試變更。

兩步遷移

我們的開發人員已經使用此工作流程兩年了,因此我們希望遷移盡可能輕鬆。 因此,我們決定在實現目標的過程中加入一個中間步驟。
第一階段很簡單:

  • 我們保留類似的結構來設定應用程式部署,但在名為 DailymotionRelease 的單一物件中。

apiVersion: "v1"
kind: "DailymotionRelease"
metadata:
  name: "app1.ns1"
  environment: "dev"
  branch: "mybranch"
spec:
  slack_channel: "#admin"
  chart_name: "app1"
  scaling:
    - context: "dev-us-central1-0"
      replicas:
        - name: "hermes"
          count: 2
    - context: "dev-europe-west1-0"
      replicas:
        - name: "app1-deploy"
          count: 2
  secrets:
    - secret_id: "app1"
      contexts:
        - name: "default"
          vaultPath: "/kv/dev/ns1/app1/test"
          vaultKey: "password"
        - name: "dev-europe-west1-0"
          vaultPath: "/kv/dev/ns1/app1/test"
          vaultKey: "password"

  • 每個應用程式 1 個版本(沒有通用圖表)。
  • 應用程式 git 儲存庫中的圖表。

我們已經與所有開發人員進行了交談,因此遷移過程已經開始。 第一階段仍使用CI平台進行控制。 我很快就會寫另一篇關於第二階段的文章:我們如何遷移到 GitOps 工作流程 。 我將告訴您我們如何設定一切以及我們遇到的困難(多個儲存庫、秘密等)。 關注新聞。

在這裡,我們試圖描述過去幾年我們在應用程式部署工作流程中取得的進展,這引發了人們對 GitOps 方法的思考。 我們還沒有達到目標,將報告結果,但現在我們確信,當我們決定簡化一切並使其更接近開發人員的習慣時,我們做了正確的事情。

來源: www.habr.com

添加評論