作者: 金湛
前言
资源编排服务ROS(Resource Orchestration Service)是阿里云提供的一项简化云计算资源管理的服务。开发者和管理员可以编写模板,在模板中定义所需的阿里云资源(例如:ECS实例、RDS数据库实例)、资源间的依赖关系等。ROS的编排引擎将根据模板自动完成所有资源的创建和配置,实现自动化部署及运维。
🪶为什么选择ROS资源编排
企业云上大量的资源管理需求带来了效率、合规和成本方面的挑战,ROS可以帮助您轻松管理多个资源:
- 采用基础设施即代码(Infrastructure as Code, IaC)的设计理念,模板的管理融入CI/CD流程,确保合规性。
- 无需手动创建多个资源,使用模板一键部署多个资源。
- 提供大量模板示例和解决方案示例,帮助企业客户部署复杂解决方案。
- 利用云上弹性,按需批量部署和释放资源,节省成本。
本文将以一个小白视角,探索如何根据阿里云的文档从0开始写一篇ROS资源编排的代码。
1️⃣Part1: 工具准备
注:本次教程所有的操作均基于macos,其他平台的操作请自行稍作修改
1. ROS CDK安装
阿里云ROS CDK(Cloud Development Toolkit)是资源编排(ROS)提供的一种命令行工具,帮助您使用多种编程语言定义云资源。您无需使用繁琐的JSON或YAML模板语法,即可使用ROS CDK完成资源的创建和配置,实现自动化部署及运维。写一篇ROS自动化测试脚本的第一步是安装ROS CDK工具。如何安装ROS在帮助文档中已经写得非常详细。
https://help.aliyun.com/zh/ros/developer-reference/install-ros-cdk?spm=a2c4g.11186623.0.i1
2. python环境安装
a. 使用Anaconda(推荐)
ⅰ. 开源、免费,强大的python环境管理软件,社区版包含很多常用软件
ⅱ. 简单、方便的环境隔离与虚拟环境创建
ⅲ. Anaconda 还附带了一个叫做 Navigator(导航)的桌面 GUI 工具,可以直观地创建和管理环境,安装、删除扩展包
ⅳ. 下载链接:https://repo.anaconda.com/archive/Anaconda3-2023.09-0-MacOSX-arm64.pkg
b. 直接安装python
ⅰ. 下载链接:https://www.python.org/downloads/release/python-3120/
3. IDE、代码编辑器推荐
a. VScode(推荐)
ⅰ. 开源免费、轻量的代码编辑器
ⅱ. 社区生态好、更新快
ⅲ. 插件生态众多,推荐部分插件
- Python
- Atom Material Icons
- GitLens --- Git supercharged
- IntelliCode
b. pycharm
ⅰ. 开箱即用、功能强大的IDE
ⅱ. 补全、代码检查等功能做得较好
ⅲ. 下载链接:https://download.jetbrains.com.cn/python/pycharm-community-2023.2.4-aarch64.dmg
4. AI编码插件
使用AI编码插件可以大幅提升代码编写效率,最经典的插件是Github Copilot,功能包括行/函数级自动续写、自然语言生成代码、生成单元测试、生成代码注释等等,然而这是一个收费插件(10美元/月),有很多免费版的插件可以平替,这里推荐几个
a. 通义灵码
ⅰ. 通义千问系列产品,目前已经开放公测,阿里云账号可以直接使用
ⅱ. 功能简介与下载链接:https://tongyi.aliyun.com/lingma
ⅲ. 代码解释,询问一段代码是什么意思,帮忙理解代码逻辑,这里给出一段阿里云ROS的代码,但是插件给出的解释是AWS的CDK,但是除了这一点错误,其余的代码解释都是正确的
ⅳ. AI代码生成(根据注释生成代码),这里我只写了注释「#创建安全组」,插件自动帮我生成了一段代码来放开80端口
b. Amazon CodeWhisperer
ⅰ. AWS出品的AI编码工具,免费
ⅱ. 功能简介与下载链接:https://aws.amazon.com/cn/codewhisperer/
c. CodeGeeX
ⅰ. 模型开源:https://github.com/THUDM/CodeGeeX2
ⅱ. 功能简介与下载链接:https://codegeex.cn/
2️⃣Part2: 环境准备
1. 创建工程目录并初始化工程
进入终端,执行以下命令,创建工程目录并初始化工程。每个ROS CDK应用都要求创建在一个独立的工程目录下,且该应用需要使用独立工程目录中模块的依赖项。所以在创建应用之前,需要先创建一个工程目录并进行初始化。
#创建iac-ros-cdk文件夹
mkdir iac-ros-cdk
#进入iac-ros-cdk文件夹
cd iac-ros-cdk
#使用ros cdk初始化项目
ros-cdk init --language=python --generate-only=true
2. 创建虚拟环境
Python工程的运行依赖于虚拟环境(virtualenv),所以在初始化Python工程之后需要创建一个属于当前工程的虚拟环境。
python3 -m venv .venv
3. 进入虚拟环境
source .venv/bin/activate
4. 测试环境是否创建成功
在终端执行以下命令,测试环境是否创建成功
python
若出现此界面则说明你的虚拟环境已经创建成功,此时的项目应该是这样的
5. 在编译器中配置环境
打开项目中的一个示例python文件「iac_ros_cdk_stack.py」,在VScode中选择python解释器,开始编写python代码
6. 安装需要的包
此时无法解析编译器无法解析「ros_cdk_core」,表明当前python环境「.venv」里没有这个包
在VScode中新建终端,终端会自动执行命令切换到当前目录并激活「.venv」环境
将pip源换成清华大学的源,加速pip安装包的速度(可选),然后执行pip install xx,在「.venv」环境中安装包
示例,换源并安装「ros_cdk_core」这个包
以上安装方式对应的是单次安装一个包的情况,如果你需要安装很多包,可以在「requirements.txt」中添加你需要的包
然后在终端中执行如下命令来安装「requirements.txt」中写的所有包
#安装requirements.txt中写的包
pip install -r requirements.txt
7. 配置阿里云凭证信息
# 将pip的源换为国内的清华源,加速下载,这一步为可选项
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
# 安装ros_cdk_core
pip install ros_cdk_core
登录阿里云官网,获取当前账号的AK信息
执行以下命令,配置阿里云凭证信息。
ros-cdk config
根据界面提示输入配置信息。
endpoint(optional, default:https://ros.aliyuncs.com):
defaultRegionId(optional, default:cn-hangzhou):cn-hangzhou
[1] AK
[2] StsToken
[3] RamRoleArn
[4] EcsRamRole
[0] CANCEL
Authenticate mode [1...4 / 0]: 1
accessKeyId:************************
accessKeySecret:******************************
✅ Your cdk configuration has been saved successfully!
配置内容说明:
- endpoint:ROS服务地址。默认值为https://ros.aliyuncs.com。
- defaultRegionId:ROS资源栈部署的地域。默认值为cn-hangzhou。
- Authenticate mode:鉴权方式。本示例的鉴权方式为AccessKey,您需要输入AccessKey ID和AccessKey Secret。关于如何获取AccessKey,请参见交互式配置(快速配置)。
3️⃣Part3: 代码编写演示
1. 代码文件建立与命名规范
找到需要转成 CDK 的技术解决方案文档,这里有一个示例
完整代码如下
新建文件,可注意以下规范
-
文件正确归类---计算的ROS代码应该放在ECS目录下
-
文件正确命名---deploy_FTP_on_ECS_460772.py
- 「deploy_FTP_on_ECS」描述文档测试内容,在ECS上部署FTP服务
- 「460772」该文档的id
-
类的正确命名
- 类名应遵循 CapWords 约定 (https://copyprogramming.com/howto/capwords-conventions-get-myclass-or-get-my-class)
- 类名应该能体现当前类的功能,比如「DeployFTP」
2. 找寻文档描述的前提条件
一般文档会描述实验前需要部署的资源,比如本篇文档规定了以下内容
- 实例规格:ecs.g6.large
- 操作系统:Alibaba Cloud Linux 3.2104 LTS 64位
现在已经知道需要首先建立一个ECS,建立ECS需要以下依赖资源
- VPC
- Vswitch
- 安全组
那么已经可以明确你的ROS代码需要编排的资源清单
3. 分步骤编写代码
如果是没用过的资源怎么找必填参数、怎么填写参数(通过文档,比如https://help.aliyun.com/zh/ros/developer-reference/datasource-cs-clusternodepools)
a. 建立VPC
python
# 创建VPC
vpc = ecs.Vpc(
self,
"VPC",
ecs.VPCProps(
cidr_block="10.0.0.0/8",
vpc_name="ftp-ros-cdk-vpc",
description="This is ros python cdk from jinzhan",
),
)
b. 建立VSwitch
python
# 创建交换机
vswitch = ecs.VSwitch(
self,
"VSwitch",
ecs.VSwitchProps(
zone_id=zone_id_param,
vpc_id=vpc.resource.ref,
cidr_block="10.0.0.0/20",
),
)
c. 创建ECS
ⅰ. 首先定义ECS的密码
python
# 设置ECS实例密码
ecs_password_param = core.RosParameter(
self,
"ECS_password",
type=core.RosParameterType.STRING,
association_property="ALIYUN::ECS::Instance::Password",
default_value="Jinz_Aliyun1",
)
ⅱ. 定义ECS使用的镜像
python
# 设置ECS实例镜像
image_id_param = core.RosParameter(
self,
"ImageId",
default_value="aliyun_3_x64_20G_alibase_20230629.vhd",
type=core.RosParameterType.STRING,
description={"zh-cn": "镜像ID", "en": "Image ID"},
label="公共镜像Alibaba Cloud Linux 3.2104 LTS 64位",
)
ⅲ. 设置ECS的实例类型
python
# 设置ECS实例类型
instance_type_param = core.RosParameter(
self,
"InstanceType",
association_property="ALIYUN::ECS::Instance::InstanceType",
association_property_metadata={"ZoneId": "ZoneId"},
default_value="ecs.g6.large",
label="Instance Type",
type=core.RosParameterType.STRING,
description={},
)
ⅳ. 设置ECS的区域
python
# 地区id类型
zone_id_param = core.RosParameter(
self,
"ZoneId",
type=core.RosParameterType.STRING,
association_property="ALIYUN::ECS::Instance::ZoneId",
default_value="cn-hangzhou-k",
)
ⅴ. 创建ECS实例,按照文档的要求在ECS上执行命令
python
# 创建ECS实例
ecs_instance = ecs.Instance(
self,
"ECS-demo",
ecs.InstanceProps(
instance_name="ecs-jinzhan-agent-ros-python-cdk",
vpc_id=vpc.resource.ref,
v_switch_id=vswitch.resource.ref,
security_group_id=sg.resource.ref,
image_id=image_id_param,
instance_type=instance_type_param,
instance_charge_type="PayAsYouGo",
password=ecs_password_param,
allocate_public_ip=True,
user_data=core.FnReplace(
value=[
{"ros-notify": wait_condition_handle_param.attr_curl_cli},
{
"Fn::Join": [
"",
[
"#!/bin/bash\n",
"dnf install -y vsftpd\n",
"systemctl enable vsftpd.service\n",
"systemctl start vsftpd.service\n",
"netstat -antup | grep ftp\n",
"adduser ftptest\n",
# 将ftp用户密码设置为abc123
"sudo chpasswd <<< "ftptest:abc123"\n",
"mkdir /var/ftp/test\n",
"touch /var/ftp/test/testfile.txt\n",
"chown -R ftptest:ftptest /var/ftp/test\n",
"sudo echo '#!/bin/bash' | sudo tee update_vsftpd_conf.sh\n",
'''sudo echo 'if [ -f "/etc/vsftpd/vsftpd.conf" ]; then \n sed -i "s/^anonymous_enable=.*/anonymous_enable=NO/" /etc/vsftpd/vsftpd.conf \n sed -i "s/^local_enable=.*/local_enable=YES/" /etc/vsftpd/vsftpd.conf\n sed -i "s/^listen=.*/listen=YES/" /etc/vsftpd/vsftpd.conf\n echo "修改成功!"\nelse\n echo "vsftpd.conf文件不存在。"\nfi' | sudo tee -a update_vsftpd_conf.sh'''
"\n",
"sudo chmod +x update_vsftpd_conf.sh\n",
"sudo ./update_vsftpd_conf.sh\n",
# 在行首添加#注释掉listen_ipv6=YES,关闭监听IPv6 sockets
"sudo sed -i 's/^listen_ipv6=YES/#&/' /etc/vsftpd/vsftpd.conf\n",
"sudo tee -a /etc/vsftpd/vsftpd.conf << EOF\n",
"#设置本地用户登录后所在目录。\n"
"local_root=/var/ftp/test\n",
"#全部用户被限制在主目录。\n",
"chroot_local_user=YES\n",
"#启用例外用户名单。\n",
"chroot_list_enable=YES\n",
"#指定例外用户列表文件,列表中用户不被锁定在主目录。\n",
"chroot_list_file=/etc/vsftpd/chroot_list\n",
"#开启被动模式。\n",
"pasv_enable=YES\n",
"allow_writeable_chroot=YES\n",
"#本教程中为Linux实例的公网IP。\n",
"EOF\n",
# 创建update_vsftpd_conf_ip.sh脚本,将获取本机ip并替换pasv_address=<本机ftp地址>
"echo '#!/bin/bash' > update_vsftpd_conf_ip.sh\n",
"echo '' >> update_vsftpd_conf_ip.sh\n",
"echo 'public_ip=$(curl -s ifconfig.me)' >> update_vsftpd_conf_ip.sh\n"
"echo '' >> update_vsftpd_conf_ip.sh\n",
'''echo 'sudo sh -c "echo "pasv_address=$public_ip" >> /etc/vsftpd/vsftpd.conf"' >> update_vsftpd_conf_ip.sh\n''',
"echo '' >> update_vsftpd_conf_ip.sh\n",
"chmod +x update_vsftpd_conf_ip.sh\n",
"./update_vsftpd_conf_ip.sh\n",
"sudo tee -a /etc/vsftpd/vsftpd.conf << EOF\n",
"#设置被动模式下,建立数据传输可使用的端口范围的最小值。\n",
"#建议您把端口范围设置在一段比较高的范围内,例如50000~50010,有助于提高访问FTP服务器的安全性。\n",
"pasv_min_port=50000\n",
"#设置被动模式下,建立数据传输可使用的端口范围的最大值。\n",
"pasv_max_port=50010\n",
"EOF\n",
"touch /etc/vsftpd/chroot_list\n",
"systemctl restart vsftpd.service\n"
],
]
},
]
),
),
)
d. 创建安全组
python
# 创建安全组
sg = ecs.SecurityGroup(
self,
"SecurityGroup",
ecs.SecurityGroupProps(
vpc_id=vpc.resource.ref,
),
)
e. 添加安全组入方向端口
python
# 添加安全组入方向端口
sg_ingress_50000_50010 = ecs.SecurityGroupIngress(
self,
"SecurityGroupIngress_80",
ecs.SecurityGroupIngressProps(
security_group_id=sg.resource.ref,
source_cidr_ip="0.0.0.0/0",
ip_protocol="tcp",
nic_type="intranet",
port_range="50000/50010",
),
)
sg_ingress_21 = ecs.SecurityGroupIngress(
self,
"SecurityGroupIngress_8080",
ecs.SecurityGroupIngressProps(
security_group_id=sg.resource.ref,
source_cidr_ip="0.0.0.0/0",
ip_protocol="tcp",
nic_type="intranet",
port_range="21/21",
),
)
sg_ingress_22 = ecs.SecurityGroupIngress(
self,
"SecurityGroupIngress_22",
ecs.SecurityGroupIngressProps(
security_group_id=sg.resource.ref,
source_cidr_ip="0.0.0.0/0",
ip_protocol="tcp",
nic_type="intranet",
port_range="22/22",
),
)
f. 使用云助手运行命令
python
# 安全组:入方向添加安全组规则并放行50000/50010、22、21端口
install_ftp = ecs.RunCommand(
self,
"InstallFTP",
ecs.RunCommandProps(
instance_ids=[ecs_instance.attr_instance_id],
type="RunShellScript",
sync=True,
timeout=600,
command_content=""
),
)
# 如果开了安全组,才运行installftp
install_ftp.add_dependency(sg_ingress_50000_50010)
install_ftp.add_dependency(sg_ingress_22)
install_ftp.add_dependency(sg_ingress_21)
g. 添加输出
python
# Output
core.RosOutput(self, "FTP URL",
value=core.FnJoin("", ["ftp://", ecs_instance.attr_public_ip, ":21"]), description="FTP User:ftptest, FTP Password:abc123, port:21, 50000/50010")
h. 更改app.py文件
修改app.py文件,导入你刚刚写好的文件,起个名字,这里起名叫「FTP-stack」
python
#!/usr/bin/env python3 ***
import ros_cdk_core as core
from python_cdk.ECS.deploy_FTP_on_ECS_460772 import DeployFTP
app = core.App()
DeployFTP(app, "FTP-stack")
app.synth()
4. 如何创建shell脚本来执行复杂命令
此文档中有一些复杂操作,无法使用简单的一两句命令来实现,这时候需要使用shell脚本来完成操作,例如这里需要使用vim来更改文件,在文件末尾添加参数并且注释某些行,显然这里已经无法使用简单的命令行来完成了。
这时候比较考验你的代码能力,如果你实在不清楚shell脚本怎么编写,这时候应该拿出我们的最强AI编码工具Chatgpt。使用Chatgpt来辅助我们编写代码。
此时GPT给出了一个实现此功能的脚本,但是此脚本需要你手动创建文件,在ROS中我们需要纯命令完成,那要如何解决?
现在gpt给出了纯命令行版本,你只需要将这段命令添加上引号,按照python中的代码规范填入user_data中,这段任务就完成了。其他比较复杂的操作类似
4️⃣Part4: 使用代码部署资源
1. 使用ROS CDK部署资源
打开终端,执行如下命令,其中「FTP-stack」是你在app.py中起的名字
ros-cdk synth FTP-stack -j
ros-cdk deploy FTP-stack --sync=true
看到如下输出说明第一行执行成功
看到如下输出说明第二行执行成功
2. 检查资源部署情况
从控制台打开资源编排,查看事件。如果你的资源状态没有任何回滚,说明至少此次的资源部署是成功的
5️⃣Part5: 验证任务是否完成
1. 进入ECS查询日志文件
连接你创建的ECS,执行如下命令,查看每一步命令是否都执行成功
less /var/log/cloud-init-output.log
比方说我此时看到的结果如下,认真查看发现没有报错,那可以暂时确定ECS上所有的命令都成功执行
2. 手动验证任务是否完成
此文档的最终目的是建立一个FTP服务器,那么需要我们手动验证服务器是否建立成功,文档原文如下
现在已经完成资源部署,ECS上的命令也已经按照文档全部执行完成。最后还需要手动验证一下FTP服务器是否建立成功,可以在自己的电脑上连接创立的FTP服务器,检查FTP服务是否正常运行
可以看到成功连接服务器,并且服务器上有文件,那么此次ROS文档测试完成。
3. 当你确定你此次任务完成,请及时销毁资源
ros-cdk destroy FTP-stack --sync=true
4. 将完成的代码更新推送到Github上
初次配置git
git常用命令
https://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html
# 初始化git
git init
# 将本地仓库与远程仓库关联
git remote add origin https://github.com/XiaoTianJianJun/ROS_JINZ_DEV/tree/master
# 创建名为jinz_dev的分支
git checkout -b jinz_dev
# 添加本次修改的内容
git add .
# 简要介绍一下本次修改的内容
git commit -m "Initial commit"
# 将更改推送到代码仓库
git push origin jinz_dev
6️⃣Part6: 弹药库
- ROS CDK官方文档是一个很好的学习途径
- OpenAPI CDK:cdk的代码示例可以查看openapi对应产品的cdk页面,可以动态根据输入参数输出运行示例
- 模版示例
- Chatgpt
总结
🪶核心内容:未接触过ROS资源部署的新人如何快速上手
-
全流程演示ROS资源编排:本文详细描述了从零开始完成一次ROS资源编排的代码编写的过程。它包含了可能遇到的大部分问题,并致力于让初学者也能够快速上手。
-
ROS的优势:ROS资源编排能够提高云资源的管理效率和稳定性,减少人工操作和错误,同时提供了可视化的监控和安全可靠的保障。
-
写代码遇到困难如何解决:
- 善用搜索引擎,自行解决问题
- 使用AI工具,提升编码效率
- 遇到不懂的问题时,积极向他人请教