本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kyma - 輕鬆擴充套件和構建 Kubernetes

根據最近完成的CNCF 調查,雲原生技術在生產環境中的採用率正在迅速增長。Kubernetes 是這場技術革命的核心。自然,雲原生技術的增長也伴隨著其生態系統的增長。當然,雲原生技術的複雜性也隨之增加。只需在谷歌搜尋“Kubernetes is hard”這個短語,你就會得到大量文章來解釋這個複雜性問題。CNCF 社群最棒的一點是,這樣的問題可以透過聰明的開發者構建新工具來賦能 Kubernetes 使用者而得到解決:例如,像 Knative 及其Build 資源擴充套件等專案,旨在降低各種場景的複雜性。儘管增加複雜性似乎是需要解決的最重要問題,但它並不是您在向雲原生過渡時面臨的唯一挑戰。

待解決的問題

選擇正確的技術很困難

現在您已經瞭解了 Kubernetes,您的團隊已經接受了培訓,並且您已經開始在其上構建應用程式,是時候面對新一層的挑戰了。雲原生不僅僅意味著部署一個供開發者在其上構建的平臺。開發者還需要儲存、備份、監控、日誌記錄和服務網格來對傳輸中的資料強制執行策略。這些獨立的系統中的每一個都必須正確配置和部署,並且需要獨立地進行日誌記錄、監控和備份。CNCF 旨在提供幫助。我們提供了所有云原生技術的概覽圖,但列表非常龐大,可能會讓人不知所措。

這就是 Kyma 讓您生活更輕鬆的地方。它的使命宣言是提供一種靈活簡單的方式來擴充套件應用程式。

Kyma in center

該專案旨在為您提供構建端到端、生產級雲原生應用程式所需的工具。KymaSAP 捐贈給開源社群;SAP 在編寫生產級雲原生應用程式方面擁有豐富的經驗。這就是我們如此興奮地宣佈 Kyma 的第一個主要版本,Kyma 1.0 釋出的原因!

決定從單體應用轉向雲原生的路徑很困難

嘗試在谷歌搜尋 `monolith to cloud native` 或 `monolith to microservices`,你會得到大量關於如何應對這一挑戰的演講和論文。將單體應用遷移到雲有許多不同的途徑,我們的經驗告訴我們在這個領域應該相當有主見。首先,讓我們回答為什麼要從單體應用轉向雲原生的問題。推動這一轉變的目標通常是:

  • 提高可伸縮性。
  • 更快地實現新功能。
  • 更靈活的可擴充套件性方法。

您無需重寫您的單體應用程式即可實現這些目標。為什麼要花費所有時間重寫已有的功能呢?只需專注於讓您的單體應用程式支援事件驅動架構

Kyma 如何解決您的挑戰?

什麼是 Kyma?

Kyma 執行在 Kubernetes 上,由多個不同的元件組成,其中三個是:

  • 應用程式聯結器,您可以使用它將任何應用程式與 Kubernetes 叢集連線,並透過 Kubernetes 服務目錄暴露其 API 和事件。
  • Serverless 讓您能夠輕鬆為應用程式編寫擴充套件。您的函式程式碼可以由 API 呼叫觸發,也可以由來自外部系統的事件觸發。您還可以從函式中安全地回撥整合系統。
  • 服務目錄旨在暴露整合系統。這種整合還使您能夠使用 Azure、AWS 或 Google Cloud 等超大規模雲服務提供商的服務。Kyma 允許輕鬆整合由 Microsoft 和 Google 維護的官方服務代理。

core components

您可以觀看此影片,透過真實的演示場景簡要了解 Kyma 的主要功能。

我們為您選擇了正確的技術

只有在妥善監控和配置的情況下,您才能在 Kyma 這樣的專案中提供可靠的可擴充套件性。我們決定不重複造輪子。CNCF 生態系統中有許多優秀的專案,大部分都有龐大的社群支援。我們決定挑選最好的專案,並將它們整合到 Kyma 中。您可以看到與上方相同的架構圖,但重點是我們將哪些專案組合在一起建立了 Kyma:

Kyma architecture

您無需整合這些工具:我們確保它們能很好地協同工作,並且始終保持最新(Kyma 已經在使用 Istio 1.1)。透過我們定製的安裝程式Helm圖表,我們實現了 Kyma 的輕鬆安裝和升級到新版本。

不要重寫您的單體應用

重寫既困難又耗資巨大,並且在大多數情況下是沒有必要的。最終,您需要的是能夠更快地編寫新功能並將其投入生產。您可以透過使用應用程式聯結器將您的單體應用連線到 Kyma 來實現這一目標。簡而言之,這個元件確保了:

  • 您可以安全地回撥已註冊的單體應用,而無需處理授權問題,因為應用程式聯結器會處理這些問題。
  • 從您的單體應用傳送的事件安全地到達 Kyma 事件匯流排。

目前,您的單體應用可以消費三種不同型別的服務:用於同步通訊的 REST(帶有OpenAPI規範)和 OData(帶有實體資料模型規範),以及用於非同步通訊的基於AsyncAPI規範的事件目錄。您的事件隨後使用帶有Knative eventingNATS Streaming通道在內部交付。

一旦您的單體服務連線成功,您就可以透過前面提到的服務目錄整合,在選定的名稱空間中配置這些服務。作為開發者,您可以訪問目錄,檢視所有可消費的服務列表。這包括來自您的單體應用程式的服務,以及透過已註冊的服務代理(如Azure 的 OSBA)提供的其他第三方服務。這是一個包含您所需一切的單一場所。如果您想搭建一個新應用程式,所有您需要的東西都已在 Kyma 中可用。

最後是一些程式碼

檢視我為將一個單體應用與 Azure 服務整合而編寫的一些程式碼。我想要了解客戶在產品評論部分表達的情緒。對於每一個包含評論的事件,我想使用機器學習呼叫一個情感分析服務,如果評論是負面的,我希望將其儲存在資料庫中以供後續審查。這是透過我們的Serverless元件建立的函式的程式碼。請注意我的程式碼註釋。

您可以觀看短影片,瞭解情感分析功能的完整演示。

/* It is a function powered by NodeJS runtime so I have to import some necessary dependencies. I choosed Azure's CosmoDB that is a Mongo-like database, so I could use a MongoClient */
const axios = require("axios");
const MongoClient = require('mongodb').MongoClient;

module.exports = { main: async function (event, context) {
    /* My function was triggered because it was subscribed to customer review event. I have access to the payload of the event. */
    let negative = await isNegative(event.data.comment)
    
    if (negative) {
      console.log("Customer sentiment is negative:", event.data)
      await mongoInsert(event.data)
    } else {
      console.log("This positive comment was not saved:", event.data) 
    }
}}

/* Like in case of isNegative function, I focus of usage of the MongoClient API. The necessary information about the database location and an authorization needed to call it is injected into my function and I just need to pick a proper environment variable. */
async function mongoInsert(data) {

    try {
          client = await MongoClient.connect(process.env.connectionString, { useNewUrlParser: true });
          db = client.db('mycommerce');
          const collection = db.collection('comments');
          return await collection.insertOne(data);
    } finally {
      client.close();
    }
}
/* This function calls Azure's Text Analytics service to get information about the sentiment. Notice process.env.textAnalyticsEndpoint and process.env.textAnalyticsKey part. When I wrote this function I didn't have to go to Azure's console to get these details. I had these variables automatically injected into my function thanks to our integration with Service Catalog and our Service Binding Usage controller that pairs the binding with a function. */
async function isNegative(comment) {
    let response = await axios.post(`${process.env.textAnalyticsEndpoint}/sentiment`,
      { documents: [{ id: '1', text: comment }] }, {headers:{ 'Ocp-Apim-Subscription-Key': process.env.textAnalyticsKey }})
    return response.data.documents[0].score < 0.5
}

多虧了Kyma,我無需擔心函數週圍的基礎設施。正如我所提到的,我在Kyma中擁有所有必要的工具,並且它們都已整合在一起。我可以快速透過Loki訪問我的日誌,並且可以快速訪問預配置的Grafana儀表盤,透過PrometheusIstio檢視我的Lambda指標。

Grafana with preconfigured lambda dashboard

這種方法在新增新功能時為您提供了很大的靈活性。它還讓您有時間重新思考重寫舊功能的必要性。

貢獻和提供反饋

Kyma 是一個開源專案,我們非常樂意幫助它成長。它的發展離不開您的幫助。閱讀本文後,您已經知道我們不想重複造輪子。我們在工作模式中堅持這一原則,這使社群貢獻者能夠參與進來。我們在特殊興趣小組中工作,並有公開錄製的會議,您可以隨時加入,因此我們的設定類似於您從 Kubernetes 本身瞭解到的那種。歡迎透過TwitterSlack與我們分享您的反饋。