当前位置: 首页 > article >正文

Monorepo架构: 项目管理工具介绍、需求分析与技术选型

概述

  • 如何实现 monorepo,以及在项目中如何管理多个包,在进行具体项目开发前,有必要强调一个重要思维 — 全局观

  • 即看待技术方案时,要从需求角度出发,综合考量该方案能否长远满足项目或团队需求

  • 为什么要有全局观呢?如果直接拿一个项目,用特定工具创建工作区间并将其作为 monorepo 项目使用,虽直观易感受,但当技术更新时,这种思维方式就会落后

  • 若站在更高视角了解新技术、新方向,先梳理相关工具,明确哪些工具可满足需求,虽前期会花费一些时间,但后续不论遇到何种工具,都能清楚其用途

  • 这种方法可称作比较学习法,能举一反三、触类旁通,学会多种技术,横向比较了三类与 monorepo 相关的应用场景工具

  • 建立全局观后,后续在进行包管理和构建相关的技术选型时,就能更有针对性

  • 目前与 monorepo 相关的工具可分为三类,前两类尤为重要,需带着问题研究

    • 包管理与版本控制:例如 NPM、Lerna 等工具
    • 构建和测试优化:需要带着疑问去探究其含义
    • 组件化流程化开发:这是前端常涉及的内容
  • 解决包管理问题后,更重要的是形成自动化流水化,并提高其效率

  • 构建和测试优化环节便是在包管理基础上加入缓存、服务端优化等,以提升自动化流水线和整体开发效率

包管理与版本控制

  • 下面先从包管理和版本控制部分开始,重点介绍三个方案:
    • Learner:用于管理多个应用源代码的工具,很多项目曾使用该工具,但官方已切换至 pnpm
    • pnpm 和 Yarn Workspaces:二者类似,都可在同一工作区间管理多个 package 的依赖项。Pnpm Space 和 Yarn Workspaces 能在每个项目中独立使用 package.json 管理对应依赖

构建和测试优化相关的工具

  • NX:功能全面,具有缓存增量、并行构建、分布式构建等特点,还包含云平台相关功能,涉及构建、发布及云平台工具功能。其维护团队与 Leana 团队有一定关联,可与 Leana 5.1 以上版本集成,二者是互补关系

  • Turborepo:近年来流行的工具,底层用 Rush 编写。具有性能优化(采用高效缓存和任务调度策略)、依赖管理(智能处理依赖关系)、可扩展性(能处理不同规模项目的构建测试)、集成支持(与现有工具框架无缝集成)、远程缓存(提供服务端远程缓存加速构建)等特点,可视为 NX 的子集

  • Rush:微软出品,专为 monorepo 项目打造,主要解决两个问题:

    • 幽灵依赖:指在 package.json 文件中未明确列出,但安装时必须安装的包,可能导致项目在不同环境运行结果不同
    • 依赖包多副本问题:即同一个依赖包的多个版本同时存在于项目中,使依赖关系复杂,易引发引用混乱。Rush 还支持并行构建、插件系统和项目发布

组件化和模块化开发相关工具

  • Bit:使用 PNPM 管理项目依赖,是商业化工具。其颗粒度小到组件级别,可将 React 等框架中的组件或函数单独封装发布,具有灵活、便捷、可插拔、无需过多维护等优点,适用于多种场景,支持多种项目类型。

  • Layer- pack:是Webpack Plugin, 主要管理导入的 Glow 选项,聚焦于 Webpack 生态,可继承 Webpack 相关配置,适用于已有 Webpack 项目且想采用特定架构的情况

基于 Yarn Workspace 的 Monorepo 项目实践指南

1 ) 环境准备

  • 先从包管理相关工具开始, 首先,查看本地环境,我使用的是 Node 的 LTS 版本,然后全局安装 yarn
  • 推荐安装 nrm 并使用它切换到淘宝源。我已经切换成功,可以通过 npm config get registry 查看,现在已经切换到淘宝源了。将淘宝源复制,然后使用 yarn config set registry 设置为淘宝源,这样使用 yarn 工具安装依赖项时就会使用淘宝源,加速安装过程,npm 则不用管

2 ) 创建项目目录与初始化

  • 创建一个空目录,使用 mkdir yarnworkspacedemo 命令,也可以右键创建
  • 我直接使用命令行创建,接下来使用 yarn init -y 初始化项目
  • 初始化完成后,用 VSCode 打开 package.json 文件

3 ) 设置 yarn workspace 项目

  • 要设置一个 yarn workspace 的项目(即命名空间项目)来管理模块,需要修改 package.json 文件,在其中设置 workspaces 属性,并指定目录。
  • 接着创建一个 packages 目录,在其下面创建对应的模块,例如 moduleAmoduleB,这两个模块实际上就是两个 npm 包。
  • packages/moduleApackages/moduleB 目录下,分别使用 yarn init -y 初始化 package.json 文件,这样每个模块就有独立的文件来记录其相关依赖。

4 ) 添加依赖项

  • 在子模块中添加依赖:可以 cd 到子模块目录下,使用 yarn add 命令添加对应的依赖
  • 在根目录为所有模块添加依赖:直接在根目录使用 yarn add lodash -w 命令,这里的 -w 表示为所有工作区添加依赖。但要注意,根目录的 package.json 中需要设置 private: trueworkspaces 属性项。执行该命令后,会更新根目录的 package.json 文件,但子目录中不会显示依赖,但在子模块中调用依赖的方法时可以正常使用,这得益于 Node 的包管理机制,它会向上查找父级目录中的依赖
  • 在特定子模块中添加依赖:使用 yarn workspace moduleA add <dependency> 命令,可以限定在某个模块中添加依赖项,此时只会更新该子模块的 package.json 文件

6 ) 处理依赖版本冲突

  • 如果在子目录中指定了某个依赖的版本,而根目录中又指定了不同的版本,yarn 会在子目录中单独安装一份指定版本的依赖。
  • 例如,在子目录中添加 lodash 版本为 3,在根目录中添加 lodash 版本为 4,子目录中会单独创建一个 node_modules 目录来存放版本为 3 的 lodash,而根目录的 node_modules 中存放版本为 4 的 lodash

7 ) 跨模块使用

  • 若要在 moduleB 中使用 moduleA 导出的方法,先在 moduleA 中导出方法,如使用 CommonJS 规范:

    const range = (x, y) => { // 方法实现 return [x, y]; 
    }; 
    module.exports = range; 
    
  • 然后在 moduleB 中使用 yarn workspace moduleB add moduleA 添加依赖, 但可能会遇到版本号问题,这是因为 npm 上可能有同名的包。解决方法有两种:

    • 修改包名:给包名添加命名空间,如 @yournamespace/moduleA,确保名称独一无二。
    • 使用文件引用:在 package.json 中使用文件路径引用,如 "./packages/moduleA"

8 ) 创建新模块及处理未发布模块引用

  • 创建一个新模块 moduleC,在 packages/moduleC 目录下使用 yarn init -y 初始化,并设置包名时使用 @命名空间/包名 的格式,包名建议使用小写英文加中短横线,且不以点号或下横线开头。

  • 若要在 moduleB 中安装还未发布的 moduleC,不能直接使用 yarn workspace moduleB add moduleC,会报错。正确做法是先 cd 到根目录,使用 yarn install 命令在 node_modules 下创建软链接。执行后若没有成功链接,可以清除缓存,删除 node_modules 目录,再次执行 yarn install。此时在 moduleB 中可以使用 require('moduleC') 引用 moduleC,但 moduleBpackage.json 中不会更新 moduleC 的依赖信息。若要更新,需要手动在 moduleBpackage.jsondependencies 部分添加 moduleC 的具体版本。

9 ) 注意事项

  • 文件协议引用的问题:如果使用文件协议引用模块(如 file:./packages/moduleA),模块会被视为外部依赖,而不是工作区的一部分。每次更新模块代码后,需要清除 node_modules 缓存,重新执行 yarn install,比较麻烦。
  • 使用 yarn workspace 的要点总结:
    • 在项目根目录的 package.json 中配置 workspaces 属性,添加多个文件目录交给 yarn 管理。
    • 管理模块可以使用 yarn workspace <模块名> <命令> 的方式,也可以直接 cd 到该目录使用常用命令,yarn 会自动管理多个不同包下同名依赖的不同版本号。若与根目录中的依赖冲突,会在该包下创建 node_modules 目录并下载一份新的依赖。
    • 模块未发布时使用 yarn 关联本地依赖,可能会下载到别人创建的同名包,解决方法是命名一个独特的名称。跨模块使用时,可以使用 module:* 方式配合 yarn install 让包在整个工作区中关联,但还需执行 yarn install 在工作区目录的 node_modules 中创建对应的软链接。
    • 包名最好使用 @命名空间/包名 的结构,采用小写英文加中短横线的方式命名,避免以点号或下横线开头

PMPM Workspace使用教程、依赖包管理操作

1 ) 创建PNPM Workspace

  • 创建空目录:首先创建一个空的目录,我在这里创建了一个名为“PNPMworkspacedemo”的目录。
  • 打开workspace:使用workspace将其打开。
  • 初始化package.json文件:在终端工具中,使用pnpm init -y初始化一个package.json文件。
  • 创建pnpm-workspace.yaml文件:在该目录中创建一个名为pnpm-workspace.yaml的文件,在文件里添加一个字段packages,换行后接上文件的目录。例如,packages/ 表示只要是packages目录下面的包,相当于moderator项目,就是受PNPM workspace管理的模块。你也可以添加其他目录,比如folder1folder2等(若根目录中没有这些目录,可以将其注释掉)。这样,PNPM的workspace就创建好了。

2 ) 创建模块并初始化

  • 创建module-amodule-b两个模块,和之前一样,在这两个目录中初始化package.json文件。打开终端工具,执行以下命令:
  • cd packages/module-a 然后 pnpm init -y
  • cd packages/module-b 然后 pnpm init -y

3 ) 安装依赖包

  • 在根目录安装依赖:在根目录执行pnpm install lodash命令,会提示需要有pnpm-workspace.yaml文件。若文件名字写错,修改后再次安装,需要加上-w参数,这样依赖项会安装在根目录,module-amodule-b可以引用根目录中的模块,但这些模块不会打包到module-amodule-b中。
  • 在指定模块安装特定版本依赖:若要在module-a中安装特定版本的lodash,可以使用--filter参数,例如pnpm install lodash@3 --filter=module-a ,执行后在module-apackage.json里会多出一个lodash的依赖项。也可以使用pnpm install lodash@2 --filter module-a 这种格式。
  • 模块间依赖安装:在module-b中引用module-a,可以使用pnpm add module-a命令。安装后,node_modules下面的依赖包会有一个小箭头,表示这些文件是在全局引用的,存放在PNPM的缓存目录中,这样可以节省磁盘空间。

4 ) 查看和设置PNPM缓存目录

  • 查看缓存目录:使用pnpm store path命令可以查看本地的PNPM store位置,使用文件管理工具打开该目录,里面存放着很多下载的包和文件。
  • 设置缓存路径:使用pnpm config set store-dir ~/.pnpm-store命令可以设置缓存路径,设置成功后,后续安装依赖包时,若提示需要重新rebuild store ,按照提示操作即可。也可以使用pnpm config delete store-dir命令将缓存路径恢复到默认情况。

5 ) 模块代码编写与测试

  • module-amodule-b中编写代码进行测试。例如,在module-a中引入lodash
    const _ = require('lodash'); 
    const range = _.range; 
    module.exports = range; 
    
  • module-b中引用module-a
    const range = require('module-a'); 
    console.log(range(1, 10)); 
    
  • 保存代码后,若要执行代码,可以使用不同的命令:
    • 执行所有模块的脚本:PNPM提供了-r命令,例如pnpm -r exec node index.js ,可以循环执行各个模块中的index.js文件。在多个模块需要运行测试脚本的场景中,就可以使用pnpm -r exec 加上测试脚本的执行命令,让PNPM循环执行每个包中的测试脚本。
    • 执行特定模块的脚本:若要执行module-a中的start脚本,可以使用pnpm --filter=module-a run start (建议写filter时带上引号,避免出现问题)。

6 ) 简化命令设置
对于觉得每次输入pnpm相关命令麻烦的同学,可以根据不同操作系统进行设置:

  • Mac或Linux系统:可以借助如zsh一类的终端工具,设置常量。例如,设置alias pnpmrs='pnpm --filter=module-a' ,使用前先执行source ~/.zshrc让设置生效。也可以进一步简化,如alias p=pnpmalias pr='pnpm -r exec' 。若需要传参,可以编写函数,例如:
    pa() { pnpm "$1" --filter="$2" 
    } 
    
  • Windows系统:在PowerShell中,配置存放在profile.ps1文件里。可以使用Set-Alias命令设置别名,例如Set-Alias p pnpmSet-Alias pr 'pnpm -r exec' 。设置完成后,保存并重新加载配置文件即可使用简化后的命令。

PNPM与Yarn对比

  • Yarn的优缺点
    • 优点:相对成熟和稳定,较早支持monorepo方式,社区支持相对广泛,支持并行下载。
    • 缺点:空间占用比PNPM大,某些情况下安装性能不如PNPM,配置命令没有PNPM方便。配置workspace时,需要在package.json里写包名,相对麻烦。
  • PNPM的优缺点
    • 优点:具有高效的存储方式,性能比Yarn优越,有更严格的包命名策略。
    • 缺点:社区支持和资源没有Yarn完善,可能会遇到与项目或工具的兼容性问题,例如低版本的Node。

相关文章:

Monorepo架构: 项目管理工具介绍、需求分析与技术选型

概述 如何实现 monorepo&#xff0c;以及在项目中如何管理多个包&#xff0c;在进行具体项目开发前&#xff0c;有必要强调一个重要思维 — 全局观 即看待技术方案时&#xff0c;要从需求角度出发&#xff0c;综合考量该方案能否长远满足项目或团队需求 为什么要有全局观呢&a…...

ubuntu下libguestfs-tools

在ubuntu下&#xff0c;使用libguestfs-tools工具挂载其他磁盘和分区。 首先安装libguestfs-tools将vmx虚拟磁盘共享&#xff1a;sudo vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other执行如下命令查看分区名称&#xff1a;virt-filesystems -a /mnt/hgfs/D/vmware/FGT_VM64-v7…...

Authentication failed(切换了新的远程仓库tld)

启用 Git Credential Manager git config --global credential.helper manager 强制弹出凭据输入窗口 git config --global credential.helper.modalprompt true 指定 TFS 服务器使用基础认证&#xff08;Basic Auth&#xff09; git config --global credential.https://…...

【Web应用】若依框架:基础篇14 源码阅读-后端代码分析-课程管理模块前后端代码分析

文章目录 一、课程管理模块前端代码截图二、前端代码及分析index.vuecourse.js 三、前端执行流程1. 组件初始化2. 查询操作3. 列表操作4. 对话框操作5. API 请求6. 执行流程总结关键点 四、课程管理模块后端代码截图五、后端代码块CourseControllerICourseServiceCourseMapperC…...

在 Linux 上安装 `pgvector`(这是一个 PostgreSQL 的向量类型扩展,常用于处理嵌入向量,便于进行向量相似度搜索)

1. 安装 PostgreSQL 确保你已经安装好 PostgreSQL 数据库。 例如在 Ubuntu 上&#xff1a; sudo apt update sudo apt install postgresql postgresql-contrib2. 安装依赖 pgvector 扩展用的是 make、gcc 等开发工具&#xff0c;因此你需要先安装 PostgreSQL 的开发包和编译…...

09.MySQL内外连接

09.MySQL内外连接 文章目录 MySQL内外连接 内连接 外连接 左外连接 右外连接 简单案例 MySQL内外连接 在数据库操作中&#xff0c;表的连接是一个非常重要的概念。简单来说&#xff0c;连接就是将两个或多个表中的数据按照某种规则结合起来&#xff0c;从而获取我们所需要的…...

Python爬虫实战:研究Scrapy-Splash库相关技术

1 引言 1.1 研究背景与意义 网络爬虫作为一种自动获取互联网信息的技术,在数据挖掘、信息检索、舆情分析等领域有着广泛的应用。然而,随着 Web 技术的不断发展,越来越多的网站采用 JavaScript 动态渲染技术,如 React、Vue 等框架构建的单页应用 (SPA)。这些网站的内容通常…...

智能升级:中国新能源汽车充电桩规模化建设与充电桩智慧管理方案

近年来&#xff0c;中国新能源汽车产业快速发展&#xff0c;市场规模持续扩大&#xff0c;但充电基础设施的建设与管理仍面临布局不均、利用率低、智能化水平不足等问题。为推动新能源汽车普及&#xff0c;国家正加速充电桩的规模化建设&#xff0c;并通过智慧化管理提升运营效…...

AlphaFold3服务器安装与使用(非docker)(1)

1. 服务器显卡驱动准备 这部分我会详细记录一下我踩过的坑及怎样拯救的&#xff0c;原谅啰嗦啦 ^_^ 1.1 服务器旧配置 1.1.1 nvidia-smi [xxxxxxlocalhost ~]# nvidia-smi Thu May 29 20:54:00 2025 -------------------------------------------------------------…...

接口自动化测试之pytest接口关联框架封装

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一般情况下&#xff0c;我们是通过一个yaml文件进行关联实现 在根目录下新建一个文件yaml&#xff0c;通过上述conftest.py文件实现全局变量的更新: 1.首先需要建…...

M1安装并使用Matlab2024a进行java相机标定

安装 Matlab下载地址&#xff1a;https://www.macxin.com/archives/23771.html注意⚠️&#xff1a;如若需要java调用Matlab函数&#xff0c;则需要java版本为21 使用 安装完成之后运行此节目可以看到&#xff1a; 构建jar 命令行输入deploytool&#xff0c;会有一个弹窗&a…...

02-Redis常见命令

02-Redis常见命令 Redis数据结构介绍 Redis是一个key-value的数据库&#xff0c;key一般是String类型&#xff0c;不过value的类型多种多样&#xff1a; 贴心小建议&#xff1a;命令不要死记&#xff0c;学会查询就好啦 Redis为了方便学习&#xff0c;将操作不同数据类型的命…...

【论文阅读笔记】Text-to-SQL Empowered by Large Language Models: A Benchmark Evaluation

文章目录 Text-to-SQL Empowered by Large Language Models: A Benchmark Evaluation一、论文基本信息1. 文章标题2. 所属刊物/会议3. 发表年份4. 作者列表5. 发表单位 二、摘要三、解决问题四、创新点五、自己的见解和感想六、研究背景七、研究方法&#xff08;模型、实验数据…...

使用ArcPy进行栅格数据分析

设置工作环境 在开始编写脚本之前&#xff0c;需要设置好工作环境。这包括指定工作空间&#xff08;workspace&#xff09;和输出路径。工作空间是包含所有输入数据的文件夹或地理数据库&#xff0c;而输出路径则是处理结果将要保存的位置。 import arcpy from arcpy import …...

华为OD机试真题——告警抑制(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…...

Java转Go日记(五十七):gin 中间件

1. 全局中间件 所有请求都经过此中间件 package mainimport ("fmt""time""github.com/gin-gonic/gin" )// 定义中间 func MiddleWare() gin.HandlerFunc {return func(c *gin.Context) {t : time.Now()fmt.Println("中间件开始执行了&quo…...

《树数据结构解析:核心概念、类型特性、应用场景及选择策略》

在数据结构中&#xff0c;树是一种分层的非线性数据结构&#xff0c;由节点和边组成&#xff0c;具有唯一根节点、子树分层结构和无环特性。其核心价值在于高效处理层次化数据或动态集合&#xff0c;广泛应用于算法、数据库、文件系统等领域。 一、树的核心概念 根节点&#…...

在本地查看服务器上的TensorBoard

建立本地服务器与远程服务器的通信&#xff0c;将TensorBoard的映射端口与本地端口连接起来&#xff0c;本地终端运行&#xff1a; ssh -L 本地端口:127.0.0.1:TensorBoard端口 用户名服务器的IP地址 -p 服务器登录端口 e.g. ssh -L 10010:127.0.0.1:39353 sx110.92.137.56 -…...

硬件开发全解:从入门教程到实战案例与丰富项目资源

硬件开发全解&#xff1a;从入门教程到实战案例与丰富项目资源 一、硬件开发基础 1.1 硬件开发概述 硬件开发&#xff0c;简单来说&#xff0c;就是从构思到实现一个电子设备的全过程。这一过程涉及到电子电路设计、嵌入式系统编程、传感器和执行器的集成等多个关键领域。在电子…...

嵌入式学习笔记 - freeRTOS的两种临界禁止

一 禁止中断 通过函数taskENTER_CRITICAL() &#xff0c;taskEXIT_CRITICAL()实现 更改就绪列表时&#xff0c;通常是通过禁止中断的方式&#xff0c;进入临界段&#xff0c;因为systick中断中有可以更改就绪列表的权利&#xff0c; 就绪列表&#xff08;如 pxReadyTasksLis…...

202403-02-相似度计算 csp认证

其实这个问题就是求两篇文章的词汇的交集和并集&#xff0c;首先一说到并集&#xff0c;我就想到了set集合数据结构&#xff0c;set中的元素必须唯一。 STL之set的基本使用–博客参考 所以将两个文章的词汇全部加入set中&#xff0c;并求出set的大小&#xff0c;即为并集的大小…...

【Oracle】游标

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 游标基础概述1.1 游标的概念与作用1.2 游标的生命周期1.3 游标的分类 2. 显式游标2.1 显式游标的基本语法2.1.1 声明游标2.1.2 带参数的游标 2.2 游标的基本操作2.2.1 完整的游标操作示例 2.3 游标属性2.3.1…...

MySQL 中 char 与 varchar 的区别

在 MySQL 的字段类型中&#xff0c;char和varchar是用来处理字符串。本文来学习二者区别 一、本质区别&#xff1a;空间分配的 “固执” 与 “灵活” 1. char&#xff1a;空间占满 固定长度特性&#xff1a; 定义时指定长度&#xff08;如char(10)&#xff09;&#xff0c;无…...

DeepSeek 赋能智能零售,解锁动态定价新范式

目录 一、引言二、智能零售动态定价策略概述2.1 动态定价的概念与原理2.2 动态定价在智能零售中的重要性2.3 传统动态定价策略的局限性 三、DeepSeek 技术解析3.1 DeepSeek 的技术原理与架构3.2 DeepSeek 的优势与特点 四、DeepSeek 在智能零售动态定价中的应用机制4.1 数据收集…...

在Flutter中定义全局对象(如$http)而不需要import

在Flutter中定义全局对象&#xff08;如$http&#xff09;而不需要import 在Flutter中&#xff0c;有几种方法可以定义全局可访问的对象&#xff08;如$http&#xff09;而不需要在每个文件中import&#xff1a; 方法1&#xff1a;使用GetX的依赖注入&#xff08;推荐&#x…...

<4>, Qt窗口

目录 一&#xff0c;菜单栏 二&#xff0c;工具栏 三&#xff0c;状态栏 四&#xff0c;浮动窗口 五&#xff0c;对话框 一&#xff0c;菜单栏 MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);// 创建菜单栏…...

6.04打卡

浙大疏锦行 DAY 43 复习日 作业&#xff1a; kaggle找到一个图像数据集&#xff0c;用cnn网络进行训练并且用grad-cam做可视化 进阶&#xff1a;并拆分成多个文件 损失: 0.502 | 准确率: 75.53% 训练完成 import torch import torch.nn as nn import torch.optim as optim from…...

【基于SpringBoot的图书购买系统】操作Jedis对图书图书的增-删-改:从设计到实战的全栈开发指南

引言 在当今互联网应用开发中&#xff0c;缓存技术已成为提升系统性能和用户体验的关键组件。Redis作为一款高性能的键值存储数据库&#xff0c;以其丰富的数据结构、快速的读写能力和灵活的扩展性&#xff0c;被广泛应用于各类系统的缓存层设计。本文将围绕一个基于Redis的图…...

Ubuntu中TFTP服务器安装使用

TFTP服务器 在 Ubuntu 下使用 TFTP&#xff08;Trivial File Transfer Protocol&#xff09; 服务&#xff0c;通常用于简单的文件传输&#xff08;如网络设备固件更新、嵌入式开发等&#xff09;。 1 TFTP服务器安装 sudo apt-get install tftp-hpa sudo apt-get install…...

Spring Boot微服务架构(十):Docker与K8S部署的区别

Spring Boot微服务在Docker与Kubernetes&#xff08;K8S&#xff09;中的部署存在显著差异&#xff0c;主要体现在技术定位、管理能力、扩展性及适用场景等方面。以下是两者的核心区别及实践对比&#xff1a; 一、技术定位与核心功能 Docker 功能&#xff1a;专注于单节点容器化…...