本文主要介绍如何基于ROS CDK创建函数计算服务与函数,实现自定义资源的逻辑处理,且支持多种编程语言,包括TypeScript、JavaScript、Java、Python和C#。
费用说明
ROS CDK本身不收费,本方案中使用到的函数计算服务与ROS自定义函数也不会产生费用。
准备工作
请确保您已经完成以下操作:
安装和配置阿里云CLI、安装ROS CDK。具体操作,请参见安装ROS CDK。
获取AccessKey信息,用于后续授权。如果没有,请参见创建AccessKey。
开发语言环境要求 。
TypeScript:Node.js 8.0或更高版本。
JavaScript:JSON解析工具包(工具包名称为
jq
)。Java:JDK 1.8或以上版本、Maven 2.5或以上版本。
Python:Python 3.4以上版本。
C#:.NET Core 2.0以上版本、Visual Studio 2010 及以上版本。
步骤一:初始化工程
在命令行窗口依次输入以下命令,在当前目录创建并初始化工程。
mkdir demo
cd demo
ros-cdk init --language=typescript --generate-only=true
mkdir demo
cd demo
ros-cdk init --language=javascript --generate-only=true
mkdir demo
cd demo
ros-cdk init --language=java --generate-only=true
mkdir demo
cd demo
ros-cdk init --language=python --generate-only=true
执行以下命令,创建一个属于当前工程的虚拟环境。
Python工程的运行依赖于虚拟环境(virtualenv),所以在初始化Python工程之后需要创建一个属于当前工程的虚拟环境。
python3 -m venv .venv
执行以下命令,进入虚拟环境。
source .venv/bin/activate
mkdir demo
cd demo
ros-cdk init --language=csharp --generate-only=true
步骤二:配置阿里云凭证信息
在命令行窗口执行以下命令,配置阿里云凭证信息。
ros-cdk config
根据界面提示依次输入配置信息。
endpoint(optional, default:https://ros.aliyuncs.com): defaultRegionId(optional, default:cn-hangzhou):cn-beijing [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!
配置内容说明如下:
参数
说明
参数
说明
defaultRegionId
ROS资源栈部署的地域。默认值为
cn-hangzhou
。您可以调用DescribeRegionsAPI,获取RegionId参数选择地域。endpoint
ROS服务地址。默认值为
https://ros.aliyuncs.com
。您可以调用DescribeRegionsAPI,获取地域对应的公网接入地址或VPC接入地址,选择ROS服务地址,并添加https://
。Authenticate mode
鉴权方式。本示例的鉴权方式为[1] AK,您需要输入准备工作中获取的AccessKey ID和AccessKey Secret。更多鉴权方式,请参见配置凭证。
步骤三:安装依赖
在工程中修改配置文件,并安装依赖。
将
package.json
文件内容,全部更改为下面代码。{ "name": "demo", "version": "0.1.0", "bin": { "demo": "bin/demo.js" }, "scripts": { "build": "tsc", "test": "jest" }, "devDependencies": { "@types/jest": "^25.2.1", "@types/node": "10.17.5", "typescript": "^3.9.7", "jest": "^25.5.0", "ts-jest": "^25.3.1", "ts-node": "^8.1.0", "babel-jest": "^26.6.3", "@babel/core": "^7.12.9", "@babel/preset-env": "7.12.7", "@babel/preset-typescript": "^7.12.7", "@alicloud/ros-cdk-assert": "^1.4.0" }, "dependencies": { "@alicloud/ros-cdk-core": "^1.4.0", "@alicloud/ros-cdk-oss": "^1.4.0", "@alicloud/ros-cdk-ossdeployment": "^1.4.0" } }
在命令行窗口执行以下命令,安装依赖。
npm install
将
package.json
文件内容,全部更改为下面代码。{ "name": "demo", "version": "0.1.0", "bin": { "demo": "bin/demo.js" }, "scripts": { "build": "echo \"The build step is not required when using JavaScript!\" && exit 0", "cdk": "cdk", "test": "jest" }, "devDependencies": { "@types/jest": "^25.2.1", "@types/node": "10.17.5", "typescript": "^3.9.7", "jest": "^25.5.0", "ts-jest": "^25.3.1", "ts-node": "^8.1.0", "babel-jest": "^26.6.3", "@babel/core": "^7.12.9", "@babel/preset-env": "7.12.7", "@babel/preset-typescript": "^7.12.7", "@alicloud/ros-cdk-assert": "^1.0.25" }, "dependencies": { "@alicloud/ros-cdk-core": "^1.4.0", "@alicloud/ros-cdk-oss": "^1.4.0", "@alicloud/ros-cdk-ossdeployment": "^1.4.0" } }
在命令行窗口执行以下命令,安装依赖。
npm install
将
pom.xml
文件内容,全部更改为下面代码。<?xml version="1.0" encoding="UTF-8"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>com.myorg</groupId> <artifactId>demo</artifactId> <version>0.1</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <cdk.version>1.0.25</cdk.version> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.6.0</version> <configuration> <mainClass>com.myorg.DemoApp</mainClass> </configuration> </plugin> </plugins> </build> <dependencies> <!-- AliCloud ROS Cloud Development Kit (ROS CDK) --> <dependency> <groupId>com.aliyun</groupId> <artifactId>ros-cdk-core</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>ros-cdk-oss</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>ros-cdk-ossdeployment</artifactId> <version>1.4.0</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
执行以下命令,安装依赖:
mvn compile
将
requirements.txt
文件内容,全部更改为下面代码。ros-cdk-core==1.4.0 ros-cdk-oss==1.4.0 ros-cdk-ossdeployment==1.4.0
在命令行窗口执行以下命令,安装依赖。
pip install -r requirements.txt
将src/Demo/Demo.csproj
文件内容,全部更改为下面代码。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<!-- Roll forward to future major versions of the netcoreapp as needed -->
<RollForward>Major</RollForward>
</PropertyGroup>
<ItemGroup>
<!-- CDK Construct Library dependencies -->
<PackageReference Include="AlibabaCloud.SDK.ROS.CDK.Core" Version="1.4.0" />
<PackageReference Include="AlibabaCloud.SDK.ROS.CDK.Oss" Version="1.4.0" />
<PackageReference Include="AlibabaCloud.SDK.ROS.CDK.Ossdeployment" Version="1.4.0" />
<!-- jsii Roslyn analyzers (un-comment to obtain compile-time checks for missing required props
<PackageReference Include="Amazon.Jsii.Analyzers" Version="*" PrivateAssets="all" />
-->
</ItemGroup>
</Project>
步骤四:添加资源
为项目添加资源,本示例涉及到的资源有:
import * as ros from '@alicloud/ros-cdk-core';
import * as fc from '@alicloud/ros-cdk-fc3';
import * as ROS from '@alicloud/ros-cdk-ros';
export class DemoStack extends ros.Stack {
constructor(scope: ros.Construct, id: string, props?: ros.StackProps) {
super(scope, id, props);
new ros.RosInfo(this, ros.RosInfo.description, "This is the simple ros cdk app example.");
// The code that defines your stack goes here
const x = new ros.RosParameter(this, 'X', {
type: ros.RosParameterType.NUMBER,
});
const y = new ros.RosParameter(this, 'Y', {
type: ros.RosParameterType.NUMBER,
});
const function1 = new fc.Function(this, 'Function', {
functionName: 'mytest',
handler: 'index.handler',
runtime: 'python3',
code: {
sourceCode: `import time\nimport json\nimport urllib.request\nimport logging\n\ndef handler(event, context):\n logger = logging.getLogger()\n logger.setLevel(logging.INFO)\n event = json.loads(event)\n logger.info('receive request: %s', event)\n\n res_props = event['ResourceProperties']\n\n result = {\n 'RequestId': event['RequestId'],\n 'LogicalResourceId': event['LogicalResourceId'],\n 'StackId': event['StackId'],\n 'Status': 'SUCCESS',\n 'PhysicalResourceId': 'MyCustomResourceId',\n 'Data': {}\n }\n\n if event['RequestType'] != 'Delete':\n result['Data']['z'] = res_props['X'] + res_props['Y']\n\n headers = {\n 'Content-type': 'application/json',\n 'Accept': 'application/json',\n 'Date': time.strftime('%a, %d %b %Y %X GMT', time.gmtime()),\n 'User-Agent': 'MyCustomUserAgent'\n }\n\n req = urllib.request.Request(event['ResponseURL'], data=json.dumps(result).encode('utf-8'), headers=headers)\n resp = urllib.request.urlopen(req)\n resp_content = resp.read().decode('utf-8')\n logger.info('response: %s', resp_content)\n\n if resp.getcode() != 200:\n logger.error('Failed to send response, status code: %s', resp.getcode())\n else:\n logger.info('Response sent successfully')\n`
}
});
const customResource = new ROS.CustomResource(this, 'SimpleTest', {
timeout: 60,
serviceToken: function1.attrArn,
parameters: {
X: x.valueAsNumber,
Y: y.valueAsNumber
}
});
new ros.RosOutput(this, 'SimpleTestOutputs', {
value: customResource.attrOutputs
});
}
}
const ros = require('@alicloud/ros-cdk-core');
const ROS = require('@alicloud/ros-cdk-ros');
const fc = require('@alicloud/ros-cdk-fc3');
class DemoStack extends ros.Stack {
/**
*
* @param {ros.Construct} scope
* @param {string} id
* @param {ros.StackProps} props
*/
constructor(scope, id, props) {
super(scope, id, props);
new ros.RosInfo(this, ros.RosInfo.description, "This is the simple ros cdk app example.");
// The code that defines your stack goes here
const x = new ros.RosParameter(this, 'X', {
type: ros.RosParameterType.NUMBER
});
const y = new ros.RosParameter(this, 'Y', {
type: ros.RosParameterType.NUMBER,
});
const function1 = new fc.Function(this, 'Function', {
functionName: 'mytest',
handler: 'index.handler',
runtime: 'python3',
code: {
sourceCode: `import time\nimport json\nimport urllib.request\nimport logging\n\ndef handler(event, context):\n logger = logging.getLogger()\n logger.setLevel(logging.INFO)\n event = json.loads(event)\n logger.info('receive request: %s', event)\n\n res_props = event['ResourceProperties']\n\n result = {\n 'RequestId': event['RequestId'],\n 'LogicalResourceId': event['LogicalResourceId'],\n 'StackId': event['StackId'],\n 'Status': 'SUCCESS',\n 'PhysicalResourceId': 'MyCustomResourceId',\n 'Data': {}\n }\n\n if event['RequestType'] != 'Delete':\n result['Data']['z'] = res_props['X'] + res_props['Y']\n\n headers = {\n 'Content-type': 'application/json',\n 'Accept': 'application/json',\n 'Date': time.strftime('%a, %d %b %Y %X GMT', time.gmtime()),\n 'User-Agent': 'MyCustomUserAgent'\n }\n\n req = urllib.request.Request(event['ResponseURL'], data=json.dumps(result).encode('utf-8'), headers=headers)\n resp = urllib.request.urlopen(req)\n resp_content = resp.read().decode('utf-8')\n logger.info('response: %s', resp_content)\n\n if resp.getcode() != 200:\n logger.error('Failed to send response, status code: %s', resp.getcode())\n else:\n logger.info('Response sent successfully')\n`
}
});
const customResource = new ROS.CustomResource(this, 'SimpleTest', {
timeout: 60,
serviceToken: function1.attrArn,
parameters: {
X: x.valueAsNumber,
Y: y.valueAsNumber
}
});
new ros.RosOutput(this, 'SimpleTestOutputs', {
value: customResource.attrOutputs
});
}
}
module.exports = { DemoStack }
package com.myorg;
import com.aliyun.ros.cdk.core.RosParameter;
import com.aliyun.ros.cdk.core.RosOutput;
import com.aliyun.ros.cdk.core.RosOutputProps;
import com.aliyun.ros.cdk.core.RosParameterType;
import com.aliyun.ros.cdk.core.Construct;
import com.aliyun.ros.cdk.core.StackProps;
import com.aliyun.ros.cdk.core.Stack;
import com.aliyun.ros.cdk.ros.CustomResource;
import com.aliyun.ros.cdk.ros.CustomResourceProps;
import com.aliyun.ros.cdk.fc3.*;
import java.util.Map;
public class DemoStack extends Stack {
public DemoStack(final Construct scope, final String id) {
this(scope, id, null);
}
public DemoStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// The code that defines your stack goes here
RosParameter x = RosParameter.Builder.create(this, "X")
.type(RosParameterType.NUMBER)
.build();
RosParameter y = RosParameter.Builder.create(this, "Y")
.type(RosParameterType.NUMBER)
.build();
// 创建函数
Function function = new Function(this, "Function", FunctionProps.builder()
.functionName("mytest")
.handler("index.handler")
.runtime("python3")
.code(RosFunction.CodeProperty.builder()
.sourceCode("" +
"import time\n" +
"import json\n" +
"import urllib.request\n" +
"import logging\n\n" +
"def handler(event, context):\n" +
" logger = logging.getLogger()\n" +
" logger.setLevel(logging.INFO)\n" +
" event = json.loads(event)\n" +
" logger.info('receive request: %s', event)\n\n" +
" res_props = event['ResourceProperties']\n\n" +
" result = {\n" +
" 'RequestId': event['RequestId'],\n" +
" 'LogicalResourceId': event['LogicalResourceId'],\n" +
" 'StackId': event['StackId'],\n" +
" 'Status': 'SUCCESS',\n" +
" 'PhysicalResourceId': 'MyCustomResourceId',\n" +
" 'Data': {}\n" +
" }\n\n" +
" if event['RequestType'] != 'Delete':\n" +
" result['Data']['z'] = res_props['X'] + res_props['Y']\n\n" +
" headers = {\n" +
" 'Content-type': 'application/json',\n" +
" 'Accept': 'application/json',\n" +
" 'Date': time.strftime('%a, %d %b %Y %X GMT', time.gmtime()),\n" +
" 'User-Agent': 'MyCustomUserAgent'\n" +
" }\n\n" +
" req = urllib.request.Request(event['ResponseURL'], data=json.dumps(result).encode('utf-8'), headers=headers)\n" +
" resp = urllib.request.urlopen(req)\n" +
" resp_content = resp.read().decode('utf-8')\n" +
" logger.info('response: %s', resp_content)\n\n" +
" if resp.getcode() != 200:\n" +
" logger.error('Failed to send response, status code: %s', resp.getcode())\n" +
" else:\n" +
" logger.info('Response sent successfully')\n"
)
.build())
.build());
// 创建自定义资源
CustomResource customResource = new CustomResource(this, "SimpleTest", CustomResourceProps.builder()
.timeout(60)
.serviceToken(function.getAttrArn())
.parameters(Map.of(
"X", x.getValueAsNumber(),
"Y", y.getValueAsNumber()
))
.build());
// 输出
new RosOutput(this, "SimpleTestOutputs", RosOutputProps.builder()
.value(customResource.getAttrOutputs())
.build());
}
}
import ros_cdk_core as core
import ros_cdk_fc3 as fc
import ros_cdk_ros as ros
class DemoStack(core.Stack):
def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# The code that defines your stack goes here
x = core.RosParameter(self, "X", type=core.RosParameterType.NUMBER)
y = core.RosParameter(self, "Y", type=core.RosParameterType.NUMBER)
function = fc.Function(self, "Function", fc.FunctionProps(
function_name='mytest',
handler='index.handler',
runtime='python3',
code={
'sourceCode': "import time\nimport json\nimport urllib.request\nimport logging\n\ndef handler(event, context):\n logger = logging.getLogger()\n logger.setLevel(logging.INFO)\n event = json.loads(event)\n logger.info('receive request: %s', event)\n\n res_props = event['ResourceProperties']\n\n result = {\n 'RequestId': event['RequestId'],\n 'LogicalResourceId': event['LogicalResourceId'],\n 'StackId': event['StackId'],\n 'Status': 'SUCCESS',\n 'PhysicalResourceId': 'MyCustomResourceId',\n 'Data': {}\n }\n\n if event['RequestType'] != 'Delete':\n result['Data']['z'] = res_props['X'] + res_props['Y']\n\n headers = {\n 'Content-type': 'application/json',\n 'Accept': 'application/json',\n 'Date': time.strftime('%a, %d %b %Y %X GMT', time.gmtime()),\n 'User-Agent': 'MyCustomUserAgent'\n }\n\n req = urllib.request.Request(event['ResponseURL'], data=json.dumps(result).encode('utf-8'), headers=headers)\n resp = urllib.request.urlopen(req)\n resp_content = resp.read().decode('utf-8')\n logger.info('response: %s', resp_content)\n\n if resp.getcode() != 200:\n logger.error('Failed to send response, status code: %s', resp.getcode())\n else:\n logger.info('Response sent successfully')\n"
}
))
custom_resource = ros.CustomResource(self, "SimpleTest", ros.CustomResourceProps(
timeout=60,
service_token=function.attr_arn,
parameters={
"X": x.value_as_number,
"Y": y.value_as_number
}
))
core.RosOutput(self, "SimpleTestOutputs", value=custom_resource.attr_outputs)
using System.Collections.Generic;
using AlibabaCloud.SDK.ROS.CDK.Core;
using AlibabaCloud.SDK.ROS.CDK.Fc3;
using AlibabaCloud.SDK.ROS.CDK.Ros;
using Stack = AlibabaCloud.SDK.ROS.CDK.Core.Stack;
using IStackProps = AlibabaCloud.SDK.ROS.CDK.Core.IStackProps;
using RosOutput = AlibabaCloud.SDK.ROS.CDK.Core.RosOutput;
using RosOutputProps = AlibabaCloud.SDK.ROS.CDK.Core.RosOutputProps;
namespace Demo
{
public class DemoStack : Stack
{
public DemoStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
new RosInfo(this, RosInfo.Description, "This is the simple ros cdk app example.");
var x = new RosParameter(this, "X", new RosParameterProps
{
Type = RosParameterType.NUMBER
});
var y = new RosParameter(this, "Y", new RosParameterProps
{
Type = RosParameterType.NUMBER
});
var function1 = new Function(this, "Function", new FunctionProps
{
FunctionName = "mytest",
Handler = "index.handler",
Runtime = "python3",
Code = new RosFunction.CodeProperty
{
SourceCode = @"import time
import json
import urllib.request
import logging
def handler(event, context):
logger = logging.getLogger()
logger.setLevel(logging.INFO)
event = json.loads(event)
logger.info('receive request: %s', event)
res_props = event['ResourceProperties']
result = {
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'StackId': event['StackId'],
'Status': 'SUCCESS',
'PhysicalResourceId': 'MyCustomResourceId',
'Data': {}
}
if event['RequestType'] != 'Delete':
result['Data']['z'] = res_props['X'] + res_props['Y']
headers = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Date': time.strftime('%a, %d %b %Y %X GMT', time.gmtime()),
'User-Agent': 'MyCustomUserAgent'
}
req = urllib.request.Request(event['ResponseURL'], data=json.dumps(result).encode('utf-8'), headers=headers)
resp = urllib.request.urlopen(req)
resp_content = resp.read().decode('utf-8')
logger.info('response: %s', resp_content)
if resp.getcode() != 200:
logger.error('Failed to send response, status code: %s', resp.getcode())
else:
logger.info('Response sent successfully')
"
}
});
var customResource = new CustomResource(this, "SimpleTest", new CustomResourceProps
{
Timeout = 60,
ServiceToken = function1.AttrArn,
Parameters = new Dictionary<string, object>
{
{ "X", x.ValueAsNumber },
{ "Y", y.ValueAsNumber }
}
});
new RosOutput(this, "SimpleTestOutputs", new RosOutputProps
{
Value = customResource.AttrOutputs
});
}
}
}
步骤五:创建资源栈
在命令行窗口运行如下命令,创建资源栈。
ros-cdk deploy --parameters X=1 --parameters Y=2 --sync=true
请选择合适的可用区进行部署。命令行终端返回
The deployment(sync create stack) has completed!
表示创建成功,全部信息如下。Create bucket(cdk-ut58ogqt8-assets-cn-beijing) successfully! Upload file(./cdk.out/DemoStack.template.json) to bucket(cdk-ut58ogqt8-assets-cn-beijing) successfully! DemoStack: deploying... |DemoStack |2025-03-26T10:25:18 | CREATE_COMPLETE | ALIYUN::FC3::Function | 9bc03d9d-ca7d-431c-a6b5-e9ded2506266 | Function |DemoStack |2025-03-26T10:25:18 | CREATE_COMPLETE | ALIYUN::ROS::CustomResource | MyCustomResourceId | SimpleTest Outputs: Key: SimpleTestOutputs Value: [Object: null prototype] { z: 3 } Description: No description given ✅ The deployment(sync create stack) has completed! Status: CREATE_COMPLETE StatusReason: Stack CREATE completed successfully StackId: 8cda****-5ca4-4206-99dc-d7b3c****ba2
- 本页导读 (1)
- 费用说明
- 准备工作
- 步骤一:初始化工程
- 步骤二:配置阿里云凭证信息
- 步骤三:安装依赖
- 步骤四:添加资源
- 步骤五:创建资源栈