ฉันเริ่มทำงานด้วย เมฆ 4 ปีที่แล้ว. ตั้งแต่นั้นมา ฉันได้ทำลายโครงสร้างพื้นฐานจำนวนมาก แม้แต่โครงสร้างพื้นฐานที่ใช้งานจริงอยู่แล้วก็ตาม แต่ทุกครั้งที่ฉันทำอะไรผิดพลาด ฉันได้เรียนรู้สิ่งใหม่ ผ่านประสบการณ์นี้ ฉันจะแบ่งปันบทเรียนสำคัญที่สุดบางบทเรียนที่ฉันเรียนรู้
บทที่ 1: ทดสอบการเปลี่ยนแปลงก่อนที่จะปรับใช้
ฉันได้เรียนรู้บทเรียนนี้หลังจากเริ่มทำงานด้วยไม่นาน เมฆ. ฉันจำไม่ได้ว่าฉันพังอะไรไปบ้างในตอนนั้น แต่ฉันจำได้แน่นอนว่าฉันใช้คำสั่ง การอัปเดตรูปแบบคลาวด์ของ aws. คำสั่งนี้เพียงเผยแพร่เทมเพลตโดยไม่มีการตรวจสอบความถูกต้องของการเปลี่ยนแปลงที่จะนำไปใช้งาน ฉันไม่คิดว่าจำเป็นต้องมีคำอธิบายว่าทำไมคุณควรทดสอบการเปลี่ยนแปลงทั้งหมดก่อนที่จะนำไปใช้งาน
หลังจากความล้มเหลวนี้ ฉันก็เปลี่ยนทันที ท่อวางระบบโดยแทนที่คำสั่ง update ด้วยคำสั่ง สร้างการเปลี่ยนแปลงชุด
# OPERATION is either "UPDATE" or "CREATE"
changeset_id=$(aws cloudformation create-change-set
--change-set-name "$CHANGE_SET_NAME"
--stack-name "$STACK_NAME"
--template-body "$TPL_PATH"
--change-set-type "$OPERATION"
--parameters "$PARAMETERS"
--output text
--query Id)
aws cloudformation wait
change-set-create-complete --change-set-name "$changeset_id"
เมื่อสร้างเซ็ตการแก้ไขแล้ว จะไม่มีผลกับสแต็กที่มีอยู่ ต่างจากคำสั่ง update ตรงที่วิธีเซ็ตการแก้ไขไม่ทริกเกอร์การปรับใช้จริง แต่จะสร้างรายการการเปลี่ยนแปลงที่คุณสามารถตรวจสอบก่อนปรับใช้แทน คุณสามารถดูการเปลี่ยนแปลงได้ในอินเทอร์เฟซคอนโซลของ aws แต่หากคุณต้องการทำให้ทุกสิ่งที่คุณทำได้เป็นอัตโนมัติ ให้ตรวจสอบสิ่งเหล่านี้ใน CLI:
# this command is presented only for demonstrational purposes.
# the real command should take pagination into account
aws cloudformation describe-change-set
--change-set-name "$changeset_id"
--query 'Changes[*].ResourceChange.{Action:Action,Resource:ResourceType,ResourceId:LogicalResourceId,ReplacementNeeded:Replacement}'
--output table
คำสั่งนี้ควรสร้างเอาต์พุตที่คล้ายกับดังต่อไปนี้:
--------------------------------------------------------------------
| DescribeChangeSet |
+---------+--------------------+----------------------+------------+
| Action | ReplacementNeeded | Resource | ResourceId |
+---------+--------------------+----------------------+------------+
| Modify | True | AWS::ECS::Cluster | MyCluster |
| Replace| True | AWS::RDS::DBInstance| MyDB |
| Add | None | AWS::SNS::Topic | MyTopic |
+---------+--------------------+----------------------+------------+
ให้ความสนใจเป็นพิเศษกับการเปลี่ยนแปลงที่การดำเนินการอยู่ แทนที่, ลบ หรือที่ไหน จำเป็นต้องเปลี่ยน - จริง. การเปลี่ยนแปลงเหล่านี้เป็นการเปลี่ยนแปลงที่อันตรายที่สุดและมักจะนำไปสู่การสูญเสียข้อมูล
เมื่อตรวจสอบการเปลี่ยนแปลงแล้ว ก็สามารถนำไปใช้งานได้
aws cloudformation execute-change-set --change-set-name "$changeset_id"
operation_lowercase=$(echo "$OPERATION" | tr '[:upper:]' '[:lower:]')
aws cloudformation wait "stack-${operation_lowercase}-complete"
--stack-name "$STACK_NAME"
บทที่ 2: ใช้นโยบายสแต็กเพื่อป้องกันไม่ให้ทรัพยากรที่มีสถานะถูกแทนที่หรือลบออก
บางครั้งการดูการเปลี่ยนแปลงเพียงอย่างเดียวอาจไม่เพียงพอ เราทุกคนเป็นมนุษย์และเราทุกคนต่างก็ทำผิดพลาด ไม่นานหลังจากที่เราเริ่มใช้เซ็ตการแก้ไข เพื่อนร่วมทีมของฉันก็ทำการปรับใช้โดยไม่รู้ตัว ซึ่งส่งผลให้มีการอัปเดตฐานข้อมูล ไม่มีอะไรเลวร้ายเกิดขึ้นเพราะเป็นสภาพแวดล้อมการทดสอบ
แม้ว่าสคริปต์ของเราจะแสดงรายการการเปลี่ยนแปลงและขอการยืนยัน แต่การเปลี่ยนแปลงแทนที่ก็ถูกข้ามไปเนื่องจากรายการการเปลี่ยนแปลงมีขนาดใหญ่มากจนไม่พอดีกับหน้าจอ และเนื่องจากนี่เป็นการอัปเดตปกติในสภาพแวดล้อมการทดสอบ จึงไม่ค่อยให้ความสนใจกับการเปลี่ยนแปลงมากนัก
มีทรัพยากรที่คุณไม่ต้องการแทนที่หรือลบออก บริการเหล่านี้เป็นบริการแบบระบุสถานะ เช่น อินสแตนซ์ฐานข้อมูล RDS หรือคลัสเตอร์ elasticsearch เป็นต้น คงจะดีไม่น้อยหาก aws ปฏิเสธการปรับใช้โดยอัตโนมัติ หากการดำเนินการที่กำลังดำเนินการอยู่จำเป็นต้องลบทรัพยากรดังกล่าว โชคดีที่รูปแบบคลาวด์มีวิธีการทำเช่นนี้ในตัว สิ่งนี้เรียกว่านโยบายสแต็ก และคุณสามารถอ่านเพิ่มเติมเกี่ยวกับนโยบายนี้ได้ใน
STACK_NAME=$1
RESOURCE_ID=$2
POLICY_JSON=$(cat <<EOF
{
"Statement" : [{
"Effect" : "Deny",
"Action" : [
"Update:Replace",
"Update:Delete"
],
"Principal": "*",
"Resource" : "LogicalResourceId/$RESOURCE_ID"
}]
}
EOF
)
aws cloudformation set-stack-policy --stack-name "$STACK_NAME"
--stack-policy-body "$POLICY_JSON"
บทที่ 3: ใช้ UsePreviousValue เมื่ออัปเดตสแต็กด้วยพารามิเตอร์ลับ
เมื่อคุณสร้างเอนทิตี mysql ของ RDS AWS กำหนดให้คุณต้องระบุ MasterUsername และ MasterUserPassword เนื่องจากเป็นการดีกว่าที่จะไม่เก็บความลับไว้ในซอร์สโค้ด และฉันต้องการทำให้ทุกอย่างเป็นแบบอัตโนมัติ ฉันจึงใช้ "กลไกอันชาญฉลาด" ซึ่งก่อนที่จะปรับใช้ ข้อมูลประจำตัวจะได้รับจาก s3 และหากไม่พบข้อมูลประจำตัว ก็จะมีการสร้างข้อมูลประจำตัวใหม่ และ เก็บไว้ใน s3 .
ข้อมูลประจำตัวเหล่านี้จะถูกส่งผ่านเป็นพารามิเตอร์ไปยังคำสั่ง cloudformation create-change-set ขณะทดลองสคริปต์ บังเอิญว่าการเชื่อมต่อกับ s3 ขาดหายไป และ “กลไกอันชาญฉลาด” ของฉันถือว่ามันเป็นสัญญาณในการสร้างข้อมูลประจำตัวใหม่
ถ้าฉันเริ่มใช้สคริปต์นี้ในการใช้งานจริงและเกิดปัญหาการเชื่อมต่ออีกครั้ง สคริปต์จะอัปเดตสแต็กด้วยข้อมูลประจำตัวใหม่ ในกรณีนี้จะไม่มีอะไรเลวร้ายเกิดขึ้น อย่างไรก็ตาม ฉันละทิ้งแนวทางนี้และเริ่มใช้วิธีอื่นโดยระบุข้อมูลประจำตัวเพียงครั้งเดียว - เมื่อสร้างสแต็ก และต่อมา เมื่อสแต็กจำเป็นต้องอัปเดต แทนที่จะระบุค่าลับของพารามิเตอร์ ฉันจะใช้แทน UsePreviousValue=true:
aws cloudformation create-change-set
--change-set-name "$CHANGE_SET_NAME"
--stack-name "$STACK_NAME"
--template-body "$TPL_PATH"
--change-set-type "UPDATE"
--parameters "ParameterKey=MasterUserPassword,UsePreviousValue=true"
บทที่ 4: ใช้การกำหนดค่าการย้อนกลับ
อีกทีมหนึ่งที่ฉันร่วมงานด้วยใช้ฟังก์ชันนี้ เมฆ, เรียกว่า การกำหนดค่าย้อนกลับ. ฉันไม่เคยเจอมันมาก่อนและรู้ได้อย่างรวดเร็วว่ามันจะทำให้การปรับใช้สแต็กของฉันเจ๋งยิ่งขึ้นไปอีก ตอนนี้ฉันใช้มันทุกครั้งที่ปรับใช้โค้ดกับ lambda หรือ ECS โดยใช้ cloudformation
มันทำงานอย่างไร: คุณระบุ สัญญาณเตือน CloudWatch ในพารามิเตอร์ --ย้อนกลับการกำหนดค่าเมื่อคุณสร้างเซ็ตการแก้ไข ต่อมา เมื่อคุณดำเนินการเปลี่ยนแปลงชุดหนึ่ง aws จะตรวจสอบสัญญาณเตือนเป็นเวลาอย่างน้อยหนึ่งนาที โดยจะย้อนกลับการใช้งานหากสัญญาณเตือนเปลี่ยนสถานะเป็น ALARM ในช่วงเวลานี้
ด้านล่างนี้เป็นตัวอย่างของข้อความที่ตัดตอนมาจากเทมเพลต เมฆที่ฉันสร้างขึ้น นาฬิกาปลุก cloudwatchซึ่งติดตามตัววัดผู้ใช้ระบบคลาวด์เป็นจำนวนข้อผิดพลาดในบันทึกระบบคลาวด์ (ตัววัดถูกสร้างขึ้นผ่าน ตัวกรองเมตริก):
Resources:
# this metric tracks number of errors in the cloudwatch logs. In this
# particular case it's assumed logs are in json format and the error logs are
# identified by level "error". See FilterPattern
ErrorMetricFilter:
Type: AWS::Logs::MetricFilter
Properties:
LogGroupName: !Ref LogGroup
FilterPattern: !Sub '{$.level = "error"}'
MetricTransformations:
- MetricNamespace: !Sub "${AWS::StackName}-log-errors"
MetricName: Errors
MetricValue: 1
DefaultValue: 0
ErrorAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: !Sub "${AWS::StackName}-errors"
Namespace: !Sub "${AWS::StackName}-log-errors"
MetricName: Errors
Statistic: Maximum
ComparisonOperator: GreaterThanThreshold
Period: 1 # 1 minute
EvaluationPeriods: 1
Threshold: 0
TreatMissingData: notBreaching
ActionsEnabled: yes
ขณะนี้ ปลุก สามารถใช้เป็น ย้อนกลับ ทริกเกอร์เมื่อดำเนินการกล่องเครื่องมือ:
ALARM_ARN=$1
ROLLBACK_TRIGGER=$(cat <<EOF
{
"RollbackTriggers": [
{
"Arn": "$ALARM_ARN",
"Type": "AWS::CloudWatch::Alarm"
}
],
"MonitoringTimeInMinutes": 1
}
EOF
)
aws cloudformation create-change-set
--change-set-name "$CHANGE_SET_NAME"
--stack-name "$STACK_NAME"
--template-body "$TPL_PATH"
--change-set-type "UPDATE"
--rollback-configuration "$ROLLBACK_TRIGGER"
บทที่ 5: ตรวจสอบให้แน่ใจว่าคุณปรับใช้เทมเพลตเวอร์ชันล่าสุด
เป็นเรื่องง่ายที่จะปรับใช้เทมเพลต cloudformation เวอร์ชันที่น้อยกว่าล่าสุด แต่การทำเช่นนั้นจะทำให้เกิดความเสียหายอย่างมาก สิ่งนี้เกิดขึ้นกับเราครั้งหนึ่ง: นักพัฒนาไม่ได้ส่งการเปลี่ยนแปลงล่าสุดจาก Git และปรับใช้สแต็กเวอร์ชันก่อนหน้าโดยไม่รู้ตัว ซึ่งส่งผลให้แอปพลิเคชันที่ใช้สแต็กนี้หยุดทำงาน
บางสิ่งที่เรียบง่ายอย่างการเพิ่มการตรวจสอบเพื่อดูว่าสาขานั้นทันสมัยหรือไม่ก่อนที่จะยอมรับมันคงจะไม่เป็นไร (สมมติว่า git เป็นเครื่องมือควบคุมเวอร์ชันของคุณ):
git fetch
HEADHASH=$(git rev-parse HEAD)
UPSTREAMHASH=$(git rev-parse master@{upstream})
if [[ "$HEADHASH" != "$UPSTREAMHASH" ]] ; then
echo "Branch is not up to date with origin. Aborting"
exit 1
fi
บทที่ 6: อย่าสร้างล้อขึ้นมาใหม่
มันอาจดูเหมือนปรับใช้กับ เมฆ - มันเป็นเรื่องง่าย. คุณเพียงแค่ต้องมีสคริปต์ทุบตีจำนวนมากที่รันคำสั่ง aws cli
4 ปีที่แล้ว ฉันเริ่มต้นด้วยสคริปต์ง่ายๆ ที่เรียกว่าคำสั่ง aws cloudformation create-stack ในไม่ช้าสคริปต์ก็ไม่ง่ายอีกต่อไป แต่ละบทเรียนที่ได้เรียนรู้ทำให้สคริปต์มีความซับซ้อนมากขึ้นเรื่อยๆ มันไม่เพียงแต่ยากเท่านั้น แต่ยังเต็มไปด้วยข้อบกพร่องอีกด้วย
ปัจจุบันฉันทำงานในแผนกไอทีเล็กๆ ประสบการณ์ได้แสดงให้เห็นว่าแต่ละทีมมีวิธีปรับใช้สแต็ก Cloudformation ของตัวเอง และนั่นก็แย่ จะดีกว่าถ้าทุกคนใช้แนวทางเดียวกัน โชคดีที่มีเครื่องมือมากมายที่จะช่วยคุณปรับใช้และกำหนดค่าสแต็กของ Cloudformation
บทเรียนเหล่านี้จะช่วยให้คุณหลีกเลี่ยงข้อผิดพลาด
ที่มา: will.com