本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
Kyma - 轻松扩展和构建 Kubernetes
根据最近完成的CNCF 调查,云原生技术在生产环境中的采用率正在迅速增长。Kubernetes 是这场技术革命的核心。自然,云原生技术的增长也伴随着其生态系统的增长。当然,云原生技术的复杂性也随之增加。只需在谷歌搜索“Kubernetes is hard”这个短语,你就会得到大量文章来解释这个复杂性问题。CNCF 社区最棒的一点是,这样的问题可以通过聪明的开发者构建新工具来赋能 Kubernetes 用户而得到解决:例如,像 Knative 及其Build 资源扩展等项目,旨在降低各种场景的复杂性。尽管增加复杂性似乎是需要解决的最重要问题,但它并不是您在向云原生过渡时面临的唯一挑战。
待解决的问题
选择正确的技术很困难
现在您已经了解了 Kubernetes,您的团队已经接受了培训,并且您已经开始在其上构建应用程序,是时候面对新一层的挑战了。云原生不仅仅意味着部署一个供开发者在其上构建的平台。开发者还需要存储、备份、监控、日志记录和服务网格来对传输中的数据强制执行策略。这些独立的系统中的每一个都必须正确配置和部署,并且需要独立地进行日志记录、监控和备份。CNCF 旨在提供帮助。我们提供了所有云原生技术的概览图,但列表非常庞大,可能会让人不知所措。
这就是 Kyma 让您生活更轻松的地方。它的使命宣言是提供一种灵活简单的方式来扩展应用程序。

该项目旨在为您提供构建端到端、生产级云原生应用程序所需的工具。Kyma 由 SAP 捐赠给开源社区;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 维护的官方服务代理。
您可以观看此视频,通过真实的演示场景简要了解 Kyma 的主要功能。
我们为您选择了正确的技术
只有在妥善监控和配置的情况下,您才能在 Kyma 这样的项目中提供可靠的可扩展性。我们决定不重复造轮子。CNCF 生态系统中有许多优秀的项目,大部分都有庞大的社区支持。我们决定挑选最好的项目,并将它们整合到 Kyma 中。您可以看到与上方相同的架构图,但重点是我们将哪些项目组合在一起创建了 Kyma:

- 监控和警报基于 Prometheus 和 Grafana
- 日志记录基于 Loki
- 事件处理使用 Knative 和 NATS
- 资产管理使用 Minio 作为存储
- 服务网格基于 Istio
- 跟踪使用 Jaeger
- 身份验证由 dex 提供支持
您无需集成这些工具:我们确保它们能很好地协同工作,并且始终保持最新(Kyma 已经在使用 Istio 1.1)。通过我们定制的安装程序和Helm图表,我们实现了 Kyma 的轻松安装和升级到新版本。
不要重写您的单体应用
重写既困难又耗资巨大,并且在大多数情况下是没有必要的。最终,您需要的是能够更快地编写新功能并将其投入生产。您可以通过使用应用程序连接器将您的单体应用连接到 Kyma 来实现这一目标。简而言之,这个组件确保了:
- 您可以安全地回调已注册的单体应用,而无需处理授权问题,因为应用程序连接器会处理这些问题。
- 从您的单体应用发送的事件安全地到达 Kyma 事件总线。
目前,您的单体应用可以消费三种不同类型的服务:用于同步通信的 REST(带有OpenAPI规范)和 OData(带有实体数据模型规范),以及用于异步通信的基于AsyncAPI规范的事件目录。您的事件随后使用带有Knative eventing的NATS 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仪表盘,通过Prometheus和Istio查看我的Lambda指标。

这种方法在添加新功能时为您提供了很大的灵活性。它还让您有时间重新思考重写旧功能的必要性。
贡献和提供反馈
Kyma 是一个开源项目,我们非常乐意帮助它成长。它的发展离不开您的帮助。阅读本文后,您已经知道我们不想重复造轮子。我们在工作模式中坚持这一原则,这使社区贡献者能够参与进来。我们在特殊兴趣小组中工作,并有公开录制的会议,您可以随时加入,因此我们的设置类似于您从 Kubernetes 本身了解到的那种。欢迎通过Twitter或Slack与我们分享您的反馈。