资料

  • AWS::CloudFormation::CustomResource
  • cfn-response module

自定义资源的逻辑

cloudformation只能对aws service进行部署和配置,但是用户可能需要使用第三方产品,此时需要通过自定义资源将其纳入到cloudformation的管理中。通过编写自定义逻辑,可以在每次对堆栈进行创建/更新/删除操作时,执行自定义逻辑。

可以使用 AWS::CloudFormation::CustomResource 或 Custom::MyCustomResourceTypeName 资源类型在模板中定义自定义资源

自定义资源执行的任何操作都涉及到以下三方:

  • template developer,请求发送者,在cfn模板中指定令牌和参数
  • custom resource provider,请求处理者,对应令牌中指定的资源,处理来自cfn的请求,
  • cloudformation,监听cfn堆栈操作,发送请求并等待响应

令牌实际上就是指定cfn请求发送的位置(可以是sns或lambda),服务令牌不能跨region

这里有一个创建eks oidc的cfn自定义资源示例,https://github.com/bambooengineering/example-eks-oidc-iam-cloudformation/blob/master/oidc-provider.yaml,在ServiceToken字段指定了lambda函数的arn。当创建改自定义资源时,cfn会将请求发送到对应的ClusterOIDCURLFunction函数进行处理。

Resources:ClusterOIDCURL:Type: Custom::ClusterOIDCURLProperties:ServiceToken: !GetAtt ClusterOIDCURLFunction.ArnClusterName: !Ref EKSClusterName

cfn请求中包括的字段有

{"RequestType" : "Create","ResponseURL" : "http://pre-signed-S3-url-for-response","StackId" : "arn:aws:cloudformation:us-west-2:123456789012:stack/stack-name/guid","RequestId" : "unique id for this create request","ResourceType" : "Custom::TestResource","LogicalResourceId" : "MyTestResource","ResourceProperties" : {"Name" : "Value","List" : [ "1", "2", "3" ]}
}

请求处理者(provider)会向s3 presign url返回响应(success或failed),具体形式是将json文件通过url上传。自定义资源所有的输出数据都存储在s3预签名位置。在cfn响应中可以包含的字段。

{"Status" : "SUCCESS","PhysicalResourceId" : "TestResource1","StackId" : "xxxxxxx","RequestId" : "unique id for this create request","LogicalResourceId" : "MyTestResource","Data" : {"OutputName1" : "Value1","OutputName2" : "Value2",}
}

测试自定义资源

使用cfn模板创建lambda

仿照上面的例子,在cfn模板中通过zipfile方式创建自定义lambda函数

查看cfnresponse函数的内容如下,只有一个send函数,实际上就是构造http请求,向ResponseURL发送响应信息

from __future__ import print_function
import urllib3
import json
SUCCESS = "SUCCESS"
FAILED = "FAILED"
http = urllib3.PoolManager()
def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False, reason=None):responseUrl = event['ResponseURL']print(responseUrl)responseBody = {'Status' : responseStatus,'Reason' : reason or "See the details in CloudWatch Log Stream: {}".format(context.log_stream_name),'PhysicalResourceId' : physicalResourceId or context.log_stream_name,'StackId' : event['StackId'],'RequestId' : event['RequestId'],'LogicalResourceId' : event['LogicalResourceId'],'NoEcho' : noEcho,'Data' : responseData}json_responseBody = json.dumps(responseBody)print("Response body:")print(json_responseBody)headers = {'content-type' : '','content-length' : str(len(json_responseBody))}try:response = http.request('PUT', responseUrl, headers=headers, body=json_responseBody)print("Status code:", response.status)except Exception as e:print("send(..) failed executing http.request(..):", e)

从lambda函数的日志中可以看到,预签名url的格式为https://cloudformation-custom-resource-response-cnnorth1.s3.cn-north-1.amazonaws.com.cn,表明改s3桶是专用的无法在用户账号下看到。

手动创建lambda

为了便于观察触发和处理的细节,手动创建lambda函数

创建lambda函数,当然也可以在cfn和自定义资源一同创建。发现找不到cfnresponse的模块,通过cfn创建zip方式会自动将该包导入

手动创建该函数,在控制台增加cfnresponse.py文件,执行时出现以下错误

Calling the invoke API action failed with this message: Lambda was not able to unzip the file

原因如下

The cfn-response module is available only when you use the ZipFile property to write your source code. It isn’t available for source code that’s stored in Amazon S3 buckets. For code in buckets, you must write your own functions to send responses.

import boto3
import json
import cfnresponse
eks = boto3.client("eks")
def lambda_handler(event, context):responseData = {}print(event)if event['RequestType'] == 'Delete':responseData['Reason'] = "Success"cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "")else:try:stack_name = event['ResourceProperties']['StackName']responseData['Reason'] = "Success"responseData['Url'] = "http://example.com"responseData['StackName'] = stack_namecfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)except Exception as e:responseData['Reason'] = str(e)cfnresponse.send(event, context, cfnresponse.FAILED, responseData, "")

重新将两个文件打包后上传到lambda中

在cfn模板中指定函数arn,集请求要发送的地址

MyCustomResource:Type: AWS::CloudFormation::CustomResourceProperties:ServiceToken: !Sub 'arn:aws-cn:lambda:${AWS::Region}:${AWS::AccountId}:function:test-cfn-resource'StackName: !Ref NetworkStackName

部署堆栈,在lambda日志中查看事件

请求信息

{"RequestType": "Create","ServiceToken": "arn:aws-cn:lambda:cn-north-1:xxxxxxxxxxxx:function:test-cfn-resource","ResponseURL": "https://cloudformation-custom-resource-response-cnnorth1.s3.cn-north-1.amazonaws.com.cn/arn/xxxxx","StackId": "arn:aws-cn:cloudformation:cn-north-1:xxxxxxxxxxxx:stack/test-customer/fee6cbb0-6fb7-11ed-93da-0205553bff1a","RequestId": "ac23fe12-8021-49e8-89fc-9a361751b076","LogicalResourceId": "MyCustomResource","ResourceType": "AWS::CloudFormation::CustomResource","ResourceProperties": {"ServiceToken": "arn:aws-cn:lambda:cn-north-1:xxxxxxxxxxxx:function:test-cfn-resource","StackName": "test-customer"}
}

响应信息

{"Status": "SUCCESS","Reason": "See the details in CloudWatch Log Stream: 2022/11/29/[$LATEST]b611058c186e4694b60aeb4ac8a7d4b2","PhysicalResourceId": "2022/11/29/[$LATEST]b611058c186e4694b60aeb4ac8a7d4b2","StackId": "arn:aws-cn:cloudformation:cn-north-1:xxxxxxxxxxxx:stack/test-customer/db6b7940-6fb9-11ed-80a8-0eeb4c1e70a4","RequestId": "d75e9cff-8ab4-493a-9a26-c50a00d86f8f","LogicalResourceId": "MyCustomResource","NoEcho": false,"Data": {"Reason": "Success","Url": "http://example.com","StackName": "test-customer"}
}

堆栈创建成功

通过以上逻辑我们可以知道,通过创建自定义资源例如lambda函数,我们能够通过代码的方式对cfn模板的请求和响应进行处理,如果需要集成第三方产品,只需要在lambda函数中调用即可

此外请求有时间限制(1小时)

The provider must respond to the S3 bucket with either a SUCCESS or FAILED result within one hour. After one hour, the request times out

关于自定义资源的参考文档

相关错误和解决

如何删除 CloudFormation 中卡在 DELETE_FAILED 状态或 DELETE_IN_PROGRESS 状态的 Lambda 支持的自定义资源?

卡在DELETE_FAILED可能是由于lambda函数缺少处理删除资源的逻辑

卡在DELETE_IN_PROGRESS,可能原因同上,但是由于landa请求处理的时间为1小时,该错误只能手动向cfn发送成功信号

在lambda函数的日志中获取以下参数,将信息存储到s3 presin url桶中(如果成功删除,这一步是lambda返回响应后cfn帮我们完成的)

$ curl -H 'Content-Type: ''' -X PUT -d '{"Status": "SUCCESS","PhysicalResourceId": "test-CloudWatchtrigger-1URTEVUHSKSKDFF","StackId": "arn:aws:cloudformation:us-east-1:111122223333:stack/awsexamplecloudformation/33ad60e0-5f25-11e9-a734-0aa6b80efab2","RequestId": "e2fc8f5c-0391-4a65-a645-7c695646739","LogicalResourceId": "CloudWatchtrigger"}' 'https://cloudformation-custom-resource-response-useast1.s3.us-east-1.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-east-1%3A111122223333%3Astack/awsexamplecloudformation/33ad60e0-5f25-11e9-a734-0aa6b80efab2%7CMyCustomResource%7Ce2fc8f5c-0391-4a65-a645-7c695646739?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20170313T0212304Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7200&X-Amz-Credential=QWERTYUIOLASDFGBHNZCV%2F20190415%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=dgvg36bh23mk44nj454bjb54689bg43r8v011uerehiubrjrug5689ghg94hb'

aws cloudformation 理解自定义资源的使用相关推荐

  1. AWS CloudFormation

    Hello大家好,欢迎来到<AWS解决方案架构师认证 Professional(SAP)中文视频培训课程>,我们今天的课时讨论AWS CloudFormation的内容. CloudFor ...

  2. AWS — AWS CloudFormation

    目录 文章目录 目录 AWS CloudFormation AWS CloudFormation Private Registry AWS CloudFormation Public Registry ...

  3. 理解 K8s 资源更新机制,从一个 OpenKruise 用户疑问开始

    作者 | 酒祝  阿里云技术专家 背景 OpenKruise 是阿里云开源的大规模应用自动化管理引擎,在功能上对标了 Kubernetes 原生的 Deployment / StatefulSet 等 ...

  4. 从OpenKruise用户疑问开始理解K8s资源更新机制

    云栖号资讯:[点击查看更多行业资讯] 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 背景 OpenKruise 是阿里云开源的大规模应用自动化管理引擎,在功能上对标了 Kuberne ...

  5. aws cloudformation 堆栈集的创建和使用

    资料 使用 AWS CloudFormation StackSets 跨多个 AWS 账户和区域配置资源 AWS cloudformation示例模板 堆栈集堆栈实例状态原因 很多组织使用大量的 AW ...

  6. operator-sdk实战开发K8S CRD自定义资源对象

    环境说明 系统:CentOS Linux release 7.6.1810 (Core) golang:v1.15 operator-sdk:v1.7.0 docker:v1.19 # 因为 oper ...

  7. 通过自定义资源扩展Kubernetes

    原文链接:通过自定义资源扩展Kubernetes 转载于:https://www.cnblogs.com/wangjq19920210/p/11555996.html

  8. VB将自定义资源中的文件释放出来

    程序代码: Option Explicit '************************************************************************* '** ...

  9. Unity使用自定义资源(.asset)配置数据

    本文原创版权归 强哥的私房菜 所有,此处为转载,如有再转,请于篇首位置标明原创作者及出处,以示尊重! 作者:强哥的私房菜 原文:http://blog.csdn.net/liqiangeastsun/ ...

最新文章

  1. CentOS 7 SSH 免密登录的方法
  2. C#String.PadLeft函数,文本对齐以及填补解决方案
  3. 力扣——有序链表转换二叉搜索树
  4. BZOJ 3673: 可持久化并查集 by zky
  5. ventory制作U盘启动盘
  6. 无忧计算机二级试题题库,全国计算机二级MS Office试题
  7. 在Ubuntu上以服务方式运行Java程序
  8. 管状合金电阻和片状合金电阻的区别_合金采样电阻的特点及作用
  9. 【Express】—get请求参数 restful API
  10. FIFO、LRU、LFU的含义和原理(转)
  11. foobar2000在线标签服务器,不再烦恼 小烧友手把手教你设置 Foobar2000界面
  12. 人类能看懂的衍射光学(含基尔霍夫衍射,瑞利--索末菲衍射,夫琅禾费衍射,角谱衍射,菲涅尔衍射积分,菲涅尔衍射的S-FFT算法,T-FFT算法,D-FFT算法)
  13. java代码绘制简单的图形
  14. 会做饭的机器人曰记_会做饭的机器人!
  15. A-Level经济真题每期一练(19)
  16. 服务器上传文件出现500错误,但是其他不涉及文件的接口均正常
  17. 一些DDR4内存的科普
  18. zookeeper启动报错Exiting JVM with code 3
  19. 关于error C2059: 语法错误:“类型”,初学者的一点收获
  20. 【MPPT】基于MPPT的风力发电系统simulink仿真

热门文章

  1. 用JS写出捕捉小精灵网页游戏
  2. 需要一个前端小哥哥或小姐姐 救救孩子吧 T_T
  3. (一)、极易上手Mac、Windows、Ubuntu、Linux的GIT的安装与日常使用
  4. vue 自定义指令 权限指令
  5. 通过 Photoshop(ps)降低文件大小
  6. 算法题 匈牙利算法 求二分图最大匹配(Python)
  7. Android 8.1 App开机自启动、注册为无障碍服务、实现悬浮窗
  8. 一个简单的傅里叶变换matlab函数(绝对可用)
  9. 【BZOJ4209】西瓜王
  10. PlatON谢翔博士:​ETH 2.0 能促进隐私计算应用扩展