记一次饱经挫折的阿里云ROS部署经历
前言
最近在参加的几个项目测评里,我发现**“一键部署”这功能真心好用,省下了不少宝贵时间和力气,再加上看到阿里云现在有个开源上云**的活动。趁着这波热潮,今天就聊聊怎么从头开始,一步步搞定阿里云的资源编排服务(ROS),希望能对刚接触这块的朋友有点帮助。咱们一块儿边学边实践,让云上的项目部署变得更简单高效。
资源编排
阿里云的资源编排服务(Resource Orchestration Service,简称ROS)是一种基础设施即代码(IaC)服务,它允许用户通过编写模板来定义和管理云上的各种资源。这些资源包括但不限于ECS( Elastic Compute Service)实例、RDS(Relational Database Service)数据库实例、SLB(Server Load Balancer)负载均衡器等。ROS的核心价值在于自动化部署及运维,它能自动处理资源的创建、配置及之间的依赖关系,从而极大地简化了云计算资源的管理过程。
在ROS中,用户根据ROS提供的模板规范,使用JSON或YAML格式编写资源栈模板。模板中不仅定义了所需的资源类型和数量,还明确了资源之间的逻辑依赖,确保资源按正确的顺序被创建和配置。这样,无论是新建环境、更新配置还是进行大规模的架构调整,都可通过执行模板脚本来实现,保证了操作的一致性和可重复性。
资源编排地址如下:https://ros.console.aliyun.com/cn-hangzhou/welcome
下面我们还是以实战为导向,从最基础的ROS脚本开始看起,一步步拆解。
ROS模板
首先我们先看一下ROS模板结构及参数说明。
{"ROSTemplateFormatVersion" : "2015-09-01","Description" : "模板描述信息,可用于说明模板的适用场景、架构说明等。","Metadata" : {// 关于模板的元数据信息,例如存放用于可视化的布局信息。},"Parameters" : {// 定义创建资源栈时,用户可以定制化的参数。},"Mappings" : {// 定义映射信息表,映射信息是一种多层的Map结构。},"Conditions": {// 使用内部条件函数定义条件。这些条件确定何时创建关联的资源。},"Resources" : {// 所需资源的详细定义,包括资源间的依赖关系、配置细节等。},"Outputs" : {// 用于输出一些资源属性等有用信息。可以通过API或控制台获取输出的内容。}
}
【参数说明】:
-
ROSTemplateFormatVersion:必选,ROS支持的模板版本号,当前版本号:2015-09-01。
-
Description:可选,模板的描述信息。可用于说明模板的适用场景、架构说明等。通常情况下,对模板进行详细描述,有利于用户理解模板的内容。
-
Metadata:可选,模板编写者可以使用Metadata来存放与模板相关的元数据信息,内容可以为JSON格式。
-
Parameters:可选,定义创建资源栈时,模板用户可以定制化的参数。通常,模板的编辑者会把ECS的规格设计成一个参数。参数支持默认值。使用参数可以增强模板的灵活性,提高复用性。使用模板创建资源栈时,可以根据实际的评估结果来选择合适的规格。更多详细信息,请参见参数(Parameters)。
-
Mappings:可选,Mappings定义了一个多层的映射表,可以通过Fn::FindInMap函数来选择Key对应的值,或根据不同的输入参数值作为Key来查找映射表。例如,您可以根据Region不同,自动查找Region-镜像映射表,从而找到适用的镜像。更多详细信息,请参见映射(Mappings)。
-
Conditions:可选,Conditions使用Fn::And、Fn::Or、Fn::Not、Fn::Equals定义条件。多个条件之间使用半角逗号(,)隔开。在创建或更新资源栈时,系统先计算模板中的所有条件,然后再创建资源。创建与true条件关联的所有资源,忽略与false条件关联的所有资源。更多详细信息,请参见条件(Conditions)。
-
Resources:可选,用于详细定义使用该模板创建的资源栈所包含的资源,包括资源间的依赖关系、配置细节等。更多详细信息,请参见资源(Resources)。
-
Outputs:可选,用于输出一些资源属性等有用信息。可以通过API或控制台获取输出的内容。更多详细信息,请参见输出(Outputs)。
通过上面可以看出最核心、最关键的部分其实是Parameters、Resources , 因为这两个决定了模板设计者定义一系列可配置的参数和将要创建或管理的所有云资源及其配置,是直接涉及资源创建和配置的核心逻辑参数。
下面我们来创建第一个案例。
基于ROS模板创建VPC
在创建之前,我们需要先知道ROS支持的所有资源类型,这里需要查看资源类型索引。
如果在这个列表中没有出现的产品,就是暂时不支持采用ROS来创建的,这是需要明确的第一点。
如上图,我们看到VPC是支持使用ROS来创建的,接下来我们再开展第二步,点击这个蓝色链接位置,查看它的详细语法、属性及返回值。
到这里,我们基本就明白它的语法格式及书写方式了,下面第三步,上手开写。
回到资源编排界面,点击【我的模板】→【创建模板】,进去ROS在线编辑界面开始编辑。
初始的模板如下,我们选择为yaml格式来进行编写。
下面咱们一行行的分析:
ROSTemplateFormatVersion
默认版本号,这里不用修改,直接过
ROSTemplateFormatVersion: '2015-09-01'
Description
这里不是必填,不过也可以填一下,暂且起名为my first VPC-test。
Description: my first VPC-test
Parameters
这里到重头戏了,几乎所有的可定制化参数都是在这里修改的,在比较复杂的ROS脚本中几乎都会用到,但是这里为了方便演示,也选择暂时不填写,等下后面测试时再填写后对比。
Parameters: {}
Resources
这里是用来详细定义使用该模板创建的资源栈所包含的资源,包括资源间的依赖关系、配置细节等,是必填项。
而其具体的格式,可以看到如下:
这里我们沿用该格式,并且剔除一些不需要的参数,最终命令如下:
VPC:Type: ALIYUN::ECS::VPCProperties:VpcName: VPC-testCidrBlock: 192.168.0.0/24
这里面就只包含了最基础的CidrBlock(专有网络网段)和VpcName(专有网络名称)。
Mappings、Metadata、Conditions
这里也暂时不涉及,可以直接删除掉。
Outputs
这里用于输出一些资源属性等有用信息,这里我们可以尝试输出一下VPC的ID和关联的虚拟路由器ID。
Outputs:VPCId:Value:Fn::GetAtt:- VPC- VRouterIdVRouterId:Value:Fn::GetAtt:- VPC- VRouterId
参照返回示例如下
最终ROS的整体脚本如下:
ROSTemplateFormatVersion: '2015-09-01'
Description: my first VPC-test
Resources:VPC:Type: ALIYUN::ECS::VPCProperties:VpcName: VPC-testCidrBlock: 192.168.0.0/24
Outputs:VPCId:Value:Fn::GetAtt:- VPC- VRouterIdVRouterId:Value:Fn::GetAtt:- VPC- VRouterId
点击预览,查看资源架构,我们可以看到如图所示的架构:
确定之后点击保存模板,命名后可在模板空间中查看和直接创建栈:
选择失败时回滚,点击创建:
此时可以看到开始创建资源栈,等待一段时间:
创建成功后如下图所示:
点击输出,我们可以看到outputs中设定的输出的关键字
而假如我们不需要使用了,也可以直接点击删除资源栈:
以上是手动编写脚本的流程了,在实际调试中还是有一些复杂的,下面我们就来结合案例,完成这次参赛的ROS部署作品。
基于ROS部署MaxKB
MaxKB
MaxKB是基于LLM大语言模型的知识库问答系统,旨在成为企业的最强大脑。它支持开箱即用,无缝嵌入到第三方业务系统,并提供多模型支持,包括主流大模型和本地私有大模型,为用户提供智能问答交互体验和灵活性。
另外说一句,我的关于知识库侧测评的文章也已经快写完了,这几个月参加护网有点太累了,几乎没时间来写,抱歉抱歉!
编写ROS 模板
这里我们还是一步步的来,逐步解析。
ROSTemplateFormatVersion
老规矩,不变。
ROSTemplateFormatVersion: '2015-09-01'
Description
因为是参赛的作品,所以我这里也写的详细一点吧,下面也是带上了中英的描述。
Description:en: Setting up the large language model-based knowledge base question and answer system, MaxKB, on an ECS (Elastic Compute Service) instance.zh-cn: 在ECS实例上搭建大语言模型的知识库问答系统MaxKB。
Parameters
这里涉及到的就比较复杂了,因为此处是必须要进行一些自定义参数设置的,我们进到ECS的语法下面详细查看。
说实话,有点吓人,居然这么多!
我们按照下面这个表格来一一排查:
ZoneId
这里首先申明ZoneId , 至于为什么先申明ZoneId呢?这是因为区域(Zone)的选择对创建的云资源(如ECS实例、RDS数据库等)有着直接的影响,且下面在申明实例规格时会用到。
ZoneId:Type: StringLabel:en: Availability Zonezh-cn: 可用区IDAssociationProperty: ALIYUN::ECS::Instance:ZoneId
AssociationProperty 说明ZoneId参数与ECS实例的ZoneId属性关联。这意味着在模板中使用此参数的地方,我们所选择的值将会直接应用于创建ECS实例时的可用区选择。这样的设计确保了模板的逻辑与阿里云ECS服务的实际属性紧密集成,提高了模板的准确性和易用性。
InstanceType
ECS实例规格 ,必填项 ,这里需要参考实例规格族。
InstanceType:Type: StringLabel:en: Instance Typezh-cn: 实例类型AssociationProperty: ALIYUN::ECS::Instance::InstanceTypeAssociationPropertyMetadata:ZoneId: ${ZoneId}DefaultValueStrategy: recent
同样,这里的 AssociationProperty 是指明参数与ECS实例的InstanceType属性关联;而 AssociationPropertyMetadata 则是表示实例类型的可用性依赖于ZoneId中选择的区域ID,且当用户没有明确指定实例类型时,系统会选择最近常用或推荐的实例类型作为默认选项。
SystemDiskCategory
下面定义ECS实例系统盘的类型,其中,AssociationPropertyMetadata 里面包含了一些元数据来指导和约束系统盘类型的选择:
SystemDiskCategory:Type: StringLabel:en: System Disk Typezh-cn: 系统盘类型AssociationProperty: ALIYUN::ECS::Disk::SystemDiskCategoryAssociationPropertyMetadata:LocaleKey: DiskCategoryZoneId: ${ZoneId}InstanceType: ${InstanceType}AutoSelectFirst: trueAutoChangeType: falseDefault: cloud_essd
InstancePassword
下面定义了用于登录ECS实例的密码规则,确保了安全性的同时也提供了一定的灵活性:
InstancePassword:Type: StringLabel:en: Instance Passwordzh-cn: 实例密码Description:en: Server login password, Length 8-30, must contain three(Capital letters,lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbolin).zh-cn: 服务器登录密码,长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)。ConstraintDescription:en: Length 8-30, must contain three(Capital letters, lowercase letters, numbers,()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in).zh-cn: 长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)。AssociationPropertyMetadata:Visible:Condition:Fn::Equals:- ${SelectInstance}- falseDefault:AllowedPattern: '[0-9A-Za-z\_\-\&:;''<>,=%`~!@#\(\)\$\^\*\+\|\{\}\[\]\.\?\/]+$'MinLength: 8MaxLength: 30NoEcho: true
所以Parameters此处的完整脚本如下:
Parameters:ZoneId:Type: StringLabel:en: Availability Zonezh-cn: 可用区IDAssociationProperty: ALIYUN::ECS::Instance:ZoneIdInstanceType:Type: StringLabel:en: Instance Typezh-cn: 实例类型AssociationProperty: ALIYUN::ECS::Instance::InstanceTypeAssociationPropertyMetadata:ZoneId: ${ZoneId}DefaultValueStrategy: recentSystemDiskCategory:Type: StringLabel:en: System Disk Typezh-cn: 系统盘类型AssociationProperty: ALIYUN::ECS::Disk::SystemDiskCategoryAssociationPropertyMetadata:LocaleKey: DiskCategoryZoneId: ${ZoneId}InstanceType: ${InstanceType}AutoSelectFirst: trueAutoChangeType: falseDefault: cloud_essdInstancePassword:Type: StringLabel:en: Instance Passwordzh-cn: 实例密码Description:en: Server login password, Length 8-30, must contain three(Capital letters,lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbolin).zh-cn: 服务器登录密码,长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)。ConstraintDescription:en: Length 8-30, must contain three(Capital letters, lowercase letters, numbers,()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in).zh-cn: 长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)。AssociationPropertyMetadata:Visible:Condition:Fn::Equals:- ${SelectInstance}- falseDefault:AllowedPattern: '[0-9A-Za-z\_\-\&:;''<>,=%`~!@#\(\)\$\^\*\+\|\{\}\[\]\.\?\/]+$'MinLength: 8MaxLength: 30NoEcho: true
Resources
这里开始创建资源,分析架构所需,涉及产品如下:
VPC
定义一个虚拟私有云(VPC)资源,192.168.0.0/16 指定了VPC的IP地址范围。
Vpc:Type: ALIYUN::ECS::VPCProperties:CidrBlock: 192.168.0.0/16
VSwitch
定义一个虚拟交换机(VSwitch)的配置:Ref: ZoneId 表示虚拟交换机将被创建在指定的可用区(Zone)中,这里的ZoneId是一个引用,其实际值需要在模板的参数或映射部分提前定义或通过外部参数传入;Ref: Vpc 指明该虚拟交换机隶属于哪个VPC。这里同样使用了引用,意味着VSwitch将与之前定义的VPC关联。确保在模板中已经定义了VPC资源或者通过参数传递了正确的VPC ID;192.168.0.0/24 定义了虚拟交换机的IP地址范围。
VSwitch:Type: ALIYUN::ECS::VSwitchProperties:ZoneId:Ref: ZoneIdVpcId:Ref: VpcCidrBlock: 192.168.0.0/24
SecurityGroup
创建安全组:Ref: Vpc 指定该安全组将被创建在哪个VPC中,这里通过引用之前定义的VPC资源(Vpc),确保安全组与目标VPC正确关联。这一步是必要的,因为每个安全组都必须绑定到一个特定的VPC。
SecurityGroup:Type: ALIYUN::ECS::SecurityGroupProperties:VpcId:Ref: Vpc
SecurityGroupIngress_80
定义了入站规则:Ref: SecurityGroup 引用了之前定义的安全组ID,这条入站规则将被添加到该安全组中;0.0.0.0/0 指定任何IP地址(全网段)都可以作为流量的来源,这意味着对于这条规则,不限制访问的来源IP地址;**tcp **指定了该规则适用的协议类型,这里是TCP;intranet 表示这条规则仅适用于VPC内部的通信;80/80 定义了允许访问的端口范围,这里只开放了TCP 80端口,通常用于HTTP服务。
SecurityGroupIngress_80:Type: ALIYUN::ECS::SecurityGroupIngressProperties:SecurityGroupId:Ref: SecurityGroupSourceCidrIp: 0.0.0.0/0IpProtocol: tcpNicType: intranetPortRange: 80/80
InstanceGroup
定义实例群组:引用上面创建的Vpc、VSwitch和SecurityGroupId实例;指定使用CentOS 7.9的镜像;设置了实例的名称为MaxKB;后面继续引入实例类型、系统盘的类别和密码。
InstanceGroup:Type: ALIYUN::ECS::InstanceGroupProperties:VpcId:Ref: VpcVSwitchId:Ref: VSwitchSecurityGroupId:Ref: SecurityGroupImageId: centos_7_9InstanceName: MaxKBInstanceType:Ref: InstanceTypeSystemDiskCategory:Ref: SystemDiskCategoryPassword:Ref: InstancePasswordIoOptimized: optimizedMaxAmount: 1
DS_Instances
通过DS_Instances数据源来获取通过InstanceGroup创建的ECS实例列表。
DS_Instances:Type: DATASOURCE::ECS::InstancesProperties:InstanceIds:Fn::GetAtt:- InstanceGroup- InstanceIds
InstallMaxKB
这里使用到Formation模板中的ALIYUN::ECS::RunCommand资源类型配置,用于在特定的ECS实例上执行一系列Shell脚本命令。
InstallMaxKB:
Type: ALIYUN::ECS::RunCommandProperties:InstanceIds:Fn::GetAtt:- InstanceGroup- InstanceIdsType: RunShellScriptSync: trueTimeout: 1800CommandContent: |#!/bin/bashecho "#########################"echo "# Install Docker"echo "#########################"wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repoyum -y install docker-cesystemctl start dockersystemctl enable dockerecho "#########################"echo "# Install MaxKB"echo "#########################"yum -y install jqDOCKER_DAEMON_JSON="/etc/docker/daemon.json"sudo jq --arg registry "$NEW_REGISTRY" '. + { "registry-mirrors": [https://0jt38sli.mirror.aliyuncs.com] }' $DOCKER_DAEMON_JSON > ${DOCKER_DAEMON_JSON}.temp && sudo mv ${DOCKER_DAEMON_JSON}.temp $DOCKER_DAEMON_JSONsudo systemctl daemon-reloadsudo systemctl restart dockerdocker run -d --name=maxkb -p 8080:8080 -v ~/.maxkb:/var/lib/postgresql/data 1panel/maxkb
最终,Resources下脚本如下:
Resources:Vpc:Type: ALIYUN::ECS::VPCProperties:CidrBlock: 192.168.0.0/16VSwitch:Type: ALIYUN::ECS::VSwitchProperties:ZoneId:Ref: ZoneIdVpcId:Ref: VpcCidrBlock: 192.168.0.0/24SecurityGroup:Type: ALIYUN::ECS::SecurityGroupProperties:VpcId:Ref: VpcSecurityGroupIngress_80:Type: ALIYUN::ECS::SecurityGroupIngressProperties:SecurityGroupId:Ref: SecurityGroupSourceCidrIp: 0.0.0.0/0IpProtocol: tcpNicType: intranetPortRange: 80/80InstanceGroup:Type: ALIYUN::ECS::InstanceGroupProperties:VpcId:Ref: VpcVSwitchId:Ref: VSwitchSecurityGroupId:Ref: SecurityGroupImageId: centos_7_9InstanceName: difyInstanceType:Ref: InstanceTypeSystemDiskCategory:Ref: SystemDiskCategoryPassword:Ref: InstancePasswordIoOptimized: optimizedMaxAmount: 1DS_Instances:Type: DATASOURCE::ECS::InstancesProperties:InstanceIds:Fn::GetAtt:- InstanceGroup- InstanceIds
InstallMaxKB:
Type: ALIYUN::ECS::RunCommandProperties:InstanceIds:Fn::GetAtt:- InstanceGroup- InstanceIdsType: RunShellScriptSync: trueTimeout: 1800CommandContent: |#!/bin/bashecho "#########################"echo "# Install Docker"echo "#########################"wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repoyum -y install docker-cesystemctl start dockersystemctl enable dockerecho "#########################"echo "# Install MaxKB"echo "#########################"yum -y install jqDOCKER_DAEMON_JSON="/etc/docker/daemon.json"sudo jq --arg registry "$NEW_REGISTRY" '. + { "registry-mirrors": [https://0jt38sli.mirror.aliyuncs.com] }' $DOCKER_DAEMON_JSON > ${DOCKER_DAEMON_JSON}.temp && sudo mv ${DOCKER_DAEMON_JSON}.temp $DOCKER_DAEMON_JSONsudo systemctl daemon-reloadsudo systemctl restart dockerdocker run -d --name=maxkb -p 8080:8080 -v ~/.maxkb:/var/lib/postgresql/data 1panel/maxkb
Outputs
定义了名为 MaxKBUrl 的输出项,用于提供MaxKB服务的默认访问地址:
Outputs:MaxKBUrl:Description: MaxKB default address.Value:Fn::Sub:- http://${IP}- IP:Fn::Jq:- First- if .[0].PublicIpAddress != [] then .[0].PublicIpAddress[0] else .[0].EipAddress.IpAddressend- Fn::GetAtt:- DS_Instances- Instances
Metadata
添加了一个标签来描述此模板的功能和背景,按照比赛要求是需要采用“手机尾号-模板用途”来编写。
Metadata:ALIYUN::ROS::Interface:TemplateTags:- acs:developer:gitee:0147-在ECS实例上搭建大语言模型的知识库问答系统MaxKB。
整体脚本
ROSTemplateFormatVersion: '2015-09-01'
Description:en: Setting up the large language model-based knowledge base question and answer system, MaxKB, on an ECS (Elastic Compute Service) instance.zh-cn: 在ECS实例上搭建大语言模型的知识库问答系统MaxKB。
Parameters:ZoneId:Type: StringLabel:en: Availability Zonezh-cn: 可用区IDAssociationProperty: ALIYUN::ECS::Instance:ZoneIdInstanceType:Type: StringLabel:en: Instance Typezh-cn: 实例类型AssociationProperty: ALIYUN::ECS::Instance::InstanceTypeAssociationPropertyMetadata:ZoneId: ${ZoneId}DefaultValueStrategy: recentSystemDiskCategory:Type: StringLabel:en: System Disk Typezh-cn: 系统盘类型AssociationProperty: ALIYUN::ECS::Disk::SystemDiskCategoryAssociationPropertyMetadata:LocaleKey: DiskCategoryZoneId: ${ZoneId}InstanceType: ${InstanceType}AutoSelectFirst: trueAutoChangeType: falseDefault: cloud_essdInstancePassword:Type: StringLabel:en: Instance Passwordzh-cn: 实例密码Description:en: Server login password, Length 8-30, must contain three(Capital letters,lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbolin).zh-cn: 服务器登录密码,长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)。ConstraintDescription:en: Length 8-30, must contain three(Capital letters, lowercase letters, numbers,()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in).zh-cn: 长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)。AssociationPropertyMetadata:Visible:Condition:Fn::Equals:- ${SelectInstance}- falseDefault:AllowedPattern: '[0-9A-Za-z\_\-\&:;''<>,=%`~!@#\(\)\$\^\*\+\|\{\}\[\]\.\?\/]+$'MinLength: 8MaxLength: 30NoEcho: true
Resources:Vpc:Type: ALIYUN::ECS::VPCProperties:CidrBlock: 192.168.0.0/16VSwitch:Type: ALIYUN::ECS::VSwitchProperties:ZoneId:Ref: ZoneIdVpcId:Ref: VpcCidrBlock: 192.168.0.0/24SecurityGroup:Type: ALIYUN::ECS::SecurityGroupProperties:VpcId:Ref: VpcSecurityGroupIngress_80:Type: ALIYUN::ECS::SecurityGroupIngressProperties:SecurityGroupId:Ref: SecurityGroupSourceCidrIp: 0.0.0.0/0IpProtocol: tcpNicType: intranetPortRange: 80/80InstanceGroup:Type: ALIYUN::ECS::InstanceGroupProperties:VpcId:Ref: VpcVSwitchId:Ref: VSwitchSecurityGroupId:Ref: SecurityGroupImageId: centos_7_9InstanceName: MaxKBInstanceType:Ref: InstanceTypeSystemDiskCategory:Ref: SystemDiskCategoryPassword:Ref: InstancePasswordIoOptimized: optimizedMaxAmount: 1DS_Instances:Type: DATASOURCE::ECS::InstancesProperties:InstanceIds:Fn::GetAtt:- InstanceGroup- InstanceIdsInstallMaxKB:Type: ALIYUN::ECS::RunCommandProperties:InstanceIds:Fn::GetAtt:- InstanceGroup- InstanceIdsType: RunShellScriptSync: trueTimeout: 1800CommandContent: |#!/bin/bashecho "#########################"echo "# Install Docker"echo "#########################"wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repoyum -y install docker-cesystemctl start dockersystemctl enable dockerecho "#########################"echo "# Install MaxKB"echo "#########################"yum -y install jqDOCKER_DAEMON_JSON="/etc/docker/daemon.json"sudo jq --arg registry "$NEW_REGISTRY" '. + { "registry-mirrors": [https://0jt38sli.mirror.aliyuncs.com] }' $DOCKER_DAEMON_JSON > ${DOCKER_DAEMON_JSON}.temp && sudo mv ${DOCKER_DAEMON_JSON}.temp $DOCKER_DAEMON_JSONsudo systemctl daemon-reloadsudo systemctl restart dockerdocker run -d --name=maxkb -p 8080:8080 -v ~/.maxkb:/var/lib/postgresql/data 1panel/maxkbOutputs:MaxKBUrl:Description: MaxKB default address.Value:Fn::Sub:- http://${IP}- IP:Fn::Jq:- First- if .[0].PublicIpAddress != [] then .[0].PublicIpAddress[0] else .[0].EipAddress.IpAddressend- Fn::GetAtt:- DS_Instances- Instances
Metadata:ALIYUN::ROS::Interface:TemplateTags:- acs:developer:gitee:0147-在ECS实例上搭建大语言模型的知识库问答系统MaxKB
部署测试
回到我的模板中,点击我的模板,查看对应的资源框架,确认基本无误后点击保存。
命名为MaxKB。
点击创建栈:
由于我在上述ROS脚本中申明了可用区、CPU内存配置、系统盘类型等,所以这里都需要进行选择:
选择失败时回滚,点击创建,需保证账户余额大于100元:
在创建界面的资源处,可以看到ROS中定义的实例正在逐一被创建:
构建MaxKB需要花费一些时间,创建完成后如下图所示:
但是意外的是,事件里面出现执行失败了。
进入事件,点击前面的实例链接。
查看实例的日志,发现是docker超时了。
于是我增加了一个测试下载的hello-world的案例,发现是正常的:
sudo docker run hello-world
于是乎,我换到我自己的电脑上尝试,很奇怪的是,即使添加了一堆镜像源依然下载报错。。。
感觉有点不对劲了,开始尝试用git方式部署,对照着文档学习了一下,采用git本地编译部署对环境要求极为苛刻。。。转化成一键部署的脚本更是麻烦。
最后尝试了半天无果,还是放弃MaxKB的搭建吧。。。没事,咱们换个别的,反正这次重点在于ROS编写上。
既然上面我们把基本框架都搭建完了,那么理论上只需要找个能跑的脚本就可以了,思来想去,考虑到综合使用频率和实用性,我这里还是决定来试一试部署Dify。
这里在查安装方法的时候,突然看到阿里的ROS官方已经发过一篇了。。。。流汗黄豆。。。
整体的内容也是大差不差,区别就在于Dify的本地编译很方便,而MaxKB需要规定版本的python环境,很麻烦。
ROSTemplateFormatVersion: '2015-09-01'
Description:en: Build the large language model (LLM) application development platform Dify onthe ECS instance (CentOS 7).zh-cn: 在ECS实例(CentOS 7)上搭建大语言模型(LLM) 应用开发平台Dify。
Parameters:ZoneId:Type: StringLabel:en: Availability Zonezh-cn: 可用区IDAssociationProperty: ALIYUN::ECS::Instance:ZoneIdInstanceType:Type: StringLabel:en: Instance Typezh-cn: 实例类型AssociationProperty: ALIYUN::ECS::Instance::InstanceTypeAssociationPropertyMetadata:ZoneId: ${ZoneId}DefaultValueStrategy: recentSystemDiskCategory:Type: StringLabel:en: System Disk Typezh-cn: 系统盘类型AssociationProperty: ALIYUN::ECS::Disk::SystemDiskCategoryAssociationPropertyMetadata:LocaleKey: DiskCategoryZoneId: ${ZoneId}InstanceType: ${InstanceType}AutoSelectFirst: trueAutoChangeType: falseDefault: cloud_essdInstancePassword:Type: StringLabel:en: Instance Passwordzh-cn: 实例密码Description:en: Server login password, Length 8-30, must contain three(Capital letters,lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbolin).zh-cn: 服务器登录密码,长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)。ConstraintDescription:en: Length 8-30, must contain three(Capital letters, lowercase letters, numbers,()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in).zh-cn: 长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)。AssociationPropertyMetadata:Visible:Condition:Fn::Equals:- ${SelectInstance}- falseDefault:AllowedPattern: '[0-9A-Za-z\_\-\&:;''<>,=%`~!@#\(\)\$\^\*\+\|\{\}\[\]\.\?\/]+$'MinLength: 8MaxLength: 30NoEcho: true
Resources:Vpc:Type: ALIYUN::ECS::VPCProperties:CidrBlock: 192.168.0.0/16VSwitch:Type: ALIYUN::ECS::VSwitchProperties:ZoneId:Ref: ZoneIdVpcId:Ref: VpcCidrBlock: 192.168.0.0/24SecurityGroup:Type: ALIYUN::ECS::SecurityGroupProperties:VpcId:Ref: VpcSecurityGroupIngress_80:Type: ALIYUN::ECS::SecurityGroupIngressProperties:SecurityGroupId:Ref: SecurityGroupSourceCidrIp: 0.0.0.0/0IpProtocol: tcpNicType: intranetPortRange: 80/80InstanceGroup:Type: ALIYUN::ECS::InstanceGroupProperties:VpcId:Ref: VpcVSwitchId:Ref: VSwitchSecurityGroupId:Ref: SecurityGroupImageId: centos_7_9InstanceName: difyInstanceType:Ref: InstanceTypeSystemDiskCategory:Ref: SystemDiskCategoryPassword:Ref: InstancePasswordIoOptimized: optimizedMaxAmount: 1DS_Instances:Type: DATASOURCE::ECS::InstancesProperties:InstanceIds:Fn::GetAtt:- InstanceGroup- InstanceIdsInstallDify:Type: ALIYUN::ECS::RunCommandProperties:InstanceIds:Fn::GetAtt:- InstanceGroup- InstanceIdsType: RunShellScriptSync: trueTimeout: 1800CommandContent: |#!/bin/bashecho "#########################"echo "# Install Docker"echo "#########################"wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repoyum -y install docker-cesystemctl start dockersystemctl enable dockerecho "#########################"echo "# Install Dify"echo "#########################"yum -y install gitgit clone --depth 1 https://github.com/langgenius/dify.git /opt/difycd /opt/dify/dockerdocker compose up -ddocker compose ps
Outputs:DifyUrl:Description: Dify default address.Value:Fn::Sub:- http://${IP}- IP:Fn::Jq:- First- if .[0].PublicIpAddress != [] then .[0].PublicIpAddress[0] else .[0].EipAddress.IpAddressend- Fn::GetAtt:- DS_Instances- Instances
Metadata:ALIYUN::ROS::Interface:TemplateTags:- acs:developer:gitee:0147-在ECS实例上搭建大语言模型的知识库问答系统MaxKB
最后结果是创建成功了,但是网站打不开,我一查日志,给我看笑了。
官方文档给出的部署方式同样出现了docker超时的情况,这下估计docker真指望不到了。
离了个大谱,还是自己来吧。
先写了个部署nginx的脚本:
#!/bin/bash
#提前解决编译时所需的依赖环境、库文件;
yum install -y wget gzip gcc tar make
yum install -y pcre pcre-devel zlib-devel
#下载Nginx软件包;
wget -c http://nginx.org/download/nginx-1.24.0.tar.gz -P /usr/src/
#Cd切换/usr/src/;
cd /usr/src/
ls -l nginx-1.24.0.tar.gz
#通过Tar工具对其解压;
tar -xzvf nginx-1.24.0.tar.gz
#Cd切换至Nginx源代码目录;
cd nginx-1.24.0/
#提前创建www用户和组;
useradd -s /sbin/nologin www -M
#预编译;
./configure --prefix=/usr/local/nginx/ --user=www --group=www --with-http_stub_status_module
#编译;
make -j4
#安装;
make -j4 install
#查看Nginx软件服务是否部署成功;
ls -l /usr/local/nginx/
#启动Nginx服务进程;
/usr/local/nginx/sbin/nginx
#查看Nginx进程状态;
ps -ef|grep -aiE nginx
#Firewalld防火墙对外开放80端口;
firewall-cmd --add-port=80/tcp --permanent
systemctl reload firewalld.service
直接丢里面执行,部署完了如下所示:
这里可以看到nginx还是部署成功了的,看来只是docker存在一些莫名奇妙的问题罢了。将这里的nginx脚本替换之前的MaxKB或者Dify的shell脚本处,勉强算是制作出第一个ROS脚本了,虽然一点用处都没有。。。
总结
如果不是这次亲手尝试来写ROS脚本也没想到会碰到那么多问题,本来其实听起来很简单的,整个逻辑也能理解,但是实际上手后,由于不熟悉,搞得这也是问题那也是问题,反反复复折腾。
第二点就是,官网上给的脚本居然也会出现执行错误的情况,这是我没想到的。
不过,也正是这些问题和挑战,让我深刻体会到了理论与实践之间的差距,也促使我更加深入地学习和探索。每解决一个问题,都是对云计算领域理解的一次深化,对ROS及背后资源编排理念的掌握也愈发熟练。
过程充满挑战,但每一次解决问题都是一次宝贵的学习机会,让我的技术栈更加坚实,也让我在云原生和DevOps的道路上迈出了坚实的一步。这种从实战中获得的经验,是任何教科书或理论学习都无法替代的。
2024年7月13日更新
昨晚研究了一晚,又写了一个部署2048游戏的ROS脚本。
ROSTemplateFormatVersion: '2015-09-01'
Description:en: Set up the 2048 game on an ECS instance..zh-cn: 在ECS实例上搭建2048小游戏。
Parameters:ZoneId:Type: StringLabel:en: Availability Zonezh-cn: 可用区IDAssociationProperty: ALIYUN::ECS::Instance:ZoneIdInstanceType:Type: StringLabel:en: Instance Typezh-cn: 实例类型AssociationProperty: ALIYUN::ECS::Instance::InstanceTypeAssociationPropertyMetadata:ZoneId: ${ZoneId}DefaultValueStrategy: ecs.e-c1m2.large
Resources:Vpc:Type: ALIYUN::ECS::VPCProperties:CidrBlock: 192.168.0.0/16VSwitch:Type: ALIYUN::ECS::VSwitchProperties:ZoneId:Ref: ZoneIdVpcId:Ref: VpcCidrBlock: 192.168.0.0/24SecurityGroup:Type: ALIYUN::ECS::SecurityGroupProperties:VpcId:Ref: VpcSecurityGroupIngress_80:Type: ALIYUN::ECS::SecurityGroupIngressProperties:SecurityGroupId:Ref: SecurityGroupSourceCidrIp: 0.0.0.0/0IpProtocol: tcpNicType: intranetPortRange: 80/80InstanceGroup:Type: ALIYUN::ECS::InstanceGroupProperties:VpcId:Ref: VpcVSwitchId:Ref: VSwitchSecurityGroupId:Ref: SecurityGroupImageId: centos_7_9InstanceName: GAMEInstanceType:Ref: InstanceTypeSystemDiskCategory : cloud_essdIoOptimized: optimizedMaxAmount: 2DS_Instances:Type: DATASOURCE::ECS::InstancesProperties:InstanceIds:Fn::GetAtt:- InstanceGroup- InstanceIdsInstallGAME:Type: ALIYUN::ECS::RunCommandProperties:InstanceIds:Fn::GetAtt:- InstanceGroup- InstanceIdsType: RunShellScriptSync: trueTimeout: 1800CommandContent: |#!/bin/bashyum install -y httpd wgetsystemctl start httpdwget 'https://computenest-artifacts-cn-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/1853370294850618/cn-beijing/1697533575326/2048.tgz' -O 2048.tgztar xvf 2048.tgzmv 2048/* /var/www/html && rm -rf 2048Outputs:GAMEUrl:Description: GAME default address.Value:Fn::Sub:- http://${IP}- IP:Fn::Jq:- First- if .[0].PublicIpAddress != [] then .[0].PublicIpAddress[0] else .[0].EipAddress.IpAddressend- Fn::GetAtt:- DS_Instances- Instances
Metadata:ALIYUN::ROS::Interface:TemplateTags:- acs:developer:gitee:0147-在ECS实例上搭建2048小游戏
这里实测是完全没有任何问题的。
下面我把脚本上传到我的gitee中,新建一个仓库,命名为阿里云ROS:
由于只有一个脚本,所以直接创建文件然后复制进去就可以了:
最终地址如下:
我们来尝试直接一键部署,前面引入ROS的部署的链接地址:
https://ros.console.aliyun.com/region/stacks/create?hideStepRow=true&hideStackConfig=true&disableRollback=false&isSimplified=true&disableNarue&productNavBar=disabled&templateUrl=
后面拼接自己的gitee地址:
https://gitee.com/a156da16/aliyunros/blob/master/GAME.yaml
所以最终一键部署链接如下:
https://ros.console.aliyun.com/cn-hangzhou/stacks/create?hideStepRow=true&hideStackConfig=true&disableRollback=false&isSimplified=true&disableNarue&productNavBar=disabled&templateUrl=https://gitee.com/a156da16/aliyunros/blob/master/GAME.yaml
尝试了一下,有个很逆天的地方,一直显示访问被拒绝。具体原因也一直没找到,在群里找专家问了:
为了避免版本不一致,我直接复制gitee里上传的那个版本,进入ROS中进行创建,是能够识别模板参数的:
但是通过官方给的链接就是一直报错。。。
这篇就这样吧,反正总之把脚本也是写出来了,刚开始接触不是很熟悉,只能从简单的开始了。
相关文章:

记一次饱经挫折的阿里云ROS部署经历
前言 最近在参加的几个项目测评里,我发现**“一键部署”这功能真心好用,省下了不少宝贵时间和力气,再加上看到阿里云现在有个开源上云**的活动。趁着这波热潮,今天就聊聊怎么从头开始,一步步搞定阿里云的资源编排服务…...

代码运行故障排除:PyCharm中的问题解决指南
代码运行故障排除:PyCharm中的问题解决指南 引言 PyCharm,作为一款流行的集成开发环境(IDE),提供了强大的工具来支持Python开发。然而,即使是最先进的IDE也可能遇到代码无法运行的问题。这些问题可能由多…...

css实现渐进中嵌套渐进的方法
这是我们想要的实现效果: 思路: 1.有一个底色的背景渐变 2.需要几个小的块级元素做绝对定位通过渐变filter模糊来实现 注意:这里的采用的定位方法,所以在内部的元素一律要使用绝对定位,否则会出现层级的问题&…...

JavaWeb后端学习
Web:全球局域网,万维网,能通过浏览器访问的网站 Maven Apache旗下的一个开源项目,是一款用于管理和构建Java项目的工具 作用: 依赖管理:方便快捷的管理项目以来的资源(jar包)&am…...

VUE_TypeError: Cannot convert a BigInt value to a number at Math.pow 解决方法
错误信息 TypeError: Cannot convert a BigInt value to a number at Math.pow vue 或 react package.json添加 "browserslist": {"production": ["chrome > 67","edge > 79","firefox > 68","opera >…...

Linux下mysql数据库的导入与导出以及查看端口
一:Linux下导出数据库 1、基础导出 要在Linux系统中将MySQL数据库导出,通常使用mysqldump命令行工具。以下是一个基本的命令示例,用于导出整个数据库: mysqldump -u username -p database_name > export_filename.sql 其中&a…...

Open3d入门 一文读懂三维点云
三维点云技术的发展始于20世纪60年代,随着激光雷达和三维扫描技术的进步,在建筑、考古、地理信息系统和制造等领域得到了广泛应用。20世纪90年代,随着计算机处理能力的提升,点云数据的采集和处理变得更加高效,推动了自…...

pyinstaller系列教程(一)-基础介绍
1.介绍 PyInstaller是一个用于将Python应用程序打包为独立可执行文件的工具,它支持跨平台操作,包括Windows、Linux和MacOS等操作系统。特点如下: 跨平台支持:PyInstaller可以在多个操作系统上运行,并生成相应平台的可…...

echarts图表:类目轴
category 类目轴,适用于离散的类目数据。 例如商品名称、时间等。 类目轴上的每个刻度代表一个类目,刻度之间没有量的关系,只是简单的分类。 在类目轴上,数据点会对应到相应的类目上。...

SSM贫困生申请管理系统-计算机源码84308
摘要 随着教育信息化的不断推进,越来越多的高校开始借助信息技术手段提升贫困生申请管理的效率与准确性。为此,我们设计并实现了SSM贫困生申请管理系统,旨在通过信息化手段优化贫困生申请流程,提高管理效率,为贫困生提…...

[C++]——同步异步日志系统(5)
同步异步日志系统 一、日志消息格式化设计1.1 格式化子项类的定义和实现1.2 格式化类的定义和实现 二、日志落地类设计2.1 日志落地模块功能实现与测试2.2 日志落地模块功能功能扩展 一、日志消息格式化设计 日志格式化模块的作用:对日志消息进行格式化,…...

Qt项目:基于Qt实现的网络聊天室---TCP服务器和token验证
文章目录 TCP服务器设计客户端TCP管理者ChatServerAsioIOServicePoolSession层LogicSystem总结 token验证模块完善protoStatusServer验证token客户端处理登陆回包用户管理登陆界面 本篇完成的模块是TCP服务器的设计和token验证 TCP服务器设计 客户端TCP管理者 因为聊天服务要…...

深入理解C++构造函数
目录 1.引言 2.默认构造函数 3.自定义构造函数 4.带继承关系类的构造函数 5.带多重继承关系类的构造函数 6.带虚继承关系类的构造函数 7.总结 1.引言 对于学过C的来说,构造函数是非常熟悉不过的了。但是你真正了解它吗?构造函数内部初始化变量的顺…...

J025_斗地主游戏案例开发(简版)
一、需求描述 完成斗地主游戏的案例开发。 业务:总共有54张牌; 点数:3、4、5、6、7、8、9、10、J、Q、K、A、2 花色:黑桃、红桃、方片、梅花 大小王:大王、小王 点数分别要组合4种花色,大小王各一张。…...

路径规划 | 飞蛾扑火算法求解二维栅格路径规划(Matlab)
目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 路径规划 | 飞蛾扑火算法求解二维栅格路径规划(Matlab)。 飞蛾扑火算法(Firefly Algorithm)是一种基于自然界萤火虫行为的优化算法,在路径规划问题中也可以应…...

优化Cocos Creator 包体体积
优化Cocos Creator 包体体积 引言一、优化图片文件体积:二、优化声音文件体积:三、优化引擎代码体积:四、 优化字体字库文件大小: 引言 优化Cocos Creator项目的包体体积是一个常见且重要的任务,尤其是在移动设备和网…...

TCPDump协议分析工具
TCPDump协议分析工具 TCPDump是一个强大的命令行工具,用于捕获和分析网络数据包。它能够实时监控和记录网络流量,帮助网络管理员和安全专家排查网络问题、分析流量和检测网络攻击。以下是TCPDump的详细介绍,包括其安装、基本使用、过滤规则和…...

土壤分析仪:解密土壤之奥秘的科技先锋
在农业生产和生态保护的道路上,土壤的质量与状况一直是我们关注的焦点。土壤分析仪,作为现代科技在农业和环保领域的杰出代表,以其高效、精准的分析能力,为我们揭示了土壤的奥秘,为农业生产提供了科学指导,…...

计算1的数量
1. 计算1的数量 题目ID:9809必做题100分 最新提交: Accepted 100 分 历史最高: Accepted 100 分 时间限制: 1000ms 空间限制: 524288kB 题目描述 给定一个n*m的二进制矩阵,请你数一数矩阵中完全被0上下左右包围的1的数…...

Linux udp编程
我最近开了几个专栏,诚信互三! > |||《算法专栏》::刷题教程来自网站《代码随想录》。||| > |||《C专栏》::记录我学习C的经历,看完你一定会有收获。||| > |||《Linux专栏》࿱…...

【开源项目】Rust开发复制文件夹目录结构工具
说明 由于我经常需要在多个大容量的移动硬盘中查找和新增文件,我希望把硬盘的目录结构放到服务器的自建网盘中,因此开发了这个工具,使得在不同硬盘之间的文件管理变得更加便捷 项目地址:https://github.com/VinciYan/folder_clon…...

PostgreSQL的pg_dirtyread工具
PostgreSQL的pg_dirtyread工具 pg_dirtyread 是一个第三方PostgreSQL扩展,它允许用户读取数据库文件中的“脏”数据,即那些被标记为删除或不再可见的数据。这个扩展对于数据恢复和调试非常有用,尤其是在需要恢复被删除或更新前的数据时。 以…...

苹果梦碎:Vision Pro的辉煌与失落,苹果已决定暂停 Vision Pro 后续产品的研发工作
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点 苹果Vision Pro:科技巨头的跌宕起伏 在科技的海洋中,苹果公司一直以其创新精神和卓越品质引领潮流。然而,即…...

推荐一款uniapp拖动验证码插件
插件地址:易盾验证码 - DCloud 插件市场 具体使用方式访问插件地址自行获取...

十年期国债收益率
十年期国债收益率是指政府发行的、期限为十年的国债的年化收益率。它被广泛视为一个国家经济健康状况和未来经济前景的重要指标,同时也是金融市场中的一个重要基准利率。 下面我将详细解释十年期国债收益率的相关内容及其意义。 十年期国债收益率的意义 经济健康的…...

使用Go编写的持续下行测速脚本,快速消耗流量且不伤硬盘
GoSpeed 声明 此工具仅用于测试与学习,请勿用于非法用途,如使用此程序请确保所有下载的内容都拥有合法的使用权或分发权,避免侵犯版权、恶意访问 此工具仅用于测试与学习,请勿用于非法用途,如使用此程序请确保所有下载的内容都拥有合法的使用权或分发权,…...

保护国外使用代理IP的安全方法
为了保护在国外使用代理IP的安全,用户可以采取以下方法: 1. 选择可信的代理服务器 在选择代理服务器时,用户应该选择那些经过验证和信任的服务器,如知名的VPN服务提供商。这些服务器通常具有更高的安全性和隐私保护措施。 2. 使用…...

18集 学习ESP32的ESP-DL深度学习教程-《MCU嵌入式AI开发笔记》
18集 学习ESP32的ESP-DL深度学习教程-《MCU嵌入式AI开发笔记》 参考文档:https://docs.espressif.com/projects/esp-dl/zh_CN/latest/esp32/tutorials/index.html 使用TVM自动生成模型部署项目 本案例介绍了使用 TVM 部署模型的完整流程。 该项目基于 TVM v0.14…...

jmeter-beanshell学习9-放弃beanshell
写这篇时候道心不稳了,前面写了好几篇benashell元件,突然发现应该放弃。想回去改前面的文章,看了看无从下手,反正已经这样了,我淋了雨,那就希望别人也没有伞吧,哈哈哈哈,放在第九篇送…...

Web 性能入门指南-1.5 创建 Web 性能优化文化的最佳实践
最成功的网站都有什么共同点?那就是他们都有很强的网站性能和可用性文化。以下是一些经过验证的有效技巧和最佳实践,可帮助您建立健康、快乐、值得庆祝的性能文化。 创建强大的性能优化文化意味着在你的公司或团队中创建一个如下所示的反馈循环ÿ…...