AWS CloudFormation — Custom Resources

Mart — Tanathip Viriya
4 min readJun 17, 2020

--

Custom Resources เป็นการช่วยให้เราสามารถเขียน logic เพิ่มเติมใน template ของเราได้ โดยสามารถนําไปใช้เมื่อไรก็ได้เมื่อ CloudFormation เรียกใช้ โดยมองเป็นใน resource types ได้เลย

Pattern ของ Type resources จะออกมาเป็น

AWS::CloudFormation::CustomResource or Custom::MyCustomResourceTypeName

โดยจะมี require property เดียวคือเจ้า service token ที่ทําหน้าที่ระบุว่าจะให้ CloudFomation ส่ง requests ไปที่ไหน? เช่น SNS topic หรือ Lambda Function นั้นเอง

Custom Resources ทํางานยังไง?

มีขั้นตอนง่ายๆ 3 ขั้น

  1. Template developer — สร้าง template ที่มีการเรียกใช้ custom resource type แล้วก็ระบุ service token และ input data ใน template
  2. Custom resource provider — คนที่สร้าง service provider ก็เขียน code จัดการพวก response ที่ CloudFormation ส่ง request มาให้เราว่าจะจัดการยังไงบ้าง
  3. AWS CloudFormation — ในจังหวะที่ stack CloudFormation ทํางาน Cfn จะส่ง request ไปที่ service token แล้วก็รอ response จนกว่าจะทํางานเสร็จนั้นเอง

ตัวอย่างด้านล่างคือ sample data ที่ Cfn ส่งเข้าไปใน request

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html

โดย ResourceProperties คือ ส่วนที่เป็น custom payload ที่เราส่งไปให้ Lambda function ในการเอาไปทําอะไรก็ได้ตาม logic ที่เราสร้างไว้

หลังจากส่ง request ไปเสร็จแล้ว Custom resource provider (คนที่สร้าง service token) จะเป็นคนจัดการกับ request นั้นและ response กลับไปให้กับ CloudFormation ซึ่งถ้า SUCCESS response CloudFormation ก็จะทํางานต่อ แต่ถ้า FAILED ก็จะ Fails นั้นเอง

คําถาม? แล้ว Custom resource provider จะจัดการกับ Response ยังไง?

มีอยู่ 2 วิธี

  • วิธีง่ายๆใช้ ZipFile ในการใส่ custom logic ของเรา เราจะสามารถใช้สิ่งที่เรียกว่า

cfn-response Module

ที่มีหน้าที่ใช้ในการจัดการสร้าง response object สําหรับ custom resource ให้เรานั้นเอง โดยดูจาก template ด้านล่างได้เลย

File: https://hta-cloudformation-bucket.s3.amazonaws.com/custom/simple-custom.json

โดยทั้ง Module หลักๆมี function เดียวเลยคือ send Method

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-lambda-function-code-cfnresponsemodule.html#w2ab1c19c25c14b9c11

ทําหน้าที่สร้าง response กลับไปให้ CloudFormation เพื่อทํางานต่อได้นั้นเอง

  • อีกวิธีนึงคือเขียน request ไป update response url เอง

เนื่องจากเราไม่มี cfn_response module แบบตัวบน เราเลยต้องส่ง response กลับไปให้กับทาง URL ของ cloudformation เอง โดยการส่ง status ไปที่ event.responseUrl ที่ได้มาใน request นั้นเอง

File: https://hta-cloudformation-bucket.s3.amazonaws.com/custom/lambda-code/lambda-code.zip

Template File: https://hta-cloudformation-bucket.s3.amazonaws.com/custom/simple-custom.json

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/walkthrough-custom-resources-lambda-lookup-amiids.html#walkthrough-custom-resources-lambda-lookup-amiids-createfunction-createstack
ตัวอย่าง request event ที่มี response URL มาให้เราทําการส่ง status ให้มัน

Custom Resource Event?

การทํางานของแต่ละ request type ใน custom resource จะมีลักษณะไม่เหมือนกัน เพราะฉะนั้นเราต้องเข้าใจว่ามันทํางานยังไง จะได้จัดการในแต่ละ event ได้ถูก โดยเราต้องตอบ response ไปแบบตัวอย่างข้างบนภายใน 1 ชั่วโมง

  1. Create
  2. Delete
  3. Update

Create Event

หน้าตาของ request ที่จะส่งมาใน create

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-requesttypes-create.html

สิ่งที่น่าสนใจคือมันส่ง Logical ID ของ template ที่เราใช้มาด้วยว่าเราใช้ชื่ออะไร

แต่สิ่งที่น่าสนใจของ response มี 2 ส่วนคือเรื่องของ Data ซึ่งเจ้าตัว Data สามารถ access ได้ผ่าน Fn::GetAtt ของ CloudFormation และ PhysicalResourcId ที่เป็นตัว unique identifier ของ custom resource vendor

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-requesttypes-create.html

Delete Event

ใช้เมื่อทําการ deletes stack ที่มี custom resource อยู่

request ของ type delete

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-requesttypes-create.html

จะเห็นว่ามันจะมีการส่ง PhysicalResourceId ไปมา ไม่เหมือนกับตอน create ละ

Update Event

ทีนี้มาดูตัวน่าสนใจคือการ Update เป็น request ที่ถูกเรียกใช้เมื่อมรการเปลี่ยนแปลงของ properties ใน custom resource ของ template

request ของ Update event

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-requesttypes-update.html

จะเห็นว่ามันจะมีการ refer ถึง properties ตัวเก่าและ properties ตัวใหม่เพื่อทําการ update ค่าที่เปลี่ยนแปลงไป

สิ่งที่น่าสนใจใช้การส่งไปมาตั้งแต่แรกสร้าง stack จน delete stack คือ PhysicalResourceId คําถามมันคืออะไร?

อย่างแรกเมื่อเราดูค่าของ PysicalResourceId เมื่อเวลาเราไม่ไดกําหนดอะไร มันจะใช้ logStreamName ซึ่งจะมีค่าตามรูปด้านล่าง (ชื่อ log group ของ CloudFormation นั้นเอง) ซึ่งจริงๆแล้วไม่ควรใช้

ตัวอย่าง request event ที่มี response URL มาให้เราทําการส่ง status ให้มัน

มันมีหน้าที่ใช้ในการ reference ไปมาระหว่าง Lifetime ของ Custom resource เช่น

  • ตอน create มันจะถูกสร้างขึ้นมา
  • ตอน delete มันจะถูกลบไป
  • ตอน update จะมีสอง behavior คือ ถ้าส่งค่าเดิมตอน create มา มันจะ update properties แต่ถ้าส่งค่าใหม่มา มันจะทําการลบ parameter เก่าแล้วสร้างใหม่ (replace ไม่ update)

ทีนี้มันมีผลยังไง?

โดยปกติแล้วพวก Unique id ถ้าเราไป replace มันด้วยตัวใหม่เนี้ยส่งผลคือมันจะทําให้มันไม่มี parent และ manage ไม่ได้นั้นเอง เพราะฉะนั้นเราไม่ควรจะทําการ delete (replace) นั้นเอง

ทีนี้ก็ขึ้นอยู่กับการจัดการ resource ใน code เราแล้วว่าเราต้องการที่จะจัดการมันยังไง โดยดูจาก request type นั้นเอง สามารถดูตัวอย่าง Logic ได้จาก github ด้านล่างนี้

Troubleshoot

  1. ใช้ Cloudwatch เสมอ ในการจัดการอะไรต่างๆ โดยเฉพาะ Lambda ให้สิทธิ์ write log เลย เพื่อที่เวลามีปัญหาจะได้ดู Log ได้ รวมถึง x-ray ด้วย
    ส่วนถ้าอยากดู event ที่ส่งเข้ามาแนะนํา write event ลง log ด้วยจะได้เห็นภาพมากขึ้นแบบในตัวอย่างข้างบน
  2. Custom Resource Failed to stabilize in expected time in AWS CloudFormation ส่วนใหญ่จะเกิดจาก เราไม่ได้ส่ง response กลับไปให้ทาง URL ของ CloudFormation เวลาทํา Custom Resource
    https://stackoverflow.com/questions/60998040/why-custom-resource-failed-to-stabilize-in-expected-time-in-aws-cloudformation
  3. Best Practise for custom resource Cfn
    https://aws.amazon.com/premiumsupport/knowledge-center/best-practices-custom-cf-lambda/

แนะนํา

เรื่องของการจัดการ S3 pre-signed S3 เนี้ยแนะนําใช้ Helper library ที่ทํามาไว้ให้แล้วดีกว่าจะได้ไม่ต้องเสียเวลาเขียนเอง

แล้วก็ลองอ่าน Custom Resource Github Webhook อันนี้จะเห็นภาพมากขึ้น

--

--