AWS CloudFormation in Action

Mart — Tanathip Viriya
5 min readJun 12, 2020

คราวนี้เรามาลองใช้งานจริงกับ CloudFormation และ เพื่อให้เข้าใจในบทความเดียวเลย เราจะลองตั้งแต่แบบพื้นฐานง่ายๆเช่นสร้าง EC2, S3 แบบง่ายๆ ไปจนถึงสร้าง security group ให้ EC2, EC2 กับ RDS, EC2 กับ RDS และ Elastic Load Balancer ไปจนถึง Nested Stack เพื่อให้สามารถนําไปประยุกต์ใช้งานได้จริงหลังจากอ่านจบ

CloudFormation Template หลักๆต่อไปนี้คือที่เราจะมาเล่นกัน

  1. S3
  2. VPC
  3. EC2,
  4. Nested Stack and Exporting Output

FYI: CloudFormation Template จะอยู่ที่ S3 เพื่อให้ง่ายต่อการใช้งานและเอาไปใช้ในอนาคต

Intrinsic Function

ก่อนจะเริ่มเล่นกับ CloudFormation เราควรจะเรียนรู้กับ built-in functions ที่ AWS เตรียมไว้ให้ก่อน เพราะพวกนี้เป็นประโยชน์อย่างมากเพื่อให้เราจัดการกับ stacks ได้ง่ายๆ เช่น ตัวฮิตที่ใช้บ่อยๆ

  • Fn::GetAtt

{ “Fn::GetAtt” : [ “logicalNameOfResource”, “attributeName” ] }

Function GetAttribute ของ LogicalName ตัวไหนก็ได้ เช่น

“Fn::GetAtt” : [ “myELB” , “DNSName” ]

เราจะได้ค่าจอง DNSName ของ ELB ออกมานั้นเอง ซึ่ง myELB คือ Logical Name ที่เราสร้างขึ้นมานั้นเอง

  • Fn::Join

{ “Fn::Join” : [ “delimiter”, [ comma-delimited list of values ] ] }

Function Join มีไว้สําหรับ join string เข้าด้วยกัน โดยจะ Join กี่ตัวก็ได้เพราะรับค่าเป็น Array เพียงแค่ระบุ delimiter ให้มัน เช่น

“Fn::Join” : [ “:”, [ “a”, “b”, “c” ] ]

จะได้ค่าออกมาเป็น a:b:c

  • Ref

{ “Ref” : “logicalName” }

Reference logical name ใน template ของเรา เช่น

“MyEIP” : { “Type” : “AWS::EC2::EIP”, “Properties” : { “InstanceId” : { “Ref” : “MyEC2Instance” } } }

EIP ที่เราสร้าง attach EC2 ด้วย InstanceId ของ MyEC2Instance

S3

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

เรามาเริ่มกับการสร้าง Bucket ของ S3 แบบง่ายสุดๆๆกัน ด้วยการเพิ่ม Resource Bucket เข้าไปใน Resources section

Simple CFC template

เพียงแค่นี้เราก็สร้าง AWS resource ขึ้นมาแล้วซึ่งก็คือ S3 Bucket นั้นเอง โดยเราจะตั้งค่าอะไรให้กับ Bucket นี้ก็แค่เพิ่มใน Properties นั้นเอง โดยมี Syntax ตามตัวอย่างข้างล่าง

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#aws-properties-s3-bucket-syntax

ซึ่งในกรณีเราตัวอย่างแรกคือเราตั้ง BucketName ให้เป็นแบบที่เราต้องการ และ ตั้งค่า DeletionPolicy ไว้ เพื่อเวลาเราลบ Stack ออกมันจะได้ลบไปด้วยนั้นเอง

ทีนี้เดี๋ยวเรามาดูตัวอย่างของการสร้าง S3 Bucket และตั้ง CORS ของ Bucket เพื่อให้เข้ามาใช้ได้เฉพาะ GET จาก example1.com เท่านั้น

โดยตัวอย่างนี้เราจะมีการเริ่มใช้ Outputs ซึ่งจะเป็นค่าที่จะไปแสดงบนหน้า GUI ของ AWS หรือไปแสดงบน CLI เมื่อเรารันเสร็จ ซึ่งเราสามารถจะตั้งให้มันแสดงอะไรก็ได้

ซึ่งจากตัวอย่างคือเราต้องการ BucketName เราเลยใช้วิธี Ref ไป logical name ของเราซึ่งก็คือ S3Bucket และ Ref มันจะทําการ return ID กลับมาให้เรานั้นเอง

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

Simple S3 with CORS control

EC2

File: https://hta-cloudformation-bucket.s3.amazonaws.com/create-simplest-ec2.json

CloudFormation สามารถสร้าง AWS resources ไม่ว่าจะเป็นตัวไหนก็ตามเพียงแค่เราต้อง Configue มันให้ถูกแค่นั้นเอง

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#aws-properties-ec2-instance-syntax

อย่างตัวอย่างนี้คือเราจะสร้าง EC2 instance ขึ้นมาใช้งานด้วย CloudFormation เราก็แค่เข้าไปที่ document ของ EC2 Cloudformation แล้วดูว่าตัวไหนเป็น required properties แล้วเราก็สร้างตามนั้น

https://hta-cloudformation-bucket.s3.amazonaws.com/create-simplest-ec2.json

ซึ่งจริงๆแล้ว EC2 แบบ simplest เลยนะ มัน required แค่ตัวเดียวคือ ImageId ในการสร้าง resource

Sample of Image Id

แต่เอาจริงๆทํางั้นไม่ได้นะ เวลาใช้งานบน Production เราต้อง Config ให้ถูกและเหมาะสมที่สุด เช่น InstanceType, Volume, Monitor เป็นต้น

VPC

File: https://hta-cloudformation-bucket.s3.amazonaws.com/vpc/full-vpc.json

ตัวอย่างที่น่าสนใจสําหรับการสร้าง Virtual Private Cloud ที่ใช้งานได้จริงๆ โดยจะประกอบด้วย

  • Internet Gateway
  • 2 Availiability Zone
  • 2 Nat Gateway และ 2 EIP สําหรับ NAT Gateway
  • 2 Public Subnet
  • 2 Private Subnet
  • 2 Route
  • 2 RouteTable

FYI: NAT Gateway ต้องอยู่ใน public subnet เพื่อให้ instance ใน private subnet สามารถที่จะออก internet ได้ โดยสิ่งที่ต้องทําคือให้สร้าง RouteTable ชี้ไปที่ NAT เหล่านั้น

EC2 และ RDS ใน VPC

File: https://hta-cloudformation-bucket.s3.amazonaws.com/ec2/full-app.json

Template นี้จะเป็นการสร้าง EC2 และ RDS (MySQL) ขึ้นมาแบบที่ Production Environment ใช้

โดยเราจะใช้ตัวอย่าง VPC ข้างบนมาใส่ Resource ที่เราต้องการนั้นเอง โดยตัว Webserver ที่อยู่ใน Public Subnet เป็นทางเดียวที่เข้าถึง RDS ใน Private Subnet ได้เพียงแต่เราต้องสร้าง Security Group ให้กับ EC2 instance ของเราด้วยนั้นเอง

https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Scenario2.html

Nested Stack

Best Practise ของการทํา CloudFormation คือ การใช้ Nested Stack เนี้ยแหละในการจัดการ common component ทั้งหมด จะได้ไม่ DRY ตัวเอง

สาเหตุเพราะเมื่อเราสร้าง CloudFormation Template พวกนี้ไปเรื่อยๆจะพบว่า Infrastructure ของเรามันโตขึ้นเรื่อยๆๆ Resources เยอะแยะและซํ้ากันเต็มไปหมด ยกตัวอย่างเช่น VPC ถ้าไม่นับ Parameter ที่เปลี่ยนไปนะ มันก็ต้องสร้างแน่นอน ซึ่งซํ้ากันเยอะแนะนอน

ดังนั้น AWS เลยมีสิ่งที่เรียกว่า Nested Stack ที่มีไว้ช่วยเราให้สามารถ Reuse component ต่างๆๆ ไม่ต้องสร้างซํ้าๆกัน ให้เราสามารถ Reuse กันมา

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html

ตัวอย่างนี้เราจะทําการใช้ Nested Stack กับ VPC แล้วจับ Instance ใส่เข้าไป เพื่อให้เราสามารถ reuse VPC ได้

ให้ลองมองจาก Diagram ข้างบนให้มอง A เป็นจุดที่สร้าง Parent (Root) แล้วเราสร้าง VPC ไว้ใน B (Child) ที่มี 1 VPC, 1 public subnet ทีนี้เวลาพอ A ถูกสร้าง B ก็จะถูกสร้างตามไปด้วย และเราก็ได้ VPC มาโดยไม่ต้องสร้างแบบเดิมซํ้าๆอีก

AWS::CloudFormation::Stack

File: https://hta-cloudformation-bucket.s3.amazonaws.com/ec2/nested/ec2-nested-stack.json

Sample of Resource stack

ซึ่งเมื่อเวลาเราสร้าง Parent Stack (root stack) มันก็จะวิ่งไปสร้าง Stack อื่นๆๆที่ Child Stack (nested stack) ให้เอง รวมถึงเราสามารถส่ง Parameters ให้ stack อื่นๆได้ด้วย เพื่อเอาไปใช้งานในด้านอื่นๆ

Refer Outputs Resource จาก CloudFormation Stack อื่น

Network template file:https://hta-cloudformation-bucket.s3.amazonaws.com/ec2/full-vpc-resuse.json

EC2 reuse that network: https://hta-cloudformation-bucket.s3.amazonaws.com/ec2/ec2-resuse.json

เวลาเราใช้พวก Reuseable Stack แบบนี้มีบางทีที่เราต้อง References ไปที่ Stack เหล่านั้น สิ่งที่เราต้องทําก็คือการ Export ใน Output จาก Stack พวกนั้นเป็น variable ให้คนอื่นเรียกใช้ แล้วใช้ Built-in Function ImportValue เข้ามาใช้งานใน Stack ของเรานั้นเอง

แล้วเมื่อไรเราควรใช้ Nested Stack หรือ Exporting Output

วิธีเลือกใช้ง่ายๆของสองตัวนี้คือ เราต้องการจะ share information ให้กับคนอื่นรู้ หรือ ไม่ต้องการแชร์

เพราะสําหรับการทํา Exporting Output มันคือการเอาข้อมูลจาก stack ของเราไปให้คนอื่นใช้ด้วย และ มันก็จะเป็น dependencies กันด้วย แปลว่า stack อื่นไม่จําเป็นต้องที่สร้างของตัวเอง แต่เข้ามาใช้ได้เลย เช่น เราสร้าง VPC ให้คนอื่นเข้ามาใช้ โดยเราส่ง VPCId และ Subnet ไปให้ใช้ (ถ้า Export Value ของเรายังถูกใช้จาก Stack อื่นๆ เราจะไม่สามารถ delete stack ที่ export นั้นได้)

แต่ในทางการกลับกัน Nested Stack จะสร้างแค่ใน stack นั้นซึ่งไม่แชร์ข้อมูลกับใครเลย

Troubleshooting CloudFormation

  • ใช้ Events ของ CloudFormation ดูว่าจังหวะไหนสร้างอะไรไม่ได้ แล้วไล่ troubleshooting ต่อจากตรงนั้น
  • เวลาเราสร้าง Amazon RDS DB Instance ใน VPC ที่เจาะจงที่ต้องการบางทีเราอาจจะเกิดปัญหาต้องสร้าง DBSubnetGroup ไว้ใช้ด้วย
  • ถ้ามันค้างตอนสร้างนานๆให้เราไปดู CloudTrail เพื่อดูว่า request ที่ส่งไปหา Services ไหนมันเกิด error บ้าง ซึ่งถ้ามันค้างเพราะยังงั้นก็กดลบ CloudFormation Stack ไปเลย แล้วสร้างใหม่
  • การใช้ CloudFormation ก็เหมือนการสั่งคนไปสร้างของให้เราตามเราต้องการ ถ้ามันเกิดปัญหาอะไรเช่น DELETE ไม่ได้ หรือสร้างไรไม่ได้ เราไม่ได้แก้ปัญหาใน CloudFormation เราแค่ไปลบของชิ้นนั้นจาก Console ของ Services นั้นโดยตรงกจะแก้ได้ แค่นั้นเอง

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Responses (1)

Write a response