跳到主要内容

8 篇博文 含有标签「技术管理」

技术管理相关

查看所有标签

智能体(AI Agent):企业该如何实践

· 阅读需 37 分钟

1. 概述

AI Agent 可以翻译为人工智能代理或智能体,下文为了概念一致,统一将 AI Agent 描述为智能体。

提示

Open AI 、Google、Microsoft 还有国内如阿里、百度等一些厂商对智能体定义及智能体各部分组成结构等都有各自的解释,各厂商的概念整体上是相同的,个别地方有细微差别。下文结合 Open AI 和 Google 的定义作说明。

信息

2. 什么是智能体

AI 智能体的核心是大语言模型 (LLM),因此,AI 智能体通常也称为大语言模型智能体。它是能够代表用户独立完成任务的系统(或应用程序),可执行一系列步骤以实现用户目标。它利用大语言模型来管理工作流程的执行并做出决策。它能够识别工作流程何时完成,并且在必要时可以主动纠正自身行为。失败时,它可以暂停执行并将控制权交回给用户。它可以使用各种工具与外部系统进行交互,既可以收集上下文信息,也可以采取行动。并且,它会根据工作流的当前状态动态选择合适的工具,并在明确界定的安全策略保护范围内运行。

例如,组织可能会构建一个费用管理智能体来帮助员工管理费用报销。费用管理智能体可以使用大语言模型与公司支出政策文档相结合来回答员工关于可以报销哪些费用以及有哪些限制的问题。此外,费用管理智能体还可以使用编程函数根据报销金额自动提交定期重复费用(例如每月手机账单),或根据报销金额智能地将费用流转到适当的审批者。

上图显示了以下过程:

  1. 员工向费用管理智能体询问可以报销的费用问题。

  2. 费用管理智能体接受问题并将其作为大语言模型的提示(Prompt)。

  3. 费用管理智能体检索包含公司一系列费用政策等信息的知识库作为提示的依据。

  4. 有依据的提示将提交到费用管理智能体的大语言模型,以生成响应,会在响应中提供相关的政策文档链接。

  5. 费用管理智能体代表用户生成费用单据,并将其提交以进行处理。

在更复杂的情境中,组织可以开发多智能体解决方案,其中多个智能体协调它们之间的协作。 例如,旅行预订智能体可以为员工预订航班和酒店,并自动向费用管理智能体提交带发票的费用单据,如下图所示:

alt text

此图显示了以下过程:

  1. 用户向旅行预订智能体提供即将旅行的详细信息。

  2. 旅行预订智能体自动预订机票和预订酒店。

  3. 旅行预订智能体通过费用智能体为差旅费用发起费用报销。

  4. 费用智能体提交费用报销进行处理。

3. 企业何时需要构建智能体解决方案

一些确定性的解决方案,即传统的工作流引擎或规则引擎就像一个检查表,根据预设条件进行决策。当企业考虑是否需要构建智能体解决方案时,首先要考虑传统的确定性的解决方案是否可以满足,当不能很好的满足需求时,再考虑智能体解决方案。

智能体的核心是大语言模型,大语言模型智能体的工作方式更像一位经验丰富的调查员,评估上下文背景情况,利用推理能力能够有效处理复杂、模糊情况。如涉及以下几项需求,则考虑构建智能体解决方案,

  • 复杂决策:涉及微妙判断、特殊情况或上下文敏感决策的工作流,例如客户服务工作流中的退款审批。

  • 规则难以维护:由于规则集广泛且复杂,导致系统难以管理,更新成本高或容易出错,例如对供应商的一些评估审查。

  • 严重依赖非结构化数据:涉及解读自然语言、从文档中提取含义或与用户进行对话交互的场景,例如处理家庭保险理赔。

4. 智能体的组成

为了理解智能体的内部运作机制,我们可以把驱动智能体行为、行动和决策的基本组成部分描述为一种认知架构,智能体的认知架构中有三个基本组成部分。

  1. 模型

不同的模型在任务复杂性、延迟和成本方面各有优势和权衡。可能需要考虑在工作流程中针对不同任务使用多种模型。并非每个任务都需要最智能的模型,简单的检索或意图分类任务或许可以由更小、更快的模型处理,而像决定是否批准退款这样更棘手的任务,可能会得益于能力更强的模型。

一种行之有效的方法是,为每个任务使用最强大的模型来构建智能体原型,以建立性能基线。从这开始,尝试换用较小的模型,看看它们是否仍能取得可接受的结果。这样,你就不会过早限制智能体的能力,并且可以分析较小的模型在解决特定业务场景时,哪些方面具有优势和劣势。

总之,选择模型的原则很简单:

  • 设置评估以建立性能基线
  • 专注于使用现有的最佳模型来达到你的准确率目标
  • 在可能的情况下,用较小的模型替换较大的模型,以优化成本和响应延迟。
  1. 工具

虽然语言模型在处理信息方面表现出色,但它们缺乏直接感知和影响现实世界的能力。这限制了它们在需要与外部系统或数据进行交互的场景中的应用价值。语言模型的优劣取决于它从训练数据中学到的内容。但无论我们向模型输入多少数据,它们仍然缺乏与外部世界交互的基本能力。

工具是在我们的基础模型与外部世界之间建立联系的桥梁,它使智能体能够与外部数据和服务进行交互。这种与外部系统和数据的联系,使得我们的智能体能够执行更多种类的任务。工具可以是外部函数或应用程序接口,它可以有多种形式,复杂程度也各不相同,但通常与常见的网络 API 方法(如GET、POST、PATCH和DELETE)一致。

工具能够帮助智能体完成多种任务,例如调整智能家居设置、更新日历、按照预设指令发送电子邮件等。此外,智能体还可以利用工具在数据库中更新客户信息,或获取实时天气数据来优化旅行建议。通过工具,智能体得以访问和处理现实世界的信息,这使其能够支持更专业的系统(如检索增强生成 RAG),从而显著扩展基础模型本身的能力。

  1. 编排层

编排层描述了一个循环往复的过程,用于管理智能体如何:

  • 获取信息‌,
  • 进行内部推理‌,
  • 并运用该推理结果来指导其后续行动或决策。

通常,这个循环会持续进行,直到智能体达成目标或到达某个终止节点。编排层的复杂程度差异巨大,具体取决于智能体及其正在执行的任务。有些循环可能只是基于决策规则的简单计算;而另一些循环则可能包含链式逻辑、涉及额外的机器学习算法,或是实现了其他概率推理技术。

5. 智能体如何工作

想象一下,在一个繁忙的厨房里有一位厨师。他的目标是为餐厅顾客制作美味的菜肴,这涉及到一些规划、执行和调整的循环。

  • 他们收集信息,比如顾客的订单以及食品储藏室和冰箱里有哪些食材。

  • 根据刚刚收集到的信息,对可以制作哪些菜肴和风味进行一些内部推理。

  • 采取行动制作菜肴:切菜、调配香料、煎炒。

在这个过程的每个阶段,厨师会根据需要进行调整,随着食材的消耗或收到顾客反馈来完善他们的计划,并利用之前的一系列结果来确定下一个行动计划。这种信息收集、规划、执行和调整的循环,描述了厨师为实现目标所采用的一种独特的认知架构。

就像厨师一样,智能体可以使用认知架构,通过迭代处理信息、做出明智决策,并根据先前的输出优化后续行动,来实现其最终目标。智能体认知架构的核心是编排层,它负责维护记忆、状态、推理和规划。它利用迅速发展的提示工程领域及相关框架来指导推理和规划,使智能体能够更有效地与环境互动并完成任务。针对语言模型的提示工程框架和任务规划领域的研究正在迅速发展,产生了各种有前景的方法。以下是一些最流行的框架和推理技术:

  • ReAct 是一种提示工程框架,它为语言模型提供了一种思维过程策略,使模型能够针对用户查询进行推理并采取行动,无论是否有上下文示例。ReAct 提示已被证明优于多个当前最优(SOTA)基准,并提高了大语言模型(LLMs)与人类的互操作性和可信度。

  • 思维链(Chain-of-Thought,CoT)是一种提示工程框架,它通过中间步骤实现推理能力。思维链有多种子技术,包括自一致性、主动提示和多模态思维链,每种技术根据具体应用都有其优缺点。

  • 思维树(Tree-of-thoughts,ToT)是一种提示工程框架,非常适合探索或前瞻性战略任务。它对思维链提示进行了概括,使模型能够探索各种思维链,这些思维链可作为使用语言模型解决一般问题的中间步骤。

智能体可以利用上述推理技术中的一种,或许多其他技术,为给定的用户请求选择下一个最佳行动。

6. 提升智能体应用的模型能力

企业智能体应用应考虑模型的性能,现实世界的场景往往需要训练数据之外的知识。可以将此想象为基本烹饪技能与精通特定菜系之间的区别。两者都需要烹饪基础知识,但后者需要有针对性的学习,以获得更优秀的成果。

为了帮助模型获取这类特定知识,有几种方法:

  • 上下文学习: 这种方法在推理时为通用模型提供提示、工具和少量示例,使其能够 “即时” 学习如何以及何时针对特定任务使用这些工具。ReAct 框架就是自然语言领域中这种方法的一个示例。

  • 基于检索的上下文学习: 该技术通过从外部存储中检索最相关的信息、工具及相关示例,动态地将其填充到模型提示中。例如,前面提到的基于 RAG 架构的数据存储。

  • 基于微调的学习: 这种方法包括在推理之前使用更大的特定示例数据集对模型进行训练。这有助于模型在收到任何用户查询之前了解何时以及如何应用某些工具。

为了对每种学习方法提供更多了解,让我们回顾一下之前的烹饪类比。

  • 想象一下,一位厨师从顾客那里收到了一份具体的食谱(提示)、几种关键食材(相关工具)以及一些菜品示例(少样本示例)。基于这些有限的信息以及厨师的烹饪常识,他们需要“即兴”想出如何烹制出最符合食谱和顾客喜好的菜肴。这就是上下文学习

  • 现在,让我们想象一下,我们的厨师身处一个储备丰富的厨房,其中有一个满是各种食材和食谱(示例和工具)的食品储藏室(外部数据存储)。此时,厨师能够从食品储藏室中动态选择食材和食谱,从而更好地匹配顾客的菜谱和喜好。这使得厨师能够利用现有知识和新知识,做出更有见地、更精致的菜肴。这就是基于检索的上下文学习

  • 最后,假设我们送厨师回学校学习一种新菜系或一组菜系(在更大的特定示例数据集上进行预训练)。这能让厨师在面对未来从未见过的顾客菜谱时,有更深入的理解。如果我们希望厨师在特定菜系(知识领域)上出类拔萃,这种方法堪称完美。这就是基于微调的学习

这些方法中的每一种在速度、成本和延迟方面都有独特的优点和缺点。然而,通过在智能体框架中结合这些技术,我们可以利用它们的各种优势并将劣势降至最低,从而实现一个更强大、更具适应性的解决方案。

7. 智能体类型

智能体编排可以分为:单智能体系统(Single-agent systems)多智能体系统(Multi-agent systems)

  • 单智能体系统(Single-agent systems),即单个模型配备适当的工具和指令,以循环方式执行工作流程。单个智能体可以通过逐步添加工具来处理多项任务,每一个新工具都能扩展其能力。

一般建议是首先最大化单个智能体的能力。更多的智能体可以直观地对概念进行区分,但也会带来额外的复杂性和开销,因此通常一个配备工具的智能体就足够了。

  • 多智能体系统(Multi-agent systems),即工作流执行分布在多个相互协作的智能体之间。

对于许多复杂的工作流程而言,将提示和工具分散到多个智能体中,有助于提升性能和可扩展性。当智能体无法遵循复杂指令,或持续选择错误工具时,可能需要进一步拆分系统,引入更多不同的智能体。

例如:

  • 复杂逻辑: 当提示词包含大量条件语句(多个 “如果 - 那么 - 否则” 分支 ),且提示模板难以扩展时,可考虑将每个逻辑部分分配给不同智能体。

  • 工具过载: 问题不仅在于工具数量,还在于工具的相似性或重叠性。有些实现能成功管理 15 个以上定义清晰、互不相同的工具,而有些在处理少于 10 个功能重叠的工具时就会遇到困难。如果通过提供描述性名称、清晰参数和详细说明来提高工具清晰度仍无法提升性能,可使用多个智能体。

虽然多智能体系统可以根据特定的工作流程和需求以多种方式进行设计,通常有以下两种编排形式:

  1. 管理器模式或集中管理模式(Manager pattern)(智能体作为工具):一个中央 “管理器” 智能体通过工具调用协调多个专业智能体,每个专业智能体处理特定的任务或领域。

在集中管理模式中,一个中央单元智能体包含全部知识库、连接各个智能体并监督它们的信息。这种结构的优点在于智能体之间易于通信、知识统一。中心化的缺点是依赖中央单元智能体;如果中心单元失效,整个智能体系统也会失效。

  1. 分散式或去中心化模式(Decentralized pattern)(智能体之间任务移交):多个智能体对等运行,根据各自的专业领域相互移交任务。

在上述示例中,初始用户消息被发送到分类智能体。分类智能体识别到输入内容与最近的一次购买有关,便会调用转交给订单管理智能体,并将控制权转移给它。智能体之间可以相互“移交”工作流执行权。它允许一个智能体将任务委托给另一个智能体。同时转移最新的对话状态。 这种模式涉及在平等的基础上使用多个智能体,其中一个智能体可以直接将工作流程的控制权交给另一个智能体。当你不需要单个智能体维持集中控制时,这种模式是最优的,允许每个智能体根据需要接管执行并与用户进行交互。

这种模式在诸如对话分类等场景中特别有效,或者在任何你希望专业智能体完全接管某些任务,而无需原始智能体继续参与的情况下也同样有效。另外,你可以为第二个智能体配备一个交回控制权给原始智能体的功能,以便在必要时再次转移控制权。

分散式智能体与其邻近的智能体共享信息,优点包括稳健性和模块化。由于没有中央单元,当一个智能体失效时,并不会导致整个系统失效。

无论采用何种模式,同样的原则都适用:保持灵活性、可组合性,并由清晰、结构良好的提示(Prompt)驱动。

8. 企业智能体应用示例场景

想象一下,您是一个生产线的维护技术人员,收到了警报信息:其中一台机器停止工作。通常,这些警报以代码的形式出现,例如 IHT 或 PDE 。如果您是一位经验丰富的技术人员,您知道这意味着测量的参数已超出可接受的范围。但是,究竟是哪个参数出了问题呢?具体范围是什么?

如果检查机器时没有发现明显的问题,您就必须仔细阅读数百页的维修手册和文档来诊断问题。通过企业创建的维修顾问智能体应用可以在几秒钟内从企业的手册、过去的维修和文档中检索所有这些信息,并用简单易懂的语言回答您的问题。技术人员可以询问:这台机器以前出现过故障吗?解决方法是什么?维修顾问智能体应用将会检索答案,还可以根据这个工厂中的这台机器的文档和历史记录,为技术人员推荐维修方案。这就是企业应用智能体的优势 — 他们可以从经验中学习,就像人类一样。

维修顾问智能体应用不仅仅是一个知识库。这个智能体可以在相关业务流程的情境中主动工作,并了解 ERP 系统中的数据。它不仅会根据手册和维修历史记录来推荐机器修理方案,还掌握了具体机器的详细信息,可以在 SCM 系统中检查需要更换的零件是否仍在保修期内。这意味着智能体可以推荐更理想的维修解决方案,并帮助您获得替换零件的保修信息,从而节省时间并降低成本。智能体不仅仅是为您提供答案,而是能够结合企业数据、政策和流程,在帮助您做出更智能、更高效的行动的同时提供答案。

9. 如何开发智能体

智能体仍处于早期阶段。随着 AI 背后科技的发展,其底层框架也将不断发展。以下是一些目前流行的 AI 智能体框架。

LangChain

LangChain 是一个开源的用于开发由大语言模型提供支持的应用程序框架。它采用模块化架构,每个模块都封装了使用 LLM 所需的复杂概念和步骤的抽象结构。可以将这些模块化组件串联起来,创建智能体应用程序。LangChain 几乎可以作为所有大语言模型的通用接口。它为向量数据库提供支持,将存储合并到应用程序中,从而保留历史记录和上下文。其 LangSmith 平台组件允许进行调试、测试和性能监控。

LangChain 由 Harrison Chase 于 2022 年 10 月推出,之后迅速脱颖而出,LangChain 是 Github 上增长最快的开源 AI 项目。

LangGraph

LangGraph 是 LangChain 生态系统中的一个平台组件。该框架擅长为多智能体系统编排复杂的工作流。

例如,航空公司可能希望构建一个旅行助手 AI 智能体,以便帮助用户查找和预订航班。使用 LangGraph,每个操作都将表示为节点,并且这些节点可以有多个执行特定任务的智能体。

LlamaIndex

LlamaIndex 是一个领先的框架,它利用大语言模型和工作流程来构建基于LLM的数据智能体。该框架提供 Python 和 TypeScript 两种版本,通过组合各种工具和功能,简化了生成式AI用例的上下文增强流程(RAG)。

CrewAI

CrewAI 是开源的多智能体 AI 解决方案的编排框架。CrewAI 支持与各种大语言模型的连接,该框架还拥有一套检索增强生成 (RAG) 工具来搜索不同的数据源。

AutoGen

AutoGen (github) 是 Microsoft 推出的开源框架,用于创建多智能体 AI 应用程序来执行复杂任务。

AutoGen 还提供了两种方便的开发人员工具:用于评估智能体型 AI 性能和执行基准测试的 AutoGen Bench,以及用于开发智能体的无代码界面的 AutoGen Studio。

Semantic Kernel

Semantic Kernel (github )是 Microsoft 提供的一个轻量级的开源开发工具包,可让您轻松构建人工智能代理,并将最新的人工智能模型集成到您的 C#、Python 或 Java 代码库中。它是一个高效的中间件,能够快速交付企业级解决方案。

Dify

Dify 是一个开源的大语言模型应用开发平台。提供从 Agent 构建到 AI workflow 编排、RAG 检索、模型管理等能力,轻松构建和运营生成式 AI 应用。Dify 可以为开发人员节省大量时间,使他们能够专注于业务需求,快速构建生产级的生成式 AI 应用。Dify 这个名字来自 Define + Modify,指的是定义并不断改进我们的 AI 应用程序。

10. 选择智能体开发框架时需考虑的因素

在深入智能体领域之前,请先考虑一下您所在组织的目标和任务场景。理想的框架可在您的技术能力、短期需求和长期目标之间取得平衡。

以下是选择智能体框架时需要考虑的几个方面:

  • 复杂性

确定您希望智能体完成的任务以及这些任务的复杂程度。确定您是需要仅包含单个智能体的简单实施,还是需要多智能体生态系统。对于多智能体环境,规划出所需的智能体交互以及仍然需要人工干预的地方。

例如,在客户支持领域,单个智能体即可帮助对所遇问题的严重程度进行分类。但是,如果您想要高效率的工作流,请考虑创建一个具有不同功能智能体的多智能体系统,以便解决问题、提出修复建议并将复杂的案例分配给其他智能体。

  • 数据隐私和安全

选择智能体框架时,数据隐私和安全必须是首要考虑因素。验证您选择的框架的安全策略和措施,包括静态和传输中数据的加密、访问控制和删除任何敏感信息。

  • 使用便捷

考虑开发团队的技能水平。例如,Dify、CrewAI 等适合初学者的 AI 框架具有用于快速原型设计的无代码界面和用于快速部署的现成的 AI 智能体模板。更有经验的 AI 开发人员可能会使用高级智能体框架,例如 LangGraph,它提供低级别控制和可定制的代码选项。

  • 无缝集成

根据智能体框架与现有技术栈的兼容性来对其进行评估。检查您选择的框架与当前数据源、基础设施和工具的集成程度。了解如何将智能体部署到您的环境中(无论是本地还是云)以及是需要小规模还是大规模的部署。

  • 性能和可扩展性

评估所选智能体框架的性能。考虑实时应用程序的响应时间或延迟,并评估在处理大量数据或多个并发请求时性能是否会下降。虽然重点可能放在短期上,但也要考虑框架如何随着业务的增长而扩展。

11.企业开发智能体应用的实施步骤

开发智能体的实施步骤与其他任何 AI 部署相似。首先,您需要定义任务:您希望智能体做些什么,并尽可能具体地列出目标和目的。然后,确定智能体在工作中需要遵循的功能流程、需要访问的数据、可以访问的工具和其它智能体。

建议企业先从小范围的测试开始,密切监视使用情况和结果,并根据结果优化智能体,然后在成功的基础上提高智能体的自主性。

举个例子,某零售商需要开发一个需求预测智能体,帮助其为学生的开学季做好规划。

  1. 定义业务目标: 该智能体的任务是预测产品需求,包括背包、笔记本和儿童服装。

  2. 确定所需数据: 整理数据源,至少需要相关产品的历史销售数据;有关当前市场趋势和经济指标的信息;以及客户人口统计和购买历史。企业可以纳入可能影响需求的季节性趋势数据,例如气温可能高于正常水平,以及成功促销、折扣和营销活动的历史详情,这可能有助于提高准确性。

  3. 外部工具: 将智能体与库存管理、ERP及供应链计划等系统集成,可显著提升业务处理的准确性和效率。此外,建议联合相关产品线的业务专家,通过其经验建议指导智能体开发中的工具选型与决策制定。

  4. 提供反馈: 定期评估和调优是一项前期投资,但事实证明这些投资往往都是值得的。企业可以收集客户和专家反馈,确定需要改进的地方。

  5. 配置足够的资源: 最后一点,需要有足够的计算资源来运行智能体。

12. 参考资料

[1] OpenAI 白皮书《A Practical Guide To Building Agents》 下载 PDF
[2] Google 白皮书《Agents》 下载 PDF
[3] Google 白皮书《Agents Companion》 下载 PDF
[4] LangChain
[5] LangGraph
[6] LlamaIndex
[7] CrewAI
[8] AutoGen
[9] AutoGen Github
[10] Semantic Kernel
[11] Semantic Kernel Github
[12] Dify 官网
[13] Dify Github

开源免费的生成式人工智能(Generative AI)课程

· 阅读需 6 分钟

1. 概述

生成式人工智能(Generative AI)无疑是目前最为火爆的计算机领域前沿技术。下面列出一些免费开放课程,适用于人工智能领域的初学者或想提高相关技能的专业人士。

提示

下面课程的链接,有些是需要外网特殊访问,如没有网络环境可以看国内哔哩哔哩等视频网站平台上的其他人的搬运。

2. 微软、谷歌、亚马逊等公司的开源免费生成式 AI 课程

2.1 面向初学者的生成式人工智能课程(微软)

微软的开源免费课程项目目前有 21 节,面向生成式人工智能初学者,每节课都有一个主题,可以从任意主题开始。课程分为学习(Learn)课程和构建(Build)课程。学习课程解释概念,构建课程除了解释概念外还包括用 Python 和 TypeScript 实现的代码示例(支持 Azure OpenAI 和 OpenAI API )。

课程链接:Generative AI for Beginners (Version 3)

2.2 面向初学者的 AI 代理 (微软)

本课程有11节课,涵盖了构建AI代理的基础知识。每节课都涵盖了自己的主题。

课程链接:AI Agents for Beginners

2.3 生成式人工智能学习路径(谷歌)

此学习路线概要介绍了生成式 AI 的概念,包括大语言模型的基础知识和负责任人工智能(Responsible AI) 原则等。一共五个视频。

课程链接:Google Cloud Skills Boost

2.4 适用于所有人的生成式 AI(Deeplearning.AI )

由人工智能先驱吴恩达(Andrew Ng)讲授的 Generative AI for Everyone 以他独特的视角,为你和你的工作提供人工智能生成技术。将引导你了解生成式人工智能的工作原理以及它能做什么(不能做什么)。你将深入了解生成式人工智能的功能、潜力和局限。你将深入了解现实世界中的应用并学习常见的使用案例。你将亲身参与生成式人工智能项目,将所学知识付诸行动,深入了解其对商业和社会的影响。

本课程旨在确保每个人都能成为人工智能推动的未来的参与者。

课程链接:适用于所有人的生成式 AI

2.5 采用大型语言模型的生成式人工智能(亚马逊)

这是一门中级课程,因此你应该有一定的 Python 编程经验,这样才能学有所获。你还应该熟悉机器学习的基础知识,如监督和非监督学习、损失函数以及将数据分成训练集、验证集和测试集。如果你已经学习了 DeepLearning.AI 的机器学习专业课程或深度学习专业课程,那么你就可以学习本课程,深入学习生成式人工智能的基础知识。

通过学习本课程,将学会

  • 深入理解生成式人工智能,描述基于 LLM 的典型生成式人工智能生命周期中的关键步骤,从数据收集和模型选择到性能评估和部署
  • 详细描述为 LLM 提供动力的转换器架构、如何训练 LLM 以及如何微调 LLM 以适应各种特定用例
  • 使用经验缩放法则,在数据集大小、计算预算和推理要求之间优化模型的目标函数
  • 应用最先进的训练、调整、推理、工具和方法
  • 使用最先进的训练、调整、推理和工具、听完行业研究人员和从业人员的故事后,讨论生成式人工智能为企业带来的挑战和机遇
  • 对 LLM 如何工作以及训练和部署 LLM 背后的最佳实践有了良好基础了解的开发人员,将能够为他们的公司做出正确的决策,并更快地构建工作原型。

课程链接: Generative AI with Large Language Models

2.6 Introduction to Generative AI 2024 Spring(李宏毅公开课 台湾大学)

课程链接:Introduction to Generative AI 2024 Spring

用 Dify 构建一个简单的大语言模型(LLM)驱动的应用程序

· 阅读需 11 分钟

1. 概述

Dify 是一个开源的大语言模型(LLM)应用开发平台。提供从 Agent 构建到 AI workflow 编排、RAG 检索、模型管理等能力,轻松构建和运营生成式 AI 应用。

Dify 可以为开发人员节省大量时间,使他们能够专注于业务需求,快速构建生产级的生成式 AI 应用。

Dify 这个名字来自 Define + Modify,指的是定义并不断改进我们的 AI 应用程序。

本文旨在初步探索了解 Dify 可以做到哪些事情,以及什么样的业务需求可以由 Dify 来帮助我们去完成。

2. 假设的一个业务场景

北京市公共数据开放平台 是一个面向公众的政府数据平台。这些数据(见下图)与我们生产生活密切相关,它们是以文件或接口形式对外开放。信息种类和数量庞杂,要想了解某一类信息,需要通过接口获得数据,再对数据进行加工处理。

open-data

例如:北京市统计局提供的农林牧渔业总产值,见下图

excel-data

可以利用 Dify 创建 AI 交互应用,自动获得我们要的数据,并利用 LLM 来帮助我们理解分析数据。

3. 最终实现的功能

创建一个 ChatFlow 应用,当启动时,可以有两个查询选项。(见下面视频演示)

分别是:

  • 北京市农林牧渔业总产值-表格
  • 北京市农林牧渔业总产值-柱状图

在这个例子中 LLM 的作用是将 API 接口调用获得的数据进行抽取,因为接口返回的数据集中既包括北京市的总体数据也包括了各个区的数据。

我们的业务需求是:

  • 当查询 北京市农林牧渔业总产值-表格 时,只要北京市的历年农林牧渔业的总产值和分项产值,各个区的历年数据是不需要的。
  • 当查询 北京市农林牧渔业总产值-柱状图 时,只要北京市的历年农林牧渔业的总产值,各个区的总产值和各分项产值是不需要的。

北京市农林牧渔业总产值 Excel 文件。Download

当查询 北京市农林牧渔业总产值-表格 时,结果如下图。

app-done1

当查询 北京市农林牧渔业总产值-柱状图 时,结果如下图。

app-done2

4. 准备 Dify 测试环境

测试环境为华为云服务器 Ubuntu 22.04 server 64bit(2核 4G内存)配置安全组入规则,允许 80 端口。安装 Docker 和 Docker Compose(v2)

从项目库下载社区 Release 版 https://github.com/langgenius/dify 解压上传到 Ubuntu 服务器上

# 进入 Dify 源代码的 Docker 目录
cd dify/docker

# 复制环境配置文件
cp .env.example .env

# 启动 Docker 容器
docker compose up -d

第一次访问 http://服务器IP地址 需要设置管理员邮箱和密码。

5. 准备后端数据服务接口

为了简单和方便测试,这里没有使用北京市公共数据开放平台,而是使用了一个模拟的后端接口。

使用了一个开源的项目 JSON-Server,并将 json-server 在 docker 环境中运行。

首先,创建一个 Dockerfile 文件,并拷贝下面内容。

FROM node:latest

RUN npm install -g json-server

WORKDIR /data
VOLUME /data

EXPOSE 80
ADD run.sh /run.sh
ENTRYPOINT ["bash", "/run.sh"]
CMD []

创建一个 run.sh 文件,并拷贝下面内容。

#!/bin/bash

args="$@"

args="$@ -p 80"

file=/data/db.json
if [ -f $file ]; then
echo "Found db.json, trying to open"
args="$args db.json"
fi

file=/data/file.js
if [ -f $file ]; then
echo "Found file.js seed file, trying to open"
args="$args file.js"
fi

json-server $args

这个 db.json 文件包含我们的测试数据 Download

在 Ubuntu 服务器的 home 目录下创建 docker-json-server 目录,将三个文件 Dockerfile , run.sh , db.config 上传到这个目录下,如下图所示。

json-server

进入到这个目录下执行下面命令,构建 json-server 的 docker 镜像。


docker build -t docker-json-server .

执行下面命令,启动 json-server docker 运行时,这里使用 8081 端口。需要打开云服务器的安全组规则,允许 8081 的访问。

docker run -d --name docker-json-server -p 8081:80 -v /home/docker-json-server/db.json:/data/db.json --restart=always docker-json-server 

打开浏览器访问 http://服务器IP:8081/data 可以看到数据,表示我们后端服务模拟的数据接口可以使用了。

json-server-api

6. 在 Dify 中接入 DeepSeek

这里使用 DeepSeek 作为模型供应商接入 Dify ,需要申请 API key,打开 DeepSeek API 开放平台,创建 API Key

如下图所示:

deepseek-apikey

进入 Dify 界面,点击设置,如下图

setting

在模型供应商中搜索并安装深度求索,设置刚才创建的 API key,如下图所示。

install-apikey

DeepSeek 模型使用价格,参见 价格详情

如果选择本地自建模型,可以选择 Ollama 。它是开源工具,专为无缝部署大语言模型(LLM)而设计。

可参考在 Dify 接入 Ollama 部署的本地模型

7. 在 Dify 中创建应用

打开 http://服务器IP 登录到 Dify 后,在主页中,点击创建空白应用。选择 Chatflow ,输入应用名称 北京市数据开放平台查询

create-app

下图是创建完成的所有流程节点。

app-done

下面依次介绍各个节点。

首先,要设置两个开场问题选项,如下图所示。

start

条件分支节点

ifelse

两个 API 请求节点,两个节点调用 API 地址一样。

api-call

条件分支下的回复节点

other-else

LLM 节点,将调用 API 获得的数据抽取出北京市的各项产值,并要求表格输出。

LLM

LLM 后面的回复节点。

LLM-ansower

参数提取器节点,将调用 API 获得的数据抽取出北京市的历年农林牧渔业总产值,构造用于画柱形图的数据。

params

代码节点,用于生成柱形图

code

完整 javascript 代码段如下:

function main({xData,yData}) {

let option = {
title: {
text: '农林牧渔业总产值(万元)',
left: 'center',
textStyle: {
color: '#1890ff',
fontSize: 14
}
},
xAxis: {
type: 'category',
data: xData.split(',').map(Number)
},
yAxis: {
type: 'value'
},
series: [
{
data: yData.split(',').map(Number),
type: 'bar',
smooth: false
}
]
};

let output = "```echarts\n" + JSON.stringify(option) + "\n```"

return {
result:output
}

}

代码节点后的回复节点

code-ansower

8. 测试应用

当查询 北京市农林牧渔业总产值-表格 时,只显示北京市的历年农林牧渔业的总产值和分项产值,各个区的历年数据不在输出结果中。

app-done1

  • 当查询 北京市农林牧渔业总产值-柱状图 时,只显示北京市的历年农林牧渔业的总产值柱状图,各个区的总产值和各分项产值不体现在柱状图中。

app-done2

9. 其它

本文仅简单演示了 Dify 的一些基础功能,Dify 还有一些其它的能力。

  • 工作流中的代码节点仅适用于逻辑简单的情况。如果要实现更复杂的业务可以开发自定义的插件。
  • 通过创建自定义的工作流并转换成工具组件,也可以实现处理流程逻辑的复用。
  • 通过创建基于业务的知识库,可以结合信息检索和大语言模型(LLM)的生成能力,即 RAG (Retrieval-Augmented Generation 检索增强生成)能力。建立一个业务知识库适用于智能客服(基于企业文档问答)和医疗/法律问答(基于专业知识数据库)等场景应用。

10. 参考资料

[1] Dify 官网
[2] Dify Github
[3] 北京市公共数据开放平台
[4] 北京市公共数据开放平台-农林牧渔业总产值
[5] JSON-Server
[6] DeepSeek API 开放平台
[7] DeepSeek 价格详情
[9] Ollama
[10] 接入 Ollama 部署的本地模型

搭建 Kubernetes (v1.32) + Istio (v1.24.2) 开发测试环境

· 阅读需 28 分钟
提示

此文档内容最后更新于 2025-02-12

1. 概述

快速建立一个用于开发测试的 k8s 集群有很多种方法,包括:minikube、kubeadm、Docker desktop、kind、MicroK8s 等,另外也可以使用阿里云或华为云等云计算厂商提供的产品服务。如果仅是用于日常开发测试使用,考虑成本和简单方便还是应考虑自建测试集群环境。

同时还需要考虑:

  • 资源占用小
  • 环境可迁移
  • 团队之间可方便分享
  • 单节点和多节点可方便扩展

综合上述的几项关注点,使用 Kubeadm 进行开发测试环境的搭建是比较好的选择。本文将在操作系统 Windows 10 家庭版上从零开始一步一步进行搭建。

2. 最后搭建完的环境和配置项

分类描述
主机操作系统
  • Windows 10 家庭版
  • 版本号 22H2
新建 NAT 网络
  • 名称:NATNetwork
  • 网络地址范围:10.10.0.0/16
网络适配器
  • 名称:vEnthernet(nat-switch)
  • IP:10.10.0.254
  • 子网掩码:255.255.0.0
(可选)SSH 客户端工具 MobaXterm MobaXterm Home Edition v25.0 (Portable edition)
下载 MobaXterm_Portable_v25.0.zip
(可选)命令行终端工具 Windows TerminalWindows Terminal
下载 Windows Terminal
虚拟机Hyper-V 配置
  • 虚拟机名称:k8s-dev
  • iso:ubuntu-24.04.1-live-server-amd64.iso
  • 虚拟机代数:第二代
  • vCPU:2
  • RAM:使用静态固定内存 4096MB
  • 检查点:不使用自动检查点(默认使用标准检查点)
  • 网络适配器:nat-switch
  • 存储:200GB 动态扩展
  • 安全:启用安全启动,Microsoft UEFI 证书颁发机构
操作系统Ubuntu Server 24.04.1 LTS 最小化安装
下载 ubuntu-24.04.1-live-server-amd64.iso
操作系统安装配置
  • 在安装步骤中,选中了 Install OpenSSH server 以便允许通过 ssh 远程访问。
  • Server Name: k8s-dev loginname: administrator password: P@22w0rd
网络配置
  • IP 10.10.0.100
  • 子网掩码 255.255.0.0
  • 网关 10.10.0.254
  • DNS 223.5.5.5 和 223.6.6.6
其它设置
  • 配置阿里云 Ubuntu 源
  • 安装 vim 和 ping 工具

K8s & istio

名称版本Release date备注
containerd 运行时containerd 2.0.22025-01-14下载 containerd-2.0.2-linux-amd64.tar.gz
containerd.service下载 containerd.service
runc v1.2.42025-01-07下载 runc.amd64
(可选)nerdctl v2.0.32025-01-21下载 nerdctl-2.0.3-linux-amd64.tar.gz
Kubernetesv1.32.02024-12-12
cilium-cliv0.16.242025-01-30下载 cilium-linux-amd64.tar.gz
cilium1.17.02025-02-04
istio1.24.22024-12-19下载 istio-1.24.2-linux-amd64.tar.gz
提示

因为有一些资源在外网,你需要有一个稳定的网络环境,如果在安装过程中遇到困难,比如外网域名无法访问或镜像资源无法拉取的问题,可以与我联系。

3. 主机环境准备

3.1 安装 Hyper-V

这里虚拟机使用 Microsoft Hyper-V,在微软的官方 Hyper-V 安装指南 Install Hyper-V 中给出的安装需求如下:

  • Windows 10 (Pro or Enterprise), or Windows 11 (Pro or Enterprise)
  • 64-bit Processor with Second Level Address Translation (SLAT).
  • CPU support for VM Monitor Mode Extension (VT-c on Intel CPUs).
  • Minimum of 4 GB memory.
  • Note:The Hyper-V role can't be installed on Windows 10 Home or Windows 11 Home.

如果你的操作系统是专业版或企业版,可以按照微软官方安装指南中的方法进行安装,如果是家庭版,官方给出的说法是不能安装,实际上也是可以装的,并且功能也都是完全可用,但需要特殊的方式。因为我们大多数笔记本安装的操作系统都是家庭版,下面是家庭版安装 Hyper-V 的方法,这个方法同样适用于 Windows 10 和 Windows 11 家庭版。

  1. 打开 Windows 记事本,粘贴下面内容到记事本中,并保存到磁盘目录下,保存的文件名为:hv.bat,如下图片所示。
pushd "%~dp0"
dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hv.txt
for /f %%i in ('findstr /i . hv.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i"
del hv.txt
Dism /online /enable-feature /featurename:Microsoft-Hyper-V -All /LimitAccess /ALL
pause

hv-bat

  1. 右键点击这个 hv.bat 文件,选择以管理员身份运行

hv-bat-run

  1. 等待运行完成重启操作系统后,Hyper-V 将自动安装。可以在应用中找到 Hyper-V 管理器

hyper-v-installed

  1. 如果在上一步的应用中没有找到 Hyper-V 管理器,可以按下面步骤操作,打开控制面板,点击启用或关闭 windows 功能。勾选Hyper-V,并确定。

control-panel

windows-features

3.2 (可选)安装 Windows Terminal 命令行终端工具

可参考官方文档 安装并开始设置 Windows 终端 。此步骤可选,也可使用 Windows 操作系统自带的 Wiondows PowerShell 工具代替。

下载 Windows Terminal

3.2 创建 NAT 网络

我们要在 Hyper-V 中创建 Ubuntu Server 作为 k8s 集群节点。并且我们希望的网络具有下面的几项特性:

  • 虚拟机之间、虚拟机与宿主机之间可以网络互通。
  • 虚拟机要能访问外网,
  • 在需要时,可以增加多个 k8s 虚拟机节点。为了方便对节点进行管理,虚拟机要配置成静态IP。

Hyper-V 安装完成后会有一个默认虚拟交换机(默认的名称为:Default Switch),这个默认的虚拟交换机将自动使用 NAT 网络地址转换向虚拟机提供计算机网络的访问权限。并且此默认虚拟交换机提供 DHCP 和 DNS功能,虚拟机够通过 DHCP 可获得 IP。

这个默认虚拟交换机对应的网络适配器的 IP 地址是操作系统自动分配的(可能是 172.XXX.XXX.XXX),它有操作系统本地冲突检测机制,是操作系统从一个 IP 地址范围中自动选择一个 IP 来进行分配,并将此地址用作连接到它上的虚拟机的 DHCP、默认网关和 DNS 服务器。

另外,这个默认虚拟交换机 Default Switch 不能删除或管理 DHCP,意味着使用这个虚拟交换机的虚拟机不能配置静态IP地址。

基于上面的信息,我们需要的是可以指定静态IP,因此不能使用这个 Default Switch ,需要创建一个自定义的虚拟交换机,使虚拟机可以访问外部网络,并使用自己分配的 IP 地址,而不是通过 DHCP 获得 IP 地址。

例如用 10.10.0.0/16 作为虚拟机也就是 k8s 集群节点的 IP 地址范围,可以做如下分配:

  • k8s-master-1 10.10.0.1
  • k8s-master-2 10.10.0.2
  • k8s-master-3 10.10.0.3
  • k8s-node-1 10.10.0.4
  • k8s-node-2 10.10.0.5

我们需要先创建一个 NAT 网络,也可以参考官网文档 设置 NAT 网络 进行操作。

危险

注意:由于 Windows 仅支持一个内部 NAT 子网前缀,所以不能创建多个 NAT ,请确保你只有一个 NAT。

可以查询是否已经创建过 NAT。以管理员身份运行 Windows Terminal 命令行工具。

# 查看当前 NAT 网络
Get-NetNat

# 如果存在,可以选择删除存在的 NAT 网络, -Name 参数指定要移除的 NAT 网络名称
# Remove-NetNat -Name [your nat name]

下面命令创建一个名为 NATNetwork 的 NAT 网络,并将网络地址范围设置为 10.10.0.0/16。


# 创建 NAT 网络,名称为 NATNetwork,网络地址为 10.10.0.0/16
New-NetNat -Name NATNetwork -InternalIPInterfaceAddressPrefix 10.10.0.0/16

3.3 创建 Hyper-V 虚拟交换机

可以通过图形界面或命令行创建虚拟交换机并配置网络适配器,下面是用命令行操作方法。

  • 名称:nat-switch
  • IP:10.10.0.254
  • 子网掩码:255.255.0.0
# 创建虚拟交换机 "nat-switch"
New-VMSwitch -SwitchName "nat-switch" -SwitchType Internal

# 记录 "nat-switch" 的 ifIndex 值
Get-NetAdapter

# 设置 "nat-switch" 的 IP 地址为 10.0.0.254
New-NetIPAddress -InterfaceIndex [上面的ifIndex] –IPAddress 10.10.0.254 -PrefixLength 16

上面第一行命令执行后将在 Hyper-V 中创建一个 nat-switch 虚拟交换机,并在网络连接中生成一个网络适配器 vEthernet (nat-switch) 如下图所示:

nat-switch

上面第二行和第三行命令将配置新生成的网络适配器 vEthernet (nat-switch) IP地址和子网掩码,如下图所示。

nat-switch-ip

3.4 (可选)安装 SSH 客户端工具 MobaXterm

可以使用任意 SSH 工具连接虚拟机,这里使用 MobaXterm Home Edition (Portable edition)

Home 版是一个免费工具,安装方法参见官网 MobaXterm 官网

下载 MobaXterm_Portable_v25.0.zip

4. 创建 Ubuntu 虚拟机

4.1 下载安装文件

下载 ubuntu-24.04.1-live-server-amd64.iso

4.2 创建虚拟机

Hyper-V 配置如下:

  • 虚拟机名称:k8s-dev
  • iso:ubuntu-24.04.1-live-server-amd64.iso
  • 虚拟机代数:第二代
  • vCPU:2
  • RAM:使用静态固定内存 4096MB
  • 检查点:不使用自动检查点(默认使用标准检查点)
  • 网络适配器:nat-switch
  • 存储:200GB 动态扩展
  • 安全:启用安全启动,Microsoft UEFI 证书颁发机构
提示

k8s 安装需要至少 2cpu 和 2G 内存。考虑后面需要安装 istio 的 Kiali 仪表板、以及 Prometheus、Grafana、Jaeger 等组件,因此这里为虚拟机分配了 4G 内存。

可以通过图形界面创建 Hyper-V 虚拟机,也可通过命令行的方式创建。下面以命令行的方式创建虚拟机。

以管理员身份运行 Windows Terminal 命令行工具。复制下面的内容并粘贴到命令行窗口。

这里假设虚拟机创建在 D:\Hyper-V 目录下,ubuntu-24.04.1-live-server-amd64.iso 文件保存在 D:\ 根目录下。


$vmName = 'k8s-dev'
$vmPath = 'D:\Hyper-V'
$vmSwitch = 'nat-switch'
$ubuntuISO = 'D:\ubuntu-24.04.1-live-server-amd64.iso'

New-VM -Name $vmName -Path $vmPath -Generation 2

Set-VM -VMName $vmName -ProcessorCount 2 -MemoryStartupBytes 4096MB -StaticMemory -AutomaticCheckpointsEnabled $false

New-VHD -Path "$($vmPath)\$($vmName)\Virtual Hard Disks\$($vmName).vhdx" -SizeBytes 200GB -Dynamic

Add-VMHardDiskDrive -VMName $vmName -Path "$($vmPath)\$($vmName)\Virtual Hard Disks\$($vmName).vhdx"

Add-VMDvdDrive -VMName $vmName -Path $ubuntuISO

Set-VMFirmware $vmName -FirstBootDevice $(Get-VMDvdDrive -VMName $vmName) -EnableSecureBoot on -SecureBootTemplate MicrosoftUEFICertificateAuthority

Get-VMSwitch $vmSwitch | Connect-VMNetworkAdapter -VMName $vmName

4.2 安装 Ubuntu

Ubuntu 安装设置如下:

  • OS Version:Ubuntu Server 24.04.1 LTS
  • 操作系统安装选项:
    • 安装 Ubuntu Server (minimized),在安装步骤中,选中了 Install OpenSSH server 以便允许通过 ssh 远程访问。
    • Server Name: k8s-dev
    • loginname: administrator
    • password: P@22w0rd
  1. 启动虚拟机开始安装

ubuntu-1

  1. 选择安装程序语言,通常选择「English」

ubuntu-2

  1. 设置键盘布局,默认「English US」即可

ubuntu-3

  1. 选择安装类型,这里选择 Ubuntu Server (minimized)
  • Ubuntu Server:这是默认选项,包含了服务器操作系统所需的基本软件包。
  • Ubuntu Server (minimized):精简版本,只包含最小的运行时操作系统,适合高级用户自定义配置。

ubuntu-4

  1. 配置网络连接,这里先不配置

ubuntu-5

  1. 设置代理

如果服务器需要通过代理来访问 Internet,填写代理服务器信息。否则,直接留空并按 「回车」键继续。 ubuntu-6

  1. 设置 Ubuntu 镜像源,这里不指定镜像,待安装完成后配置

ubuntu-7

  1. 磁盘分区

ubuntu-8-1

总磁盘是200G,这里 ubuntu-lv(LV) 只使用了 98.472G 并没有使用整个 ubuntu-vg(VG)的空间。只要简单的把 LV 的空间进行调整,即可使用全部 VG 的 196.945G 空间了,选中 ubunt-lv ,按回车,在右侧菜单中选择 Edit 回车。

ubuntu-8-2

在出现的 LV 编辑界面中,将 Size 填写到最大值 196.945G,或直接删除 Size 里的值 Save 即可,此时系统会自动使用最大值空间。

ubuntu-8-3 ubuntu-8-4 ubuntu-8-5

  1. 设置 Ubuntu 主机名和用户信息
  • Your name:administrator
  • Your Servers Name:k8s-dev
  • Pick a username:administrator
  • Password:P@22w0rd

ubuntu-9

  1. Ubuntu Pro 这里默认跳过

ubuntu-10-1

ubuntu-10-2

  1. Install OpenSSH server

勾选「Install OpenSSH Server」安装 OpenSSH 服务器,方便以后远程访问。

ubuntu-11

  1. 安装系统并重启

ubuntu-12

4.3 配置虚拟机网络

Ubuntu Server (minimized) 安装类型,默认没有 vi 或 vim 编辑工具,需要使用 cat 编辑网络配置文件。

网络配置文件是 /etc/netplan/00-installer-config.yaml

网络配置如下:

  • IP 10.10.0.100
  • 子网掩码 255.255.0.0
  • 网关 10.10.0.254
  • DNS 223.5.5.5 和 223.6.6.6
提示

其中 223.5.5.5 和 223.6.6.6 是阿里云的公共DNS,参见 https://alidns.com/

在 Hyper-V 中启动虚拟机,键入下面内容。


# 备份原配置文件
sudo cp /etc/netplan/50-cloud-init.yaml /etc/netplan/50-cloud-init.yaml.bak

sudo cat << EOF | sudo tee /etc/netplan/50-cloud-init.yaml
network:
version: 2
ethernets:
eth0:
addresses:
- 10.10.0.100/16
routes:
- to: default
via: 10.10.0.254
nameservers:
addresses: [223.5.5.5,223.6.6.6]
EOF

执行下面命令使配置生效


# 使配置生效
sudo netplan apply

# 查看网卡配置
ip addr show

4.4 配置 Ubuntu 源

在上一步进行网络配置后,可以在主机使用 MobaXterm 客户端工具连接到 Ubuntu 虚拟机

连接信息如下:

  • IP:10.10.0.100
  • 用户名:administrator
  • 密码:P@22w0rd

MobaXterm

可以配置任一个国内镜像源,例如:

提示

Ubuntu 镜像源配置文件 Ubuntu 22.04 是 /etc/apt/sources.list ,在 Ubuntu 24.04 已经被移动到 /etc/apt/sources.list.d/ubuntu.sources

这里选择阿里云 Ubuntu 源

# 备份原镜像列表
sudo cp /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources.bak


# 替换
sudo sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list.d/ubuntu.sources
sudo sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list.d/ubuntu.sources

# Update the package list
sudo apt-get update

4.5 安装 vim 和 ping 工具


sudo apt install vim iputils-ping

5. 安装 Kubernetes 集群

5.1 准备

安装的组件和版本如下表所示,在开始安装前,提前下载所需组件。

名称版本Release date备注
containerd 运行时containerd 2.0.22025-01-14下载 containerd-2.0.2-linux-amd64.tar.gz
containerd.service下载 containerd.service
runc v1.2.42025-01-07下载 runc.amd64
(可选)nerdctl v2.0.32025-01-21下载 nerdctl-2.0.3-linux-amd64.tar.gz
Kubernetesv1.32.02024-12-12
cilium-cliv0.16.242025-01-30下载 cilium-linux-amd64.tar.gz
cilium1.17.02025-02-04
istio1.24.22024-12-19下载 istio-1.24.2-linux-amd64.tar.gz

下载的文件:

k8s-istio-component

将文件上传到虚拟机中,如下图。

upload-component

5.2 安装 Containerd 运行时

# 创建 1-containerd.sh 文件,并粘贴下面内容。
sudo vim 1-containerd.sh

# 执行这个批处理文件。
sudo bash 1-containerd.sh

#! /bin/bash

# file:1-containerd.sh
# 需要在所有节点上执行。

# ----------------------------------------------------------------------------------
# 设置使用的版本常量
# ----------------------------------------------------------------------------------

# Containerd
readonly CONTAINERD_VERSION="2.0.2"
# nerdctl
readonly NERDCTL_VERSION="2.0.3"

# ----------------------------------------------------------------------------------
# 安装配置先决条件
# ----------------------------------------------------------------------------------

#
# 禁用交换分区
#
sudo swapoff -a
# 使禁用交换分区更改在重启后保持不变
sudo sed -i '/swap/ s/^\(.*\)$/#\1/g' /etc/fstab

#
# 启用 IPv4 数据包转发
#

# 设置所需的 sysctl 参数,参数在重新启动后保持不变
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF

# 应用 sysctl 参数而不重新启动
sudo sysctl --system

# ----------------------------------------------------------------------------------
# 安装 containerd
# ----------------------------------------------------------------------------------

# 解压缩
sudo tar Cxzvf /usr/local containerd-${CONTAINERD_VERSION}-linux-amd64.tar.gz

#
# 通过 systemd 启动 containerd。
#
sudo mkdir -p /usr/local/lib/systemd/system
sudo mv containerd.service /usr/local/lib/systemd/system/

# 重新加载配置
sudo systemctl daemon-reload
# containerd 服务设置为开机自启,并立即启动
sudo systemctl enable --now containerd

#
# 安装 runc
#
sudo install -m 755 runc.amd64 /usr/local/sbin/runc

#
# 配置 Containerd 的 cgroup 驱动为 systemd
#

# 采用二进制安装 containerd 时,需要创建 /etc/containerd 目录
sudo mkdir -p /etc/containerd

sudo containerd config default | sudo tee /etc/containerd/config.toml

# 设置 SystemdCgroup = true
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

# 配置文件中的 sandbox_image = "registry.k8s.io/pause:版本号",因 GFW 无法访问,需要替换为阿里云镜像。
# 替换 sandbox_image = "registry.k8s.io/pause:版本号" 为 sandbox_image = "registry.aliyuncs.com/google_containers/pause:版本号"
sudo sed -i 's/registry.k8s.io/registry.aliyuncs.com\/google_containers/' /etc/containerd/config.toml

#
# 重启 Containerd 服务
#
sudo systemctl restart containerd

5.3 安装 k8s 组件 kubeadm、kubelet 和 kubectl

# 创建 2-k8s.sh 文件,并粘贴下面内容。
sudo vim 2-k8s.sh

# 执行这个批处理文件。
sudo bash 2-k8s.sh


#! /bin/bash

# file:2-k8s.sh
# 需要在所有节点上执行。

# ----------------------------------------------------------------------------------
# 设置使用的 k8s 版本常量
# ----------------------------------------------------------------------------------

# Containerd
readonly K8S_VERSION="v1.32"

# ----------------------------------------------------------------------------------
# 1 - 更新 apt 包索引并安装使用 Kubernetes apt 仓库所需要的包
# ----------------------------------------------------------------------------------
sudo apt-get update
# apt-transport-https 可能是一个虚拟包(dummy package);如果是的话,你可以跳过安装这个包
sudo apt-get install -y apt-transport-https ca-certificates curl gpg

# ----------------------------------------------------------------------------------
# 2 - 下载用于 Kubernetes 软件包仓库的公共签名密钥。所有仓库都使用相同的签名密钥,因此你可以忽略URL中的版本
# ----------------------------------------------------------------------------------

# 如果 `/etc/apt/keyrings` 目录不存在,则应在 curl 命令之前创建它。
# 在低于 Debian 12 和 Ubuntu 22.04 的发行版本中,/etc/apt/keyrings 默认不存在。 应在 curl 命令之前创建它。
# sudo mkdir -p -m 755 /etc/apt/keyrings
# curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
curl -fsSL "https://pkgs.k8s.io/core:/stable:/${K8S_VERSION}/deb/Release.key" | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

# 添加 Kubernetes apt 仓库。 请注意,此仓库仅包含适用于特定版本的软件包; 对于其他 Kubernetes 次要版本,则需要更改 URL 中的 Kubernetes 次要版本以匹配你所需的次要版本 (你还应该检查正在阅读的安装文档是否为你计划安装的 Kubernetes 版本的文档)。
# 此操作会覆盖 /etc/apt/sources.list.d/kubernetes.list 中现存的所有配置。
# echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${K8S_VERSION}/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

# 更新 apt 包索引,安装 kubelet、kubeadm 和 kubectl,并锁定其版本
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

5.4 使用 kubeadm 引导集群

sudo kubeadm init \
--image-repository="registry.aliyuncs.com/google_containers" --v=5

集群创建成功后,执行

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

5.5 安装 Pod 网络组件 Cilium

提示

除了 Cilium 外也有一些其它网络插件可以使用,如 Calico,flannel 等。这里以 Cilium 作为示例。

sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
cilium install --version 1.17.0 --set ipam.operator.clusterPoolIPv4PodCIDRList="172.16.0.0/16"

查看安装状态

cilium status
# Or
cilium status --wait

5.6 部署一个测试应用

提示

当前只有一个节点,需要去掉 master 节点污点,否则无法调度 pod 到节点上。

检查是否可以正确部署。

# 删除污点
kubectl taint nodes k8s-dev node-role.kubernetes.io/control-plane:NoSchedule-

kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort

# 测试完删除
kubectl delete deployment nginx

6. 安装 Istio

6.1 安装

我们使用 demo 配置文件。 选择它是为了拥有一组适合测试的默认设置,Demo profile 仅用于开发测试.

提示

Istio 支持 Kubernetes Gateway API, 并计划将其作为未来流量管理的默认 API。

与 Istio Gateway 不同, 创建 Kubernetes Gateway 时, 默认情况下还会部署网关代理服务器。 由于不会使用它们,因此我们禁用通常作为 demo 配置文件的一部分安装的默认 Istio Gateway 服务的部署。


tar -xzf istio-1.24.2-linux-amd64.tar.gz

cd istio-1.24.2

# 将 istioctl 客户端添加到路径(Linux 或 macOS)
export PATH=$PWD/bin:$PATH

# 使用 demo 配置文件安装 Istio,无需任何 Gateway
istioctl install -f samples/bookinfo/demo-profile-no-gateways.yaml -y

# 检查安装了什么
kubectl -n istio-system get deploy

# 给命名空间添加标签,指示 Istio 在部署应用的时候,自动注入 Envoy 边车代理:
kubectl label namespace default istio-injection=enabled

下图所示,表示安装成功

istio-installed

安装 Kubernetes Gateway API CRD

Kubernetes Gateway API CRD 在大多数 Kubernetes 集群上不会默认安装, 因此请确保在使用 Gateway API 之前已安装它们。


# 先安装 git
sudo apt install git

kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
{ kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.2.0" | kubectl apply -f -; }

6.2 部署示例 Bookinfo 应用

kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
# 检查启动情况
kubectl get services
kubectl get pods

通过检查响应中的页面标题来验证应用程序是否在集群内运行

# <title>Simple Bookstore App</title>
kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

6.3 对外开放 Bookinfo 应用

Bookinfo 应用程序已部署,但无法从外部访问。为了使其可访问, 需要创建一个 Ingress Gateway,它将路径映射到网格边缘的路由。

# 为 Bookinfo 应用创建 Kubernetes Gateway:
kubectl apply -f samples/bookinfo/gateway-api/bookinfo-gateway.yaml

默认情况下,Istio 会为网关创建一个 LoadBalancer 服务。由于我们将通过隧道访问此网关, 因此不需要负载均衡器。如果想了解如何为外部 IP 地址配置负载均衡器, 请阅读 Ingress Gateway 文档。

# 通过注解网关将服务类型更改为 ClusterIP:
kubectl annotate gateway bookinfo-gateway networking.istio.io/service-type=ClusterIP --namespace=default

# 要检查网关的状态,运行:
kubectl get gateway

bookinfo-gateway

访问应用程序 将通过刚刚配置的网关连接到 Bookinfo productpage 服务。 要访问网关,需要使用 kubectl port-forward 命令:

  • port-forward 仅供开发和调试。在生产环境中,考虑使用 Service、Ingress 或其他方法来暴露应用。
  • 虽然 port-forward 可以让你访问内部服务,但它不提供任何安全性保障。确保只在受信任的网络中使用。
  • 当你完成转发操作后,记得关闭 kubectl port-forward 命令以释放端口。

# 默认情况下,port-forward 绑定到 127.0.0.1,但你可以指定其他本地 IP。例如,10.0.0.100 或要绑定到所有 IP(慎用)
kubectl port-forward svc/bookinfo-gateway-istio 8080:80 --address 0.0.0.0

打开浏览器并导航到 http://10.0.0.100:8080/productpage 以查看 Bookinfo 应用程序。

如果刷新页面,应该会看到书评和评分发生变化,因为请求分布在 reviews 服务的不同版本上。

bookinfo-webpage

6.5 查看仪表板

Istio 和几个遥测应用做了集成。 遥测能帮了解服务网格的结构、展示网络的拓扑结构、分析网格的健康状态。

使用下面说明部署 Kiali 仪表板、 以及 Prometheus、 Grafana、 还有 Jaeger。

  1. 安装 Kiali 和其他插件,等待部署完成。

kubectl apply -f samples/addons

# 查看部署状态
kubectl rollout status deployment/kiali -n istio-system

# 访问 Kiali 仪表板
istioctl dashboard kiali --address 10.10.0.100

都部署完成后如下图所示:

istio-addons

打开浏览器,访问 http://10.0.0.100:20001/kiali

kiali

在左侧的导航菜单,选择 Graph ,然后在 Namespace 下拉列表中,选择 default 。 要查看追踪数据,必须向服务发送请求。请求的数量取决于 Istio 的采样率。 采样率在安装 Istio 时设置,默认采样速率为 1%。在第一个跟踪可见之前,需要发送至少 100 个请求。 使用以下命令向 productpage 服务发送 100 个请求:

for i in $(seq 1 100); do curl -s -o /dev/null "http://$GATEWAY_URL/productpage"; done

Kiali 仪表板展示了网格的概览以及 Bookinfo 示例应用的各个服务之间的关系。 它还提供过滤器来可视化流量的流动

kiali-graph

参考资料

[1] 微软虚拟化文档
[2] Install Hyper-V
[3] 设置 NAT 网络
[4] MobaXterm 官网
[5] 安装并开始设置 Windows 终端
[6] Ubuntu 中国官网
[7] 阿里云 Ubuntu 源
[8] 腾讯云 Ubuntu 源
[9] 华为云 Ubuntu 源
[10] containerd 官网
[11] Getting started with containerd
[12] runc github
[12] nerdctl
[13] cilium 官网
[14] Kubernetes 官网
[15] istio 官网
[16] BookInfo 示例应用

云原生应用架构设计原则

· 阅读需 16 分钟

1.前言

12 要素应用程序 (12-Factor App) 是由 Heroku 的开发人员定义的用于构建云原生应用程序的一组原则。

然而,它诞生已超过十年,云技术自最初创建以来一直在发展。为了使应用程序能够真正利用现代云基础设施和工具,并在云中蓬勃发展,Kevin Hoffman 修订了最初的12个要素原则,并增加了三项,该书由 O’Reilly 出版社出版。书名是:Beyond the Twelve-Factor App

下面简要介绍这 15 个设计原则。

信息

云原生计算基金会(CNCF)关于云原生技术的定义:

云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。

这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。

2. 15个架构设计原则

2.1 One codebase, one application 一个应用,一个代码仓库

codebase

一个应用一个代码仓库,这里的应用也指微服务,一个微服务通常是具有一定业务边界的功能服务,当我们的软件系统有大量微服务组件时,每个微服务应该有自己的代码仓库。如果多个微服务有共享模块,那么这个共享模块也应该有独立的代码仓库,并使用依赖管理策略去加载它。

2.2 API first API优先

设计 API 时遵循 API 设计规范 OpenAPI v3规范

信息

当前 OpenAPI 规范 v3.1.0 发布时间 2021 年 2 月 15 日

2.3 Dependency management 依赖管理

dependencies

在 Java 项目中,依赖管理的两个流行的工具是 Maven 和 Gradle。工具有助于简化依赖管理的复杂性,开发人员能够声明他们的依赖关系,然后让工具负责实际确保这些依赖关系得到满足。

2.4 Design, build, release, and run 设计,构建,发布,运行

buildreleaserun

这条准则的目标是要最大化的提升发布速度,同时通过自动测试和自动部署来让我们对发布抱有信心。

2.5 Configuration, credentials, and code 配置,证书,和代码

config

配置指会随着部署环境发生变化的值,包括:

  • 后端服务的 URLs 和其他信息,比如 web service 和 SMTP 服务
  • 连接到数据库的必要信息
  • 调用第三方服务的证书
  • 可能需要放到 XMl 或者 YMAL 配置文件的其他属性

配置并不包括程序本身的内部信息,也就是说,如果某一个值在所有的部署环境都是一样的,它就不是配置。

证书是极其敏感的与代码无关的信息,通常来说,程序员会把证书从程序源代码里面提取出来放到属性文件里面,但是这样做并没有解决问题。 因为配置文件本身仍然是代码仓库的一部分,这意味着证书与程序一起发布,这本身就打破了这条规则。

一个最简单的检验证书和配置是否合理的方式,就是假设现在需要把源代码 push 到 GitHub 上面, 如果外面的人需要访问你的代码,你是否把你依赖的服务的敏感信息给暴露出去了呢?不是你的组织内部的人是否看到了内部后端服务的 URLs,证书或者其他敏感的信息呢?

如果能够在不暴露任何敏感信息的情况下去开源你的代码,那么你可能在隔离你的代码、配置、证书方面做的很好了。

外化配置的方式是可以使用一个配置中心,比如开源的 Spring Cloud Configuration Server,或者其他的配置服务产品。

2.6 Logs 日志

logs

将日志视为事件流,Logs 应该被当作一种事件流,也就是说, logs 是程序内部发出来的时间有序的事件序列。一个真正云原生的应用从来不关心如何路由和存储它的输出流。

应该将日志的聚合,处理和存储视为一项非功能性要求,该要求不是由应用程序满足,而是由云提供商或平台上面的其他工具套件来满足。可以使用ELK技术栈(ElasticSearch,Logstash 和 Kibana),Splunk,Sumologic 等工具或任何其他工具来捕获和分析日志。

2.7 Disposability 易处理

通过快速启动和优雅关机最大限度地提高稳健性。 如果一个应用程序不能快速的重启和停止,那么它就不能快速的扩展,部署,发布和恢复。要在构建应用的时候想到这一点。

如果应用程序正在一个高负载的场景下,就需要快速的启动更多的实例去处理这个负载,但是慢启动会阻碍通过扩展去处理较高的负载。如果应用程序不能快速和优雅的关闭,会失去失败场景下快速恢复的能力,不能快速关闭的能力同样会有耗尽资源的风险。

许多应用程序会在启动过程中有一些耗时较长的动作,例如获取数据缓存起来或者加载一些依赖项。需要单独处理这种动作。例如,可以将缓存外部化为后端服务,以便应用程序可以快速启动和关闭,而无需执行启动前加载动作。

2.8 Backing services 支持服务

backingsvcs

将支持服务视为附加资源,将外部组件(如数据库、电子邮件服务器、消息代理和系统人员可以提供和维护的独立服务)视为附加资源。将资源视为支持服务可以提高软件开发生命周期中的灵活性和效率。

这意味着应用程序没有一行代码会与某个特定的服务耦合到一起,可能会有一个用来发送邮件的后端服务,需要通过 SMTP 连接到邮件服务。但是邮件服务的实现细节不会影响到应用,同时应用也不会依赖于某个固定位置的 SMTP 服务器。

2.9 Environment parity 同等环境

dev-prodparity

尽可能的保持开发,预发布,线上环境相同,这一点很重要,以便可以确保所有潜在的错误/故障都可以在开发和测试中识别出来,而不是在应用程序投入生产时暴漏出来。

TestContainers 工具使我们能够确保测试环境也尽可能接近生产环境。

2.10 Administrative processes 管理进程

后台管理任务当作一次性进程运行。

不鼓励将一次性管理或管理任务放在微服务中。包括迁移数据库和运行一次性脚本来进行清理。这些应该作为一次性进程运行,它们可以作为 kubernetes 任务运行。 这样,服务可以专注于业务逻辑。

管理进程示例包括:

  • 数据迁移
  • 运行定时脚本,比如一个凌晨的批量任务
  • 运行一次性的自定义的程序

2.11 Port binding 端口绑定

portbindings

云原生应用通过端口绑定的方式暴露服务。网络可以通过端口号而不是域名来识别服务或应用程序。其原因是,域名和相关的IP地址可以通过手动操作和自动服务发现机制即时分配。因此,将它们用作参考点是不可靠的。根据端口号将服务或应用程序暴露给网络更可靠,也更容易管理。至少,由于网络私有端口号分配和另一个进程公开使用相同端口号之间的冲突而导致的潜在问题可以通过端口转发来避免。

2.12 Stateless processes 无状态进程

process

云原生应用程序应该是一个单一的无状态进程。所有持久状态都必须在应用程序外部,由后端服务提供。因此,无状态不是说不存在状态,而是说状态不能在应用程序中维护。

例如,一个提供用户管理功能的微服务是无状态的,因此所有用户的列表都在后端服务(例如 MongoDB 数据库)中维护。

2.13. Concurrency 并发

concurrancy

向一个大块的单体应用增加CPU核数,增加内存和其他的资源(虚拟的或者物理的),这种做法被称之为垂直扩展,这种做法不适用于云原生应用。

一个更加理想的扩展方式是水平扩展,相比较于把一个本来就很大的服务进程弄的越来越大,可以创建多个进程,然后在这些进程中分配负载。

大多数云提供商已经完善了这一功能,可以配置规则,根据负载或系统中可用的其他运行时遥测动态扩展应用程序实例的数量。

kubernetes 为我们提供了完善的设施来解决水平扩展的问题。

2.14 Telemetry 遥测

telemetry

遥测的字面定义是使用特殊设备对某物进行特定测量,然后使用无线通讯将这些测量传输到其它地方。遥测点到源头的测量是需要通过远程,远距离,无实物连接的方式来完成的。

这里特指监控和测量我们的云原生应用。当需要监控应用的时候,这里通常会有多种不同类型的数据:

  • 定期健康检查
  • 请求审核
  • 业务级别事件
  • 性能指标和系统日志

在规划监控策略时,要考虑清楚到底需要聚合多少信息、信息传入的速率以及要存储多少信息。如果应用程序从1个实例动态扩展到100个实例,那么也会导致日志流量增加百倍。

开源行业标准 OpenTelemeter 是在应用程序中实现有效分布式跟踪的工具,OpenTelemetry 是各类 API、SDK 和工具形成的集合。可用于插桩、生成、采集和导出遥测数据(链路、指标和日志),帮助你分析软件的性能和行为。

2.15 Authentication and authorization 认证和授权

authentication-and-authorization

在理想情况下,所有云原生应用程序都将使用 RBAC(基于角色的访问控制)保护其所有 API 。对应用程序资源的每个请求都应该知道是谁发出请求,以及该使用者所属的角色。这些角色决定调用客户端是否有足够的权限让应用程序接受请求。

有了 OAuth2、OpenID Connect 等工具,各种SSO服务器和标准,以及各种语言特定的身份验证和授权库,安全性应该从一开始就融入到应用程序的开发中,而不应该是在应用程序在生产环境中运行一段时间之后再加上的一个功能。

3. 参考

[1] 云原生计算基金会(CNCF)
[2] 12 要素应用程序 (12-Factor App)
[3] Kevin Hoffman. Beyond the Twelve-Factor App. O’Reilly
[4] Beyond the Twelve-Factor App 中文版
[5] An illustrated guide to 12 Factor Apps
[6] Creating cloud-native applications: 12-factor applications
[7] Beyond the 12 factors: 15-factor cloud-native Java applications
[8] OpenAPI 英文官网
[9] OpenAPI 中文官网
[10] kubernetes
[11] TestContainers
[12] OpenTelemeter
[13] OAuth 2.0
[14] Master OAuth 2.0 from this guide with modern use cases and real-world examples

数据库的版本控制方案

· 阅读需 11 分钟

1. 简介

作为软件开发工作的一部分对数据库进行建模是在项目的早期,但随着开发的进展,数据库模型会存在修改。在项目后期也可能由于客户提出的变更导致数据库模型的修改。许多看似不起眼的改动都可能给系统带来严重的后果。

我们希望有一种方法可以将数据库模型的修改和部署更新尽可能的平滑,把对系统可能的影响降到最低,并且即使发生问题也可以快速定位和修复,不造成毁灭的影响。

2. 数据库部署问题

软件开发中数据库的更改和部署有下面常见的一些问题。

  • 数据库生产部署可能由团队外部的DBA完成,他们不熟悉我们开发的应用程序,也可能不了解数据库结构
  • 手动部署容易出现人为错误
  • 手动部署通常需要等到发版窗口时间
  • 可能会向其他人提供不正确的脚本,从而导致部署错误的代码
  • 数据库的多个副本存在于不同的开发人员计算机上,因此很难确定要使用和部署的正确版本

3.数据库源代码控制示例

假如我们有一个名为 dept 的表。这是创建它的脚本:

CREATE TABLE dept (
id NUMBER,
name VARCHAR(100)
);

我们会将此文件保存为 “dept.sql” 文件,将其添加到我们的存储库中,提交并将其推送到远程代码存储库。

如果想对数据库进行更改怎么办,例如我们增加一个 status 字段?这引出了一个我们该决定如何管理数据库代码的问题。

有两个方案,是基于状态的版本控制和基于迁移的版本控制。

  • 方案一 基于状态

修改原有的 detp.sql 脚本。每当需要对表进行更改(例如添加状态列)时,它就会得到更新。

CREATE TABLE dept (
id NUMBER,
name VARCHAR(100),
status VARCHAR(20)
);
  • 方案二 基于迁移

创建另一个新的脚本 customer_add_status.sql。一个脚本创建客户表,另一个脚本添加状态列。

ALTER TABLE dept ADD COLUMN status VARCHAR(20);

4. 基于状态 VS 基于迁移

基于状态和基于迁移是数据库版本控制的两种方法。

基于状态:当存储反映数据库当前状态的数据库代码时,称为基于状态的版本控制。可以使用版本控制中的代码来创建数据库,脚本表示当前数据库定义是什么。

基于迁移:当存储反映为到达数据库当前状态而采取的步骤的数据库代码时,称为基于迁移的版本控制。版本控制中的脚本反映用于创建对象的原始脚本,以及后续所有变化的过程脚本。

基于状态的好处是

  • 被认为更简单,因为只有一组脚本(例如,每个对象一个脚本,或一些其他划分)。
  • 对象的定义在一个地方,所以任何人都可以打开它看看它应该是什么样子。
  • 版本控制提交历史将告诉我们更改了什么、何时以及谁更改了它们。

基于迁移的好处是

  • 数据库可以建立到某一时间点的状态,这有助于在有多个环境和分支的团队中使用
  • 所有更改都在单独的脚本中,因此知道什么正在更改以及何时更改
  • 由于脚本更小,部署可能更容易

数据库代码应该反映数据库的当前状态,还是应该反映为达到数据库的当前状态而采取的步骤呢?采用哪种方法需要与团队一起来讨论利弊。

通常的建议是使用基于迁移的部署,好处可能更多一些。这带来的另一个问题是可能会有大量过程脚本,当有大量过程脚本或者部署执行脚本带来大量的时间消耗的时候,我们可以用重新确定数据库脚本基线的方式来处理。

5. 重新确定数据库脚本的基线

重新基线化数据库部署脚本涉及将所有数据库部署脚本组合成一组反映数据库当前状态的脚本。这可以减少对同一对象上的数据库所做的更改数量,从而减少部署时间。

例如,假设在一年的时间里,对表进行了几次更改:

  1. 从原始脚本创建表
  2. 添加新列
  3. 添加索引
  4. 更改列的数据类型
  5. 再加三列
  6. 删除列
  7. 将表拆分为两个表

在所有这些脚本之后,很难判断表的样子。可以重新设置脚本基线,而不是为每个部署运行所有这些脚本。这意味着您可以创建一个脚本来创建当前状态的数据库,而不是运行所有这些迁移。

6. Liquibase & Flyway

使用比较广泛的数据库迁移工具有 Liquibase 和 Flyway,这两种工具都可以实现基于迁移的数据库部署工作。有开源的免费版本和付费商业版本。

7. 一些建议原则

下面是一些建议的指导原则。

  • 脚本一旦进入代码库,就不能更改。

一个脚本被添加到版本控制后,如果想对数据库进行更改,无论多小,都要编写一个新脚本。不要更改旧脚本。

  • 使用脚本而不是手动更改数据库。

所有更改都应使用相同的过程完成:编写新的脚本文件并在部署过程中获取它。这有助于避免数据库中的意外错误更改并确保一致性。

  • 确保每个开发人员都有自己的本地数据库,而不是共享的开发数据库。

请确保团队每个人都有自己的本地开发数据库。

  • 避免脚本中的独占锁。

编写的脚本可能会自动或手动在它们正在处理的表上放置独占锁。尽量避免在部署脚本中这样做,因为这会减慢部署过程。不过,这取决于使用的是哪个数据库供应商,因为某些数据库在某些情况下具有表级锁,而另一些则没有。

8. 如何实现上述方案

在团队中实现这一点可能需要一定的时间。技术方面可能需要设置工具和流程。个人方面也可能需要说服人们遵守一些列约定,并在过程中建立信任。

这是从手动数据库部署过程到自动化过程可以采取的步骤的列表。

  • 考虑从一个小的项目和团队开始。
  • 为数据库生成基线模式。这可以手动完成(编写 SQL 脚本)或使用IDE生成。
  • 将数据库脚本添加到源代码管理。
  • 确定用于数据库更改和迁移的工具。
  • 实现所选工具来处理版本控制的脚本。
  • 为每个开发人员实现一个本地数据库
  • 更新部署过程(或创建一个)以从源代码控制中的脚本生成数据库
  • 更新部署过程以将脚本部署到下一个环境(例如 QA )
  • 实施自动化数据库测试。这可能是一大步。
  • 更新部署过程以部署到您的下一个环境(例如 Pre Prod)
  • 更新部署过程以允许用户在需要时(以及测试通过时)触发部署到生产环境
  • 更新部署过程以自动部署到生产环境。

Tekton - 云原生持续集成与交付(CI/CD)工具

· 阅读需 6 分钟

1. 前言

在持续集成与持续交付(CI/CD)领域 Jenkins 是事实上的标准,随着云原生领域技术的发展,微服务架构下的持续集成与持续交付面临新的挑战。Jenkins 开源社区也开启了一个全新的项目 Jenkins X 来应对挑战。它基于 Jenkins 和 Kubernetes 实现,为微服务体系架构下的云原生应用的开发、运行和部署提供了全面的支持。相比于 Jenkins,Jenkins X 复用了 Jenkins 的能力,但更加专注于云原生应用的构建、测试和部署。

Tekton 是一个开源的、供应商中立的框架,用于创建持续集成和交付(CI/CD)系统,由持续交付基金会(CDF) 管理。作为 kubernetes 原生框架,Tekton 是通过为管道、工作流和其他构建块提供行业规范来实现持续交付的现代化。Tekton 允许通过抽象底层实现细节可跨多个云提供商或本地系统构建、测试和部署。

Tekton 和 Jenkins X 都是流行的持续集成/持续交付(CI/CD)工具,Jenkins X 更适用于那些已经熟悉 Jenkins 并希望将其扩展到云原生领域的团队。选择哪个工具取决于具体的项目需求、团队偏好以及团队对云原生技术的支持程度。

2. Tekton 的工作方式

Tekton 的目标是在云原生环境中创建可重用、可组合和声明性的小型构建块。它使用步骤(Step)、任务(Task)、管道(Pipeline)和资源(Resource)来执行此操作,如下图所示。

Tekton-PipelinesArchitecture

图片来源于:developers.redhat.com

  • Step 是对输入执行的操作。如果正在构建 Java 应用程序,它可能会运行一些单元测试或验证代码是否遵循现有的编码标准。Tekton 将在提供的容器中执行每个步骤。对于该Java 应用程序,可以运行安装了 JDK 的基础映像。Step 是 Tekton 中最基本的单元。

  • Task 是按顺序执行的步骤列表。Tekton 在 Kubernetes 的 pod 中运行 Task,这允许在设计一系列相关 step 时拥有一个共享环境。例如,可以在任务中挂载一个卷,该卷将在该特定任务的每个步骤中共享。

  • Pipeline 是可以并行或顺序执行的任务的集合。Tekton 为开发人员提供了如何以及何时执行这些任务的很大灵活性。甚至可以指定任务必须满足的条件才能启动下一个任务。

  • Resource 大多数 Pipeline 需要执行任务的输入,也可以产生输出。在 Tekton 中,这些被称为资源。资源可以是许多不同的类型,如 Git存储库、容器映像或 Kubernetes 集群。

3. Tekton 安装

先决条件

提示

官方 yaml 安装文件中的 image 指向 gcr.io,国内无法访问,需要科学上网。可以使用阿里云提供的镜像文件替代。只是版本略低于官方版本。 参见:阿里云容器计算服务帮助文档-Tekton最佳实践

提示

此安装方式适合作为 Tekton 管道的快速启动安装指南,不适用于生产用途。生产环境官方建议使用Tekton Operator 来安装、升级和管理 Tekton 项目。

kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml

# Specific release
# kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/previous/<version_number>/release.yaml

# 当所有组件在 READY 列下显示1/1时,安装完成。如下图。按 Ctrl+C 停止监控
kubectl get pods --namespace tekton-pipelines --watch

tekton-installed

安装 Tekton Command Line 工具

提示

测试环境为 Ubuntu 24.04 LTS

curl -LO https://github.com/tektoncd/cli/releases/download/v0.38.1/tektoncd-cli-0.38.1_Linux-64bit.deb
sudo dpkg -i ./tektoncd-cli-0.38.1_Linux-64bit.deb

4. 创建一个测试 Task

sudo cat > hello-world.yaml << EOF
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: hello
spec:
steps:
- name: echo
image: alpine
script: |
#!/bin/sh
echo "Hello World"
EOF

kubectl apply -f hello-world.yaml
sudo cat > hello-world-run.yaml << EOF
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: hello-task-run
spec:
taskRef:
name: hello
EOF

kubectl apply -f hello-world-run.yaml

# Verify that everything worked correctly:
# The value True under SUCCEEDED confirms that TaskRun completed with no errors.
kubectl get taskrun hello-task-run

# Take a look at the logs:
kubectl logs --selector=tekton.dev/taskRun=hello-task-run

5.接下来

7.参考

[1] Tekton 官网
[2] 持续交付基金会(CDF)
[3] 阿里云容器计算服务帮助文档-Tekton最佳实践
[4] Tekton Operator
[5] Visual Studio (VS) Code Tekton Pipelines extension by Red Hat

在 Kubernetes 集群中使用 MetalLB 作为负载均衡器

· 阅读需 3 分钟

在 Kubernetes 中不提供负载均衡的实现,网络负载均衡器的实现依赖于云厂商(阿里云、腾讯云、华为云、AWS、Azue 等),如果是自建集群,而不是选择这些公有云厂商提供的 Kubernetes ,在创建 Service 时,我们只能使用类型是 NodePort 和 ExternalIPs 的服务用做外部访问。

我们希望自建集群也能简单便捷的方式对集群外部暴露服务,MetalLB 这个项目正是为了解决这个问题。

先决条件

安装前有几个先决条件需要查看,特别是网络插件(CNI)的兼容性支持。

官网的安装文档 MetalLB Installation

安装

修改 kube-proxy 参数

kubectl edit configmap -n kube-system kube-proxy
提示

--proxy-mode ProxyMode 使用哪种代理模式:在 Linux 上可以是 'iptables'(默认)或 'ipvs'。 在 Windows 上唯一支持的值是 'kernelspace'。 如果配置文件由 --config 指定,则忽略此参数。

ipvs 参数含义可以参考:

  • IPVS vs. IPTables for kube-proxy in Kubernetes[3]
  • Comparing kube-proxy modes: iptables or IPVS?[4]
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true

安装MetalLB

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.8/config/manifests/metallb-native.yaml

查看命名空间下的组件都正常运行

kubectl get all -n metallb-system

alt text

定义要分配给负载均衡器服务的IP地址并配置 2 层通告。

sudo cat > metallb-config.yaml << EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 10.10.0.150-10.10.0.200
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
EOF

kubectl apply -f metallb-config.yaml

测试

kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --type=LoadBalancer --port=80

# 可以看到这里分配的地址是 10.10.0.150
kubectl get svc

curl http://10.10.0.150

alt text

参考

[1] 创建外部负载均衡器
[2] 组件工具 kube-proxy
[3] IPVS vs. IPTables for kube-proxy in Kubernetes
[4] Comparing kube-proxy modes: iptables or IPVS?