Terraform AWS Cloud: การจัดการโครงสร้างพื้นฐานที่ชาญฉลาด
เผยแพร่แล้ว: 2022-03-11การเขียนใบสมัครเป็นเพียงส่วนหนึ่งของเรื่องราวเท่านั้น เพื่อให้มีมูลค่า จำเป็นต้องปรับใช้ที่ไหนสักแห่งที่สามารถปรับขนาดได้ ต้องทำงานด้วยความพร้อมใช้งานสูง ต้องมีการสำรองข้อมูลและอื่น ๆ
นักพัฒนาจำนวนมากขึ้นเรื่อยๆ จำเป็นต้องเข้าใจกระบวนการปรับใช้นี้อย่างน้อยที่สุด สิ่งนี้แสดงให้เห็น ตัวอย่างเช่น ใน DevOps กลายเป็นบทบาทที่ได้รับการร้องขอบ่อยครั้งในปัจจุบัน เนื่องจากความซับซ้อนของระบบเพิ่มขึ้น เราไม่สามารถละเลยการเปลี่ยนแปลงเหล่านั้นได้ และจำเป็นต้องตระหนักถึงวิธีออกแบบแอปพลิเคชันให้ปรับใช้ได้ง่าย
สิ่งนี้เป็นที่สนใจของลูกค้าของเราเช่นกัน พวกเขาจ้างเราเป็นผู้เชี่ยวชาญในสาขาของเราและคาดหวังให้เราส่งมอบผลิตภัณฑ์ทั้งหมด บ่อยครั้งตั้งแต่ต้นจนจบ พวกเขามีข้อกำหนดและมักจะลืมไปว่าโซลูชันทางธุรกิจของตนทำงานอย่างไร ท้ายที่สุดแล้ว คุณค่าทางธุรกิจของผลิตภัณฑ์นั้นสำคัญไฉน
ขอแนะนำ Terraform
การปรับใช้และการจัดการโครงสร้างพื้นฐานไม่ใช่กระบวนการง่ายๆ นอกเหนือจากความเชี่ยวชาญด้านโดเมนที่เปลี่ยนแปลงตลอดเวลา เราจำเป็นต้องเรียนรู้ เครื่องมืออื่น หรือเวิร์กโฟลว์ใหม่ หากคุณหยุดทำสิ่งนี้ บทความนี้เป็นโอกาสที่คุณจะได้ทำความคุ้นเคยกับแนวทางเดียวในการจัดการโครงสร้างพื้นฐาน ฉันหวังว่าในท้ายที่สุด คุณจะมั่นใจมากขึ้นในการใช้ Terraform และรู้เพิ่มเติมเกี่ยวกับแนวทางและความท้าทายที่เป็นไปได้ คุณควรจะสามารถใช้เครื่องมือนี้เพื่อเริ่มจัดการบางส่วนของโครงสร้างพื้นฐานระบบคลาวด์ของคุณเป็นอย่างน้อย
Terraform เป็นเลเยอร์นามธรรม ใช่ และสิ่งที่เป็นนามธรรมก็รั่ว ฉันเห็นด้วย แต่สุดท้ายแล้ว เราอยู่ในธุรกิจของการแก้ปัญหาและจัดการสิ่งที่เป็นนามธรรม เป้าหมายนี้มีจุดมุ่งหมายเพื่อให้เรามีสุขภาพจิตที่ดีในงานประจำวันของเรา
เป้าหมาย
ฉันจะอธิบายว่า Terraform คืออะไร มันเข้ากับระบบนิเวศทั้งหมดอย่างไร และเปรียบเทียบกับเครื่องมืออื่นๆ ที่คล้ายคลึงกันอย่างไร จากนั้น ฉันจะแสดงขั้นตอนที่จำเป็นในการกำหนดค่าการตั้งค่า Terraform แบบหลายสภาพแวดล้อมและพร้อมสำหรับการผลิตสำหรับทีม ฉันจะอธิบายพื้นฐานการเขียนการกำหนดค่า Terraform—วิธีจัดการความซับซ้อนและโค้ดที่ซ้ำกันด้วย โมดูล ที่แชร์ได้
ตัวอย่างทั้งหมดจะเน้นที่ผู้ให้บริการระบบคลาวด์รายเดียว: Amazon Web Services (AWS) นี่เป็นเพียงระบบคลาวด์ที่ฉันมีประสบการณ์มากที่สุด แต่ข้อมูลทั้งหมดควรนำไปใช้กับคลาวด์อื่นด้วย
ฉันจะปิดท้ายด้วยบันทึกย่อที่ฉันหวังว่าฉันจะรู้เมื่อเริ่มต้น: ไวยากรณ์ gotchas, นิสัยใจคอ และกรณีที่ Terraform จะไม่เป็นเครื่องมือที่ฉันเลือก
ฉันจะไม่เน้นรายละเอียดเล็ก ๆ น้อย ๆ ของไวยากรณ์ คุณสามารถดำเนินการได้อย่างรวดเร็วโดยอ่านเอกสารและคำแนะนำที่ยอดเยี่ยมที่ HashiCorp จัดเตรียมไว้สำหรับ Terraform ฉันต้องการมุ่งเน้นไปที่สิ่งที่อาจไม่ชัดเจนตั้งแต่เริ่มต้น และฉันหวังว่าฉันจะรู้ก่อนที่จะเริ่มทำงานกับ Terraform หวังว่านี่จะนำทางคุณไปในทิศทางที่ถูกต้องและช่วยให้คุณพิจารณา Terraform เป็นเครื่องมือสำหรับใช้ในโครงการในอนาคต
การจัดการโครงสร้างพื้นฐานเป็นเรื่องยาก
มีหลายขั้นตอนที่เกี่ยวข้องในการตั้งค่าสภาพแวดล้อมสำหรับแอปในระบบคลาวด์ เว้นแต่คุณจะจดทั้งหมดเป็นรายการตรวจสอบโดยละเอียดและปฏิบัติตามอย่างเคร่งครัด ตลอดเวลา คุณจะทำผิดพลาด เราเป็นมนุษย์หลังจากทั้งหมด ขั้นตอนเหล่านั้นยากที่จะแบ่งปัน คุณต้องจัดทำเอกสารขั้นตอนการทำงานด้วยตนเองจำนวนมาก และเอกสารอาจล้าสมัยได้อย่างรวดเร็ว ตอนนี้คูณทั้งหมดนั้นด้วยจำนวนสภาพแวดล้อมทั้งหมดสำหรับแอปเดียว: dev , test/qa , stage และ prod คุณต้องคำนึงถึงความปลอดภัยสำหรับแต่ละรายการด้วย
เครื่องมือทุกชิ้นไม่มี UI ที่ฉันสามารถใช้ได้และลืมความซับซ้อนไปได้เลยใช่หรือไม่
พวกเขามี UI—AWS Management Console เป็นตัวอย่างที่สำคัญ แต่เครื่องมือเหล่านั้นทำอะไรได้หลายอย่างภายใต้ประทุน การคลิกเพียงครั้งเดียวบน UI อาจก่อให้เกิดการเปลี่ยนแปลงที่ยากจะเข้าใจ โดยปกติแล้วจะไม่มีทางเลิกทำสิ่งที่คุณทำใน UI (ข้อความแจ้ง "คุณแน่ใจหรือไม่" ตามปกติมักไม่เพียงพอ) นอกจากนี้ ควรมีตาคู่ที่สองเพื่อตรวจสอบการเปลี่ยนแปลงเสมอ แต่เมื่อเราใช้ UI เราจะต้องนั่งกับบุคคลนี้ร่วมกันหรือตรวจสอบการเปลี่ยนแปลงของเรา หลังจาก ที่ทำเสร็จแล้ว ซึ่งเป็นการตรวจสอบมากกว่า ทบทวน. ผู้ให้บริการระบบคลาวด์แต่ละรายมี UI ของตัวเองซึ่งคุณต้องเชี่ยวชาญ UI ได้รับการออกแบบมาให้ใช้งานง่าย (ไม่จำเป็นต้องง่ายเสมอไป!) และด้วยเหตุนี้จึงมีแนวโน้มที่จะเข้าใจผิด เช่น "นี่เป็นเพียงการปรับแต่งเล็กน้อย" หรือโปรแกรมแก้ไขด่วนสำหรับการผลิตแบบด่วนที่คุณจะลืมได้ภายใน 48 ชั่วโมง การคลิกแบบแมนนวลดังกล่าวทำได้ยากเช่นกัน
แล้วเครื่องมือ CLI ล่ะ?
จะดีกว่าเครื่องมือ UI สำหรับกรณีการใช้งานของเรา อย่างไรก็ตาม คุณยังคงมีแนวโน้มที่จะทำการเปลี่ยนแปลงด้วยมือหรือเขียนสคริปต์ทุบตีซึ่งสามารถหลุดพ้นจากมือได้อย่างง่ายดาย นอกจากนี้ ผู้ให้บริการแต่ละรายมีเครื่องมือ CLI ของตนเอง ด้วยเครื่องมือเหล่านี้ คุณจะไม่เห็นการเปลี่ยนแปลงของคุณก่อนที่จะทำการเปลี่ยนแปลง โชคดีที่นี่ไม่ใช่ปัญหาใหม่และมีเครื่องมือที่ช่วยในเรื่องนี้
Orchestration กับ Configuration Management
ฉันจะกำหนดประเภทของเครื่องมือและแนวปฏิบัติที่ใช้ในการจัดการโครงสร้างพื้นฐาน สิ่งเหล่านี้คือการจัดการการประสานและการกำหนดค่า คุณสามารถคิดคร่าวๆ ว่าเป็นโมเดลการเขียนโปรแกรมที่เปิดเผยและจำเป็น (คิดว่า Prolog กับ Python) แต่ละคนมีข้อดีและข้อเสียของตัวเอง แต่ควรรู้จักพวกเขาทั้งหมดและใช้เครื่องมือที่ดีที่สุดสำหรับงานที่กำหนด นอกจากนี้ การประสานมักเกี่ยวข้องกับระดับนามธรรมที่สูงกว่าการจัดการการกำหนดค่า
ประสานเสียง
Orchestration คล้ายกับกระบวนทัศน์การเขียนโปรแกรมที่เปิดเผยมากกว่า ฉันชอบคิดว่ามันเป็นวาทยกรของวงออเคสตรา วิกิพีเดีย (ลิงก์) ทำงานเป็นวาทยกรได้อย่างดีว่าเป็น "ศิลปะในการกำกับการแสดงพร้อมกันของผู้เล่นหรือนักร้องหลายคนโดยใช้ท่าทาง" ผู้ควบคุมวงจะสื่อสารจังหวะและจังหวะ ไดนามิก และการชี้นำของดนตรี แต่งานจริงดำเนินการโดยนักดนตรีแต่ละคนซึ่งเป็นผู้เชี่ยวชาญในการเล่นเครื่องดนตรีของตน หากปราศจากการประสานงานกันเช่นนี้ พวกเขาก็จะไม่สามารถแสดงผลงานที่สมบูรณ์แบบได้
นี่คือที่ที่ Terraform เหมาะกับ คุณใช้เพื่อดำเนินการโครงสร้างพื้นฐานด้านไอที: คุณบอกว่าจะใช้งานอะไร และ Terraform เชื่อมโยงทั้งหมดเข้าด้วยกันและดำเนินการเรียก API ที่จำเป็นทั้งหมด มีเครื่องมือที่คล้ายกันในพื้นที่นี้ หนึ่งในที่รู้จักกันดีที่สุดคือ AWS Cloud Formation มีการรองรับการกู้คืนและการย้อนกลับในกรณีที่เกิดข้อผิดพลาดได้ดีกว่า Terraform แต่ในความคิดของฉันก็มีช่วงการเรียนรู้ที่ชันกว่า นอกจากนี้ยังไม่ใช่ระบบไม่เชื่อเรื่องพระเจ้า: ใช้งานได้กับ AWS เท่านั้น
การจัดการการตั้งค่า
ด้านเสริมของแนวทางปฏิบัติเหล่านี้คือแนวทางการจัดการการตั้งค่าคอนฟิก ในกระบวนทัศน์นี้ คุณระบุขั้นตอนที่แน่นอนที่เครื่องมือต้องทำเพื่อให้ได้การกำหนดค่าที่ต้องการ ขั้นตอนเหล่านี้อาจมีขนาดเล็กและรองรับระบบปฏิบัติการหลายระบบ แต่คุณต้องคำนึงถึงลำดับของการดำเนินการอย่างจริงจัง พวกเขาไม่มีความตระหนักรู้ถึงสถานะปัจจุบันและสภาพแวดล้อม (เว้นแต่คุณจะตั้งโปรแกรมไว้ด้วย) และด้วยเหตุนี้ พวกเขาจะสุ่มสี่สุ่มห้าดำเนินการตามขั้นตอนที่คุณให้ไว้ ซึ่งอาจนำไปสู่ปัญหาที่เรียกว่า การกำหนดค่าลอยตัว ซึ่งทรัพยากรของคุณจะค่อยๆ ยกเลิกการซิงโครไนซ์กับสิ่งที่พวกเขาตั้งใจจะนำเสนอในตอนแรก โดยเฉพาะอย่างยิ่งหากคุณทำการเปลี่ยนแปลงด้วยตนเองบางอย่างกับทรัพยากรเหล่านี้ พวกมันยอดเยี่ยมในการจัดการและจัดเตรียมบริการในแต่ละอินสแตนซ์ ตัวอย่างของเครื่องมือที่ยอดเยี่ยมในเวิร์กโฟลว์นี้คือ Chef, Puppet, Ansible และ Salt
Orchestration บังคับใช้แนวทางในโครงสร้างพื้นฐานของคุณ ซึ่งคุณปฏิบัติต่อทรัพยากรของคุณเหมือนปศุสัตว์ ไม่ใช่สัตว์เลี้ยง แทนที่จะ "ดูแล" VPS แต่ละรายการด้วยตนเอง คุณสามารถแทนที่ด้วยสำเนาที่ถูกต้องเมื่อมีบางอย่างผิดพลาด ฉันไม่ได้หมายความว่าคุณไม่สนใจและเริ่มต้นสิ่งใหม่โดยหวังว่าจะดีที่สุด
คุณควรตรวจสอบและแก้ไขปัญหา ในโค้ด แล้วปรับใช้แทน
สามารถใช้ Ansible (และเครื่องมือ CM อื่นๆ) เพื่อจัดการโครงสร้างพื้นฐานของ AWS ได้ แต่จะต้องใช้ความพยายามอย่างมากและมีโอกาสเกิดข้อผิดพลาดได้มากกว่า โดยเฉพาะอย่างยิ่งเมื่อโครงสร้างพื้นฐานมีการเปลี่ยนแปลงบ่อยครั้งและมีความซับซ้อนเพิ่มขึ้น
สิ่งสำคัญอย่างหนึ่งที่ต้องจำไว้คือวิธีการจัดการการประสานและการกำหนดค่าจะไม่ขัดแย้งกัน พวกเขาเข้ากันได้ เป็นเรื่องปกติที่จะมีกลุ่มของอินสแตนซ์ EC2 (VPS) ในกลุ่ม AutoScaling ที่จัดการโดย Terraform แต่เรียกใช้ AWS Application Image (AMI) ซึ่งเป็นสแนปชอตของดิสก์ที่จัดเตรียมด้วยขั้นตอนที่จำเป็น เช่น Ansible . Terraform ยังมีแนวคิดของ "ผู้ให้บริการ" ที่ช่วยให้คุณสามารถเรียกใช้เครื่องมือจัดเตรียมภายนอกได้เมื่อเครื่องเริ่มทำงาน
เอกสารประกอบของ Terraform ช่วยให้คุณอธิบายเพิ่มเติมและช่วยให้คุณวาง Terraform ไว้ในระบบนิเวศทั้งหมดได้
Terraform คืออะไร?
เป็นเครื่องมือโอเพ่นซอร์สที่สร้างโดย HashiCorp ที่ให้คุณเข้ารหัสโครงสร้างพื้นฐานของคุณเป็นไฟล์การกำหนดค่าที่เปิดเผยซึ่งมีการกำหนดเวอร์ชันและแชร์และสามารถตรวจสอบได้
ชื่อ HashiCorp ควรส่งเสียงกริ่ง—พวกเขายังสร้าง Nomad, Vault, Packer, Vagrant และ Consul หากคุณเคยใช้สิ่งเหล่านี้ เครื่องมือที่คุณรู้อยู่แล้วถึงคุณภาพของเอกสาร ชุมชนที่มีชีวิตชีวา และประโยชน์ที่คุณคาดหวังได้จากโซลูชันของพวกเขา
โครงสร้างพื้นฐานเป็นรหัส
Terraform เป็นแพลตฟอร์มที่ไม่เชื่อเรื่องพระเจ้า คุณสามารถใช้เพื่อจัดการเซิร์ฟเวอร์ Bare Metal หรือเซิร์ฟเวอร์คลาวด์ เช่น AWS, Google Cloud Platform, OpenStack และ Azure ในศัพท์แสงของ Terraform สิ่งเหล่านี้เรียกว่า ผู้ให้บริการ คุณสามารถทำความเข้าใจเกี่ยวกับมาตราส่วนได้โดยการอ่านรายชื่อผู้ให้บริการที่รองรับทั้งหมด สามารถใช้ผู้ให้บริการหลายรายพร้อมกันได้ เช่น เมื่อผู้ให้บริการ A กำหนดค่า VM ให้คุณ แต่ผู้ให้บริการ B จะกำหนดค่าและมอบสิทธิ์ระเบียน DNS
นั่นหมายความว่าเราสามารถสลับผู้ให้บริการคลาวด์ด้วยการเปลี่ยนแปลงในไฟล์ปรับแต่งได้หรือไม่? ไม่ ฉันไม่คิดว่าคุณต้องการอย่างนั้น อย่างน้อยก็ไม่ใช่ด้วยวิธีอัตโนมัติ ปัญหาคือผู้ให้บริการที่แตกต่างกันอาจมีความสามารถที่แตกต่างกัน ข้อเสนอที่แตกต่างกัน โฟลว์ แนวคิด ฯลฯ หมายความว่าคุณจะต้องใช้ทรัพยากรที่แตกต่างกันสำหรับผู้ให้บริการรายอื่นเพื่อแสดงแนวคิดเดียวกัน อย่างไรก็ตาม ทั้งหมดนี้สามารถทำได้ในไวยากรณ์การกำหนดค่าเดียวที่คุ้นเคย และเป็นส่วนหนึ่งของเวิร์กโฟลว์ที่เชื่อมโยงกัน
ส่วนสำคัญของการตั้งค่า Terraform
- ไบนารีของ Terraform นั้นคุณต้องติดตั้ง
- ไฟล์ซอร์สโค้ด เช่น การกำหนดค่าของคุณ
- สถานะ (ทั้งในพื้นที่หรือระยะไกล) ที่แสดงถึงทรัพยากรที่ Terraform จัดการ (เพิ่มเติมในภายหลัง)
การเขียนการกำหนดค่า Terraform
คุณเขียนโค้ดการกำหนดค่า Terraform ในไฟล์ *.tf
โดยใช้ภาษา HCL มีตัวเลือกให้ใช้รูปแบบ JSON ( *.tf.json
) แต่มีการกำหนดเป้าหมายที่เครื่องและการสร้างอัตโนมัติมากกว่ามนุษย์ ฉันแนะนำให้คุณใช้ HCL ฉันจะไม่ดำดิ่งลงไปในไวยากรณ์ของภาษา HCL; เอกสารอย่างเป็นทางการทำงานได้อย่างยอดเยี่ยมในการอธิบายวิธีเขียน HCL และวิธีใช้ตัวแปรและการแก้ไข ฉันจะพูดถึงเฉพาะขั้นต่ำที่จำเป็นในการทำความเข้าใจตัวอย่างเท่านั้น
ภายในไฟล์ Terraform คุณจะจัดการกับ ทรัพยากร และ แหล่งข้อมูล เป็นส่วนใหญ่ ทรัพยากรแสดงถึงส่วนประกอบของโครงสร้างพื้นฐานของคุณ เช่น อินสแตนซ์ AWS EC2, อินสแตนซ์ RDS, ระเบียน DNS ของ Route53 หรือกฎในกลุ่มความปลอดภัย อนุญาตให้คุณจัดเตรียมและเปลี่ยนแปลงภายในสถาปัตยกรรมคลาวด์
สมมติว่าคุณได้ตั้งค่า Terraform แล้ว หากคุณออก terraform apply
โค้ดด้านล่างจะสร้างอินสแตนซ์ EC2 ที่ทำงานได้อย่างสมบูรณ์ (แสดงเฉพาะคุณสมบัติบางอย่างเท่านั้น):
resource "aws_instance" "bastion" { ami = "ami-db1688a2" # Amazon Linux 2 LTS Candidate AMI 2017.12.0 (HVM), SSD Volume Type - ami-db1688a2 instance_type = "t2.nano" key_name = "${var.key_name}" subnet_ vpc_security_group_ids = ["${aws_security_group.bastion.id}"] monitoring = "false" associate_public_ip_address = "true" disable_api_termination = "true" tags = { Name = "${var.project_tag}-bastion-${var.env}" Env = "${var.env}" Application ApplicationRole = "Bastion Host" Project = "${var.project_tag}" } }
ในทางกลับกัน มีแหล่งข้อมูลที่ให้คุณอ่านข้อมูลเกี่ยวกับส่วนประกอบที่กำหนดโดยไม่ต้องเปลี่ยนแปลง คุณต้องการรับ AWS ID (ARN) ของใบรับรองที่ออกโดย ACM หรือไม่ คุณใช้แหล่งข้อมูล ข้อแตกต่างคือแหล่งข้อมูลจะขึ้นต้นด้วย data_
เมื่ออ้างอิงถึงแหล่งที่มาในไฟล์คอนฟิกูเรชัน
data "aws_acm_certificate" "ssl_cert" { domain = "*.example.com" statuses = ["ISSUED"] }
ข้อมูลข้างต้นอ้างอิงถึงใบรับรอง ACM SSL ที่ออกให้ซึ่งสามารถใช้ร่วมกับ AWS ALB ได้ ก่อนที่คุณจะทำอย่างนั้น คุณต้องตั้งค่าสภาพแวดล้อมของคุณเสียก่อน
โครงสร้างโฟลเดอร์
สภาพแวดล้อม Terraform (และสถานะ) ถูกคั่นด้วยไดเร็กทอรี Terraform โหลดไฟล์ *.tf
ทั้งหมดในไดเร็กทอรีลงในเนมสเปซเดียว ดังนั้นลำดับจึงไม่สำคัญ ฉันแนะนำโครงสร้างไดเร็กทอรีต่อไปนี้:
/terraform/ |---> default_variables.tf (1) /stage/ (2) |---> terraform.tfvars (3) |---> default_variables.tf (4) |---> terraform.tf (5) |---> env_variables.tf (6) /prod/ /<env_name>/
-
default_variables.tf
– กำหนดตัวแปรระดับบนสุดทั้งหมดและเลือกค่าเริ่มต้นของตัวแปรเหล่านั้น สามารถใช้ซ้ำได้ในแต่ละสภาพแวดล้อม (ไดเรกทอรีที่ซ้อนกัน) พร้อมลิงก์สัญลักษณ์ -
/stage/
– ไดเร็กทอรีที่เก็บการกำหนดค่าสำหรับสภาพแวดล้อมที่แยกจากกันทั้งหมด (ในที่นี้มีชื่อว่าstage
แต่สามารถเป็นอะไรก็ได้) การเปลี่ยนแปลงใด ๆ ที่เกิดขึ้นภายในโฟลเดอร์นี้เป็นอิสระจากสภาพแวดล้อมอื่น ๆ โดยสิ้นเชิง (env—likeprod
) ซึ่งเป็นสิ่งที่คุณต้องการเพื่อหลีกเลี่ยงความยุ่งเหยิงในการผลิต env ด้วยการเปลี่ยนแปลงที่เกิดขึ้นกับstage
! -
terraform.tfvars
– กำหนดค่าตัวแปร ไฟล์.tfvars
คล้ายกับไฟล์ ..env
จะมีคู่key=val
สำหรับตัวแปรที่กำหนด ตัวอย่างเช่น สิ่งนี้ระบุprofile
AWS , AWSkey_name
และ AWSkey_path
ที่ฉันใช้ สามารถละเว้นได้ใน Git -
default_variables.tf
– นี่คือการเชื่อมโยงไปยังไฟล์ (2) ซึ่งช่วยให้เราแบ่งปันตัวแปรที่ไม่ขึ้นกับสิ่งแวดล้อมโดยไม่ต้องทำซ้ำตัวเอง -
terraform.tf
– นี่คือการกำหนดค่าหลักของแต่ละ env; มันเก็บบล็อกterraform {}
ซึ่งกำหนดค่าแบ็คเอนด์ ฉันยังกำหนดค่า ผู้ให้บริการ ที่นี่ -
env_variables.tf
– ไฟล์นี้มีตัวแปรเฉพาะของ env ฉันแท็กทรัพยากรทั้งหมดด้วยEnv=<env_name>
ใน AWS ดังนั้นไฟล์นี้มักจะกำหนดตัวแปรเดียวเท่านั้น:env
แน่นอนว่านี่ไม่ใช่วิธีเดียวในการจัดโครงสร้างสภาพแวดล้อมของคุณ นี่เป็นเพียงสิ่งที่ใช้ได้ผลดีสำหรับฉันโดยทำให้สามารถแยกข้อกังวลต่างๆ ออกได้อย่างชัดเจน
การกำหนดค่าส่วนหลัง
ฉันได้กล่าวถึงสถานะ Terraform แล้ว นี่เป็นส่วนสำคัญของเวิร์กโฟลว์ Terraform คุณอาจสงสัยว่าจำเป็นต้องมีสถานะจริงหรือไม่ Terraform ไม่สามารถค้นหา AWS API ตลอดเวลาเพื่อรับสถานะที่แท้จริงของโครงสร้างพื้นฐานได้หรือไม่ ถ้าคุณลองคิดดูแล้ว Terraform จำเป็นต้องรักษาการแมประหว่างสิ่งที่จัดการในไฟล์การกำหนดค่าที่เปิดเผยและไฟล์เหล่านั้นที่สัมพันธ์กันจริง ๆ (ในสภาพแวดล้อมของผู้ให้บริการคลาวด์) โปรดทราบว่าในขณะที่เขียนไฟล์การกำหนดค่า Terraform คุณไม่สนใจ ID ของอินสแตนซ์ EC2 แต่ละรายการหรือ ARN ที่จะสร้างขึ้นสำหรับกลุ่มความปลอดภัยที่คุณเผยแพร่ อย่างไรก็ตาม ภายใน Terraform จำเป็นต้องรู้ว่าบล็อกทรัพยากรที่กำหนดแสดงถึงทรัพยากรที่เป็นรูปธรรมด้วย ID/ARN สิ่งนี้จำเป็นสำหรับการตรวจจับการเปลี่ยนแปลง นอกจากนี้ state ยังใช้เพื่อติดตามการขึ้นต่อกันระหว่างทรัพยากรต่างๆ (รวมถึงสิ่งที่คุณมักจะไม่ต้องนึกถึงด้วย!) พวกมันถูกใช้เพื่อสร้างกราฟที่สามารถ (โดยปกติ) ขนานและดำเนินการได้ และเช่นเคย ฉันแนะนำให้คุณอ่านเอกสารที่ดีเยี่ยมเกี่ยวกับสถานะ Terraform และจุดประสงค์ของมัน
เนื่องจากสถานะเป็นแหล่งความจริงเพียงแหล่งเดียวสำหรับสถาปัตยกรรมของคุณ คุณต้องแน่ใจว่าคุณและทีมของคุณกำลังทำงานในเวอร์ชันล่าสุดอยู่เสมอ และคุณไม่ได้สร้างความขัดแย้งด้วยการเข้าถึงสถานะแบบไม่ซิงโครไนซ์ คุณไม่ต้องการแก้ไขข้อขัดแย้งในการผสานในไฟล์สถานะ เชื่อฉัน
โดยค่าเริ่มต้น Terraform จะจัดเก็บสถานะในไฟล์บนดิสก์ ซึ่งอยู่ในไดเร็กทอรีการทำงานปัจจุบัน (ของแต่ละ env) เป็นไฟล์ terraform.tfstate
ไม่เป็นไรถ้าคุณรู้ว่าคุณจะเป็นนักพัฒนาเพียงคนเดียวในงานหรือกำลังเรียนรู้และทดลองกับ Terraform ในทางเทคนิค คุณสามารถทำให้มันทำงานเป็นทีมได้ เนื่องจากคุณสามารถส่งสถานะไปยังที่เก็บ VCS ได้ แต่จากนั้น คุณจะต้องตรวจสอบให้แน่ใจว่าทุกคนกำลังทำงานในเวอร์ชันล่าสุดอยู่เสมอ และไม่มีใครเปลี่ยนแปลงในเวลาเดียวกัน! นี่เป็นอาการปวดศีรษะที่สำคัญและฉันขอแนะนำอย่างยิ่ง นอกจากนี้ หากมีคนเข้าร่วมการดำเนินการพัฒนาเดี่ยวของคุณ คุณยังต้องกำหนดค่าสถานที่อื่นสำหรับสถานะ
โชคดีที่นี่เป็นปัญหากับโซลูชันที่ดีที่สร้างไว้ใน Terraform: Remote State ที่เรียกว่า เพื่อให้สถานะระยะไกลทำงานได้ คุณต้องกำหนดค่าแบ็คเอนด์โดยใช้หนึ่งในผู้ให้บริการแบ็คเอนด์ที่มีอยู่ ตัวอย่างแบ็กเอนด์ต่อไปนี้จะอิงตาม AWS S3 และ AWS DynamoDB (ฐานข้อมูล AWS NoSQL) คุณสามารถใช้ S3 เท่านั้น แต่จากนั้นคุณจะสูญเสียกลไกการล็อกสถานะและการตรวจสอบความสอดคล้อง (ไม่แนะนำ) หากคุณเคยใช้สถานะท้องถิ่นเท่านั้น การกำหนดค่าแบ็คเอนด์ระยะไกลจะมีตัวเลือกให้คุณย้ายสถานะของคุณในครั้งแรก ดังนั้นคุณจะไม่สูญเสียอะไรเลย คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการกำหนดค่าส่วนหลังได้ที่นี่
ขออภัย มีปัญหาไก่กับไข่: ต้องสร้างที่ฝากข้อมูล S3 และตาราง DynamoDB ด้วยตนเอง Terraform ไม่สามารถสร้างได้โดยอัตโนมัติเนื่องจากยังไม่มีสถานะ! มีวิธีแก้ปัญหาบางอย่างเช่น https://github.com/gruntwork-io/terragrunt ที่ทำให้ใช้ AWS CLI โดยอัตโนมัติ แต่ฉันไม่ต้องการเบี่ยงเบนจากหัวข้อหลักของโพสต์บล็อกนี้
สิ่งสำคัญที่ควรทราบเกี่ยวกับการกำหนดค่าแบ็กเอนด์ S3 และ DynamoDB คือ:
- เปิดใช้งานการกำหนดเวอร์ชันบนบัคเก็ต S3 เพื่อความปลอดภัยจากความผิดพลาดของมนุษย์และกฎของเมอร์ฟี
- ตาราง DynamoDB มีการจำกัดอัตราการอ่านและเขียน (เรียกว่าความจุ) หากคุณทำการเปลี่ยนแปลงจำนวนมากในสถานะระยะไกล ตรวจสอบให้แน่ใจว่าได้เปิดใช้งาน DynamoDB AutoScaling สำหรับตารางนั้น หรือกำหนดค่าขีดจำกัด R/W ที่เพียงพอ มิฉะนั้น Terraform จะได้รับข้อผิดพลาด HTTP 400 จาก AWS API เมื่อดำเนินการเรียกจำนวนมาก
โดยสรุปแล้ว การกำหนดค่าส่วนหลังต่อไปนี้สามารถวางใน terraform.tf
เพื่อกำหนดค่าสถานะระยะไกลบน S3 และ DynamoDB
terraform { # Sometimes you may want to require a certain version of Terraform required_version = ">= 0.11.7" # Stores remote state, required for distributed teams # Bucket & dynamoDB table have to be created manually if they do not exist # See: https://github.com/hashicorp/terraform/issues/12780 backend "s3" { bucket = "my-company-terraform-state" key = "app-name/stage" region = "eu-west-1" # 5/5 R/W Capacity might not be enough for heavy, burst work (resulting in 400s). Consider enabling Auto Scaling on the table. # See: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ProvisionedThroughput.html dynamodb_table = "terraform-state-lock-table" } }
สิ่งนี้มีหลายอย่างที่ต้องทำในคราวเดียว แต่จำไว้ว่า คุณทำสิ่งนี้ครั้งเดียวสำหรับแต่ละ env แล้วลืมมันไปได้ หากคุณต้องการการควบคุมการล็อกสถานะมากขึ้น มี HashiCorp Terraform Enterprise แต่ฉันจะไม่ครอบคลุมที่นี่
ผู้ให้บริการ
เพื่อให้แบ็คเอนด์เข้าถึงได้และสามารถสื่อสารกับผู้ให้บริการระบบคลาวด์ของเราได้เลย เราจำเป็นต้องกำหนดค่าสิ่งที่เรียกว่า ผู้ให้บริการ สามารถวางบล็อกต่อไปนี้ในไฟล์ terraform.tf
(สำหรับแต่ละ env):
provider "aws" { profile = "${var.profile}" region = "${var.region}" version = "~> 1.23.0" }
ตัวแปรสำหรับ profile
และ region
ถูกเก็บไว้ในไฟล์ terraform.tfvars
ซึ่งอาจถูกละเว้น ตัวแปร profile
หมายถึงโปรไฟล์ที่มีชื่อซึ่งถือใบรับรองความปลอดภัยสำหรับ AWS Cloud โดยใช้ไฟล์ข้อมูลรับรองมาตรฐาน โปรดทราบว่าฉันกำลังตั้งค่าข้อจำกัดบางเวอร์ชันด้วย คุณไม่ต้องการให้ Terraform อัปเกรดปลั๊กอินผู้ให้บริการของคุณโดยที่คุณไม่รู้เกี่ยวกับการเริ่มต้นแบ็คเอนด์ทุกครั้ง โดยเฉพาะอย่างยิ่งเมื่อมีผู้ให้บริการ AWS เวอร์ชัน 2.x ที่ต้องอัปเกรดอย่างระมัดระวัง
การเริ่มต้นแบ็คเอนด์
การกำหนดค่าแบ็คเอนด์แต่ละรายการต้องมีขั้นตอนการเริ่มต้นที่จุดเริ่มต้น และทุกครั้งที่มีการเปลี่ยนแปลง การเริ่มต้นยังกำหนดค่าโมดูล Terraform (เพิ่มเติมในภายหลัง) ดังนั้นเมื่อคุณเพิ่มสิ่งเหล่านี้ คุณต้องเรียกใช้ขั้นตอน init อีกครั้งด้วย การดำเนินการนี้สามารถทำได้อย่างปลอดภัยหลายครั้ง โปรดทราบว่า ในระหว่างการเริ่มต้นของแบ็คเอนด์ Terraform ไม่สามารถอ่านตัวแปรทั้งหมดเพื่อกำหนดค่าสถานะได้ และไม่ควรอ่านด้วยเหตุผลด้านความปลอดภัย (เช่น คีย์ลับ) เพื่อแก้ปัญหานี้ และในกรณีของเรา ให้ใช้โปรไฟล์ AWS ที่แตกต่างจากค่าเริ่มต้น คุณสามารถใช้ตัวเลือก -backend-config
โดยยอมรับคู่ตัวแปร k=v
สิ่งนี้เรียกว่าการกำหนดค่าบางส่วน

terraform init -backend-config=profile=<aws_profile_name>
ไฟล์ Terraform แบ่งปันขอบเขตที่จำกัดอยู่ในไดเร็กทอรีที่กำหนด ซึ่งหมายความว่าโฟลเดอร์ย่อยไม่ได้เชื่อมต่อโดยตรงกับรหัสไดเรกทอรีหลัก อย่างไรก็ตาม เป็นการกำหนดโมดูลที่อนุญาตให้ใช้รหัสซ้ำ การจัดการความซับซ้อน และการแบ่งปัน
เวิร์กโฟลว์
เวิร์กโฟลว์ทั่วไปเมื่อทำงานกับโค้ด Terraform มีดังนี้:
- เขียนการกำหนดค่าสำหรับโครงสร้างพื้นฐานของคุณ
- ดูสิ่งที่จะทำการเปลี่ยนแปลงจริง (
terraform plan
) - ทางเลือก ดำเนิน การเปลี่ยนแปลงที่ คุณเห็นในขั้นตอนที่ 2 (
terraform apply
) - GOTO 1
แผนดินเผา
คำสั่ง plan
Terraform จะแสดงรายการการเปลี่ยนแปลงที่จะดำเนินการกับโครงสร้างพื้นฐานของคุณเมื่อออกคำสั่ง apply
การออก plan
หลายครั้งนั้นปลอดภัย เนื่องจากไม่เปลี่ยนแปลงอะไรเลย
วิธีอ่านแผน
ออบเจ็กต์ใน Terraform (ทรัพยากรและแหล่งข้อมูล) สามารถระบุได้อย่างง่ายดายด้วยชื่อที่มีคุณสมบัติครบถ้วน
- ในกรณีของทรัพยากร ID อาจมีลักษณะดังนี้:
<resource_type>.<resource_name>
—eg,aws_ecs_service.this
- ในกรณีของทรัพยากรภายในโมดูล เรามีชื่อโมดูลเพิ่มเติม:
module.<module_name>.<resource_type>.<resource_name>
—eg,module.my_service_ecs_service_task.aws_ecs_service.this
- แหล่งข้อมูล (ภายในและภายนอกโมดูล):
(module.<module_name>).data.<resource_type>.<resource_name>
—eg,module.my_service_ecs_service_task.data.aws_ecs_task_definition.this
ประเภททรัพยากรเป็นข้อมูลเฉพาะสำหรับผู้ให้บริการรายใดรายหนึ่ง และมักจะรวมชื่อด้วย ( aws_…
) รายการทรัพยากรทั้งหมดที่พร้อมใช้งานสำหรับ AWS มีอยู่ในเอกสาร
มีการดำเนินการห้าประการที่แผนจะแสดงสำหรับทรัพยากรที่กำหนด:
-
[+]
เพิ่ม – ทรัพยากรใหม่จะถูกสร้างขึ้น -
[-]
ทำลาย – ทรัพยากรจะถูกทำลายอย่างสมบูรณ์ -
[~]
แก้ไขแทนที่ – ทรัพยากรจะถูกแก้ไขและพารามิเตอร์อย่างน้อยหนึ่งรายการจะเปลี่ยนไป โดยทั่วไปจะปลอดภัย Terraform จะแสดงให้คุณเห็นว่าพารามิเตอร์ใดบ้างที่จะได้รับการแก้ไขและวิธี (ถ้าเป็นไปได้) -
[- / +]
– ทรัพยากรจะถูกลบออก และสร้างใหม่ ด้วยพารามิเตอร์ใหม่ สิ่งนี้จะเกิดขึ้นหากมีการเปลี่ยนแปลงพารามิเตอร์ที่ไม่สามารถเปลี่ยนแปลงได้ Terraform จะแสดงให้คุณเห็นว่าการเปลี่ยนแปลงใดบังคับให้สร้างทรัพยากรใหม่ โดยมีความคิดเห็นต่อไปนี้เป็นสีแดง:(forces new resource)
นี่อาจเป็นอันตรายได้ เนื่องจากมีช่วงเวลาที่ทรัพยากรจะไม่มีอยู่เลย นอกจากนี้ยังสามารถทำลายการพึ่งพาอื่น ๆ ที่เชื่อมต่อกันได้ ฉันขอแนะนำให้แก้ไขการเปลี่ยนแปลงดังกล่าว เว้นแต่คุณจะรู้ว่าผลที่ตามมาจะเป็นอย่างไรหรือไม่สนใจเรื่องการหยุดทำงาน -
[<=]
– แหล่งข้อมูลจะถูกอ่าน นี่เป็นการดำเนินการแบบอ่านอย่างเดียว
ด้านบนคือแผนตัวอย่าง การเปลี่ยนแปลงที่ฉันทำคือ:
- เปลี่ยน
instance_type
ของอินสแตนซ์ Bastion แรก - เพิ่มตัวอย่างป้อมปราการที่สอง
- เปลี่ยนชื่อกลุ่มรักษาความปลอดภัย
โปรดทราบว่าการเปลี่ยนแปลงครั้งล่าสุดคือกฎของกลุ่มความปลอดภัยที่ตรวจพบการเปลี่ยนแปลงในชื่อกลุ่มหลักโดยอัตโนมัติ ในความคิดของฉัน แผนทั้งหมดนั้นอ่านง่าย ค่าพารามิเตอร์บางค่าแสดงเป็น <computed>
ไม่ได้หมายความว่าจะมีการเปลี่ยนแปลง แต่จะไม่สามารถเรียกค้นและนำเสนอในขั้นตอนนี้ได้ (เช่น ชื่อ SG ที่ยังไม่ได้สร้าง) โปรดจำไว้ว่า เฉพาะทรัพยากรที่เปลี่ยนแปลงเท่านั้นที่จะแสดงในระหว่างคำสั่ง plan
สิ่งใดที่ละเว้นจะไม่ถูกแตะต้อง
โดยปกติ คำสั่ง Terraform จะยอมรับพารามิเตอร์เพิ่มเติม พารามิเตอร์ที่สำคัญที่สุดสำหรับคำสั่งแผนคืออ็อพชัน -out
ซึ่งจะบันทึกแผนของคุณบนดิสก์ แผนการที่บันทึกไว้นี้สามารถดำเนินการได้ (เหมือนกับที่บันทึกไว้) โดยใช้คำสั่ง Apply สิ่งนี้สำคัญมาก เนื่องจากไม่เช่นนั้นอาจมีการเปลี่ยนแปลง เช่น เพื่อนร่วมงานระหว่างการออก plan
และการ apply
ตัวอย่าง:
- ออก
plan
และตรวจสอบว่าดูดีหรือไม่ - มีคนเปลี่ยนสถานะโดยที่คุณไม่รู้
-
apply
ปัญหาและ—อ๊ะ มันทำอย่างอื่นนอกเหนือจากที่วางแผนไว้!
โชคดีที่เวิร์กโฟลว์นี้ได้รับการปรับปรุงใน Terraform v0.11.0 ตั้งแต่เวอร์ชันนี้ คำสั่ง apply
จะนำเสนอแผนโดยอัตโนมัติที่คุณต้องอนุมัติ (โดยการพิมพ์ yes
อย่างชัดเจน) ข้อดีคือ หากคุณใช้แผนนี้ แผนจะดำเนินการตามที่แสดงไว้ทุกประการ
อีกตัวเลือกหนึ่งที่มีประโยชน์คือ -destroy
ซึ่งจะแสดงแผนที่จะส่งผลให้คุณทำลายทรัพยากรทั้งหมดที่ Terraform จัดการ คุณยังสามารถกำหนดเป้าหมายทรัพยากรเฉพาะสำหรับการทำลายด้วยตัวเลือก -target
Terraform สมัคร
เมื่อเราใช้แผนที่กำหนดไว้ Terraform จะออกไปและล็อกสถานะของเราเพื่อให้แน่ใจว่ามีความพิเศษ จากนั้นดำเนินการเปลี่ยนทรัพยากรและในที่สุดก็ผลักดันสถานะที่อัปเดต สิ่งหนึ่งที่ควรทราบคือทรัพยากรบางอย่างใช้เวลานานกว่าจะเสร็จสิ้นกว่าทรัพยากรอื่นๆ ตัวอย่างเช่น การสร้างอินสแตนซ์ AWS RDS อาจใช้เวลานานกว่า 12 นาที และ Terraform จะรอให้เสร็จสิ้น เห็นได้ชัดว่า Terraform ฉลาดพอที่จะไม่บล็อกการทำงานอื่น ๆ ด้วยวิธีนี้ มันสร้างกราฟชี้นำของการเปลี่ยนแปลงที่ร้องขอ และหากไม่มีการพึ่งพาซึ่งกันและกัน จะใช้การขนานกันเพื่อเร่งการดำเนินการ
การนำเข้าทรัพยากร
บ่อยครั้ง Terraform และโซลูชัน "การกำหนดค่าเป็นโค้ด" อื่นๆ ได้รับการแนะนำทีละน้อยในสภาพแวดล้อมที่มีอยู่แล้ว การเปลี่ยนแปลงนั้นง่ายมาก โดยพื้นฐานแล้ว สิ่งใดก็ตามที่ไม่ได้กำหนดไว้ใน Terraform จะไม่ได้รับการจัดการและไม่เปลี่ยนแปลง Terraform เกี่ยวข้องกับสิ่งที่จัดการเท่านั้น แน่นอน เป็นไปได้ว่าสิ่งนี้จะทำให้เกิดปัญหา ตัวอย่างเช่น ถ้า Terraform อาศัยปลายทางบางอย่างที่อยู่นอกการกำหนดค่าและถูกทำลายด้วยตนเอง Terraform ไม่ทราบเรื่องนี้ ดังนั้นจึงไม่สามารถสร้างทรัพยากรนี้ขึ้นใหม่ระหว่างการเปลี่ยนแปลงสถานะ ซึ่งจะส่งผลให้เกิดข้อผิดพลาดจาก API ระหว่างการดำเนินการตามแผน นี่ไม่ใช่สิ่งที่ฉันกังวล ประโยชน์ของการแนะนำ Terraform มีมากกว่าข้อเสีย
เพื่อให้ขั้นตอนการแนะนำง่ายขึ้นเล็กน้อย Terraform รวมคำสั่ง import
ใช้เพื่อแนะนำทรัพยากรภายนอกที่มีอยู่แล้วในสถานะ Terraform และอนุญาตให้จัดการทรัพยากรเหล่านั้น น่าเสียดายที่ Terraform ไม่สามารถสร้างการกำหนดค่าอัตโนมัติสำหรับโมดูลที่นำเข้าเหล่านั้น อย่างน้อยก็ในขณะที่เขียน มีแผนสำหรับฟังก์ชันนี้ แต่สำหรับตอนนี้ คุณต้องเขียนข้อกำหนดทรัพยากรใน Terraform ก่อน แล้วจึงนำเข้าทรัพยากรนี้เพื่อบอกให้ Terraform เริ่มจัดการ เมื่อนำเข้ามาสู่สถานะแล้ว (และระหว่างการวางแผนการดำเนินการ) คุณจะเห็นความแตกต่างทั้งหมดระหว่างสิ่งที่คุณเขียนในไฟล์ .tf
กับสิ่งที่มีอยู่จริงในคลาวด์ ด้วยวิธีนี้ คุณสามารถปรับแต่งการกำหนดค่าเพิ่มเติมได้ ตามหลักการแล้ว ไม่ควรมีการเปลี่ยนแปลงใดๆ ซึ่งหมายความว่าการกำหนดค่า Terraform สะท้อนถึงสิ่งที่มีอยู่แล้วบนคลาวด์ 1:1
โมดูล
โมดูลเป็นส่วนสำคัญของการกำหนดค่า Terraform และฉันขอแนะนำให้คุณยอมรับและใช้งานบ่อยๆ พวกเขาให้วิธีการนำส่วนประกอบบางอย่างกลับมาใช้ใหม่แก่คุณ ตัวอย่างจะเป็นคลัสเตอร์ AWS ECS ซึ่งใช้เพื่อเรียกใช้คอนเทนเนอร์ Docker เพื่อให้คลัสเตอร์ทำงาน คุณต้องกำหนดค่าทรัพยากรแยกต่างหากจำนวนมาก: ตัวคลัสเตอร์เอง การกำหนดค่าการเปิดใช้ที่จะจัดการอินสแตนซ์ EC2 แยกกัน ที่เก็บคอนเทนเนอร์สำหรับอิมเมจ กลุ่มและนโยบายการปรับขนาดอัตโนมัติ และอื่นๆ โดยปกติ คุณจะต้องมีคลัสเตอร์แยกต่างหากสำหรับสภาพแวดล้อมและ/หรือแอปพลิเคชันที่แยกจากกัน
วิธีหนึ่งที่จะเอาชนะสิ่งนี้ได้คือการคัดลอกและวางการกำหนดค่า แต่นี่เป็นวิธีแก้ปัญหาระยะสั้นอย่างเห็นได้ชัด คุณจะทำผิดพลาดในการอัปเดตที่ง่ายที่สุด
โมดูลช่วยให้คุณสามารถสรุปทรัพยากรที่แยกจากกันทั้งหมดภายใต้บล็อกการกำหนดค่าเดียว (เรียกว่าโมดูล) โมดูลกำหนด อินพุต และ เอาต์พุต ซึ่งเป็นอินเทอร์เฟซที่สื่อสารกับ "โลกภายนอก" (หรือรหัสการโทร) ยิ่งไปกว่านั้น โมดูลสามารถซ้อนอยู่ในโมดูลอื่น ๆ ได้ ช่วยให้คุณหมุนสภาพแวดล้อมที่แยกจากกันได้อย่างรวดเร็ว
โมดูลท้องถิ่นและระยะไกล
คุณสามารถมีโมดูลภายในเครื่องหรือโมดูลระยะไกลได้เช่นเดียวกัน โมดูลในเครื่องจะถูกเก็บไว้ข้างๆ การกำหนดค่า Terraform ของคุณ (ในไดเร็กทอรีแยกต่างหาก ภายนอกแต่ละสภาพแวดล้อม แต่ในที่เก็บเดียวกัน) นี่เป็นเรื่องปกติถ้าคุณมีสถาปัตยกรรมที่เรียบง่ายและไม่ได้แชร์โมดูลเหล่านั้น
อย่างไรก็ตาม สิ่งนี้มีข้อจำกัด เป็นการยากที่จะกำหนดเวอร์ชันและแชร์โมดูลเหล่านั้น การกำหนดเวอร์ชันมีความสำคัญเนื่องจากคุณอาจต้องการใช้ v1.0.0 ของโมดูล ECS ในการใช้งานจริง แต่ต้องการทดลองกับ v1.1.0 ในสภาพแวดล้อมการจัดเตรียม หากโมดูลถูกจัดเก็บไว้ข้างๆ โค้ดของคุณ ทุกการเปลี่ยนแปลงในโค้ดโมดูลจะมีผลในทุก env (เมื่อเรียก apply
แล้ว) ซึ่งมักจะไม่พึงปรารถนา
แนวทางหนึ่งที่สะดวกสำหรับโมดูลการกำหนดเวอร์ชันคือการวางทั้งหมดไว้ในที่เก็บแยกต่างหาก เช่น your-company/terraform-modules จากนั้น เมื่ออ้างอิงโมดูลเหล่านั้นภายในการกำหนดค่า Terraform คุณสามารถใช้ลิงก์ VCS เป็นแหล่งที่มาได้:
module "my-module" { source = "[email protected]:your-company/terraform-modules.git//modules/my-module?ref=v1.1.0" ... }
ที่นี่ฉันกำลังอ้างอิง v1.1.0 ของ my-module (เส้นทางเฉพาะ) ซึ่งฉันสามารถทดสอบแยกจากรุ่นอื่นของโมดูลเดียวกันในสภาพแวดล้อมที่แตกต่างกัน
นอกจากนั้น ยังมีปัญหาของการค้นพบได้และความสามารถในการแชร์ของโมดูล คุณควรพยายามเขียนโมดูลที่มีเอกสารครบถ้วนและนำมาใช้ใหม่ได้ โดยปกติ คุณจะมีการกำหนดค่า Terraform ที่แตกต่างกันสำหรับแอปต่างๆ และอาจต้องการแชร์โมดูลเดียวกันระหว่างแอปเหล่านั้น หากไม่มีการแยกไปยัง repo ที่แยกจากกัน สิ่งนี้จะยากมาก
การใช้โมดูล
สามารถอ้างอิงโมดูลได้อย่างง่ายดายในสภาพแวดล้อม Terraform โดยการกำหนดบล็อกโมดูลพิเศษ นี่คือตัวอย่างของบล็อกดังกล่าวสำหรับโมดูล ECS ที่สมมติขึ้น:
module "my_service_ecs_cluster" { source = "../modules/ecs_cluster" cluster_name = "my-ecs-service-${var.env}" repository_names = [ "my-ecs-service-${var.env}/api", "my-ecs-service-${var.env}/nginx", "my-ecs-service-${var.env}/docs", ] service_name = "my-ecs-service-${var.env}" ecs_instance_type = "t2.nano" min_size = "1" max_size = "1" use_autoscaling = false alb_target_group_arn = "${module.my_alb.target_group_arn}" subnets = "${local.my_private_subnets}" security_groups = "${aws_security_group.my_ecs.id}" key_name = "${var.key_name}" env_tag = "${var.env}" project_tag = "${var.project_tag}" application_tag = "${var.api_app_tag}" asg_tag = "${var.api_app_tag}-asg" }
ตัวเลือกทั้งหมดที่ถูกส่งผ่าน (ยกเว้นจากส่วนกลางบางอย่างเช่น source
) ถูกกำหนดไว้ภายในการกำหนดค่าของโมดูลนี้เป็นอินพุต (ตัวแปร)
โมดูล Registry
ล่าสุด HashiCorp ได้เปิดตัวรีจีสทรีโมดูล Terraform อย่างเป็นทางการ นี่เป็นข่าวดีเนื่องจากคุณสามารถดึงความรู้จากชุมชนที่ได้พัฒนาโมดูลทดสอบการรบแล้ว นอกจากนี้ บางส่วนยังมีป้าย "HashiCorp Verified Module" ซึ่งหมายความว่าได้รับการตรวจสอบและบำรุงรักษาอย่างแข็งขัน และให้ความมั่นใจเป็นพิเศษแก่คุณ
ก่อนหน้านี้ คุณต้องเขียนโมดูลของคุณเองตั้งแต่เริ่มต้น (และเรียนรู้จากความผิดพลาดของคุณ) หรือใช้โมดูลที่เผยแพร่บน GitHub และที่อื่นๆ โดยไม่มีการรับประกันใดๆ เกี่ยวกับพฤติกรรมของพวกเขา (นอกเหนือจากการอ่านโค้ด!)
การแบ่งปันข้อมูลระหว่างสภาพแวดล้อม
ตามหลักการแล้ว สภาพแวดล้อมควรแยกจากกันโดยสิ้นเชิง แม้จะใช้บัญชี AWS ต่างกันก็ตาม ในความเป็นจริง มีหลายกรณีที่สภาพแวดล้อม Terraform อาจใช้ข้อมูลบางอย่างในสภาพแวดล้อมอื่น This is especially true if you are gradually converting your architecture to use Terraform. One example might be that you have a global
env that provides certain resources to other envs.
Let's say env global
shares data with stage
. For this to work, you can define outputs at the main level of the environment like so:
output "vpc_id" { value = "${module.network.vpc_id}" }
Then, in the stage
environment, you define a datasource that points to the remote state of global
:
data "terraform_remote_state" "global" { backend = "s3" config { bucket = "my-app-terraform-state" key = "terraform/global" region = "${var.region}" dynamodb_table = "terraform-state-lock-table" profile = "${var.profile}" } }
Now, you can use this datasource as any other and access all the values that were defined in global
's outputs:
vpc_
Words of Caution
Terraform has a lot of pros. I use it daily in production environments and consider it stable enough for such work. Having said that, Terraform is still under active development. Thus, you will stumble on bugs and quirks.
Where to Report Issues and Monitor Changes
First of all, remember: Terraform has a separate core repo and repositories for each provider (eg, AWS). If you encounter issues, make sure to check both the core repo and the separate provider repositories for issues and/or opened pull requests with fixes. GitHub is really the best place to search for bugs and fixes as it is very active and welcoming.
This also means that provider plugins are versioned separately, so make sure you follow their changelogs as well as the core one. Most of the bugs I have encountered were resolved by upgrading the AWS provider which already had a fix.
Can't Cheat Your Way out of Cloud Knowledge
You cannot use Terraform to configure and manage infrastructure if you have no knowledge of how a given provider works. I would say this is a misconception and not a downside, since Terraform has been designed to augment and improve the workflow of configuration management and not to be some magic dust that you randomly sprinkle around and—poof! Environments grow! You still need a solid knowledge of a security model of each cloud, how to write, eg, AWS policies, what resources are available, and how they interact.
Prefer Separate Resources That Are Explicitly linked
There are certain resources—for example, the AWS security group or AWS route table—that allow you to configure the security rules and routes respectively, directly inside their own block. This is tempting, as it looks like less work but in fact will cause you trouble. The problems start when you are changing those rules on subsequent passes. The whole resource will be marked as being changed even if only one route/security rule is being introduced. It also gives implicit ordering to those rules and makes it harder to follow the changes. Thankfully, mixing those both approaches is not allowed now (see the note).
Best-practice example, with explicitly linked resources:
resource "aws_security_group" "my_sg" { name = "${var.app_tag}-my-sg" ... } resource "aws_security_group_rule" "rule_one" { security_group_ ... } resource "aws_security_group_rule" "rule_two" { security_group_ ... }
Terraform plan
Doesn't Always Detect Issues and Conflicts
I already mentioned this in the case where you were managing resources with Terraform that were relying on other, unmanaged infrastructure. But there are more trivial examples—for example, you will get an error if your EC2 instance has Termination Protection enabled, even though plan
would show you it's OK to destroy it. You can argue that this is what Termination Protection has been designed for, and I agree, but there are more examples of things you can do in theory/on plan but when executed will deadlock or error out. For example, you cannot remove a network interface if something is using it—you get a deadlock without an option to gracefully recover.
Syntax Quirks
There are also quirks related to how HCLv1 (the syntax language Terraform uses) has been designed. It has a couple of frustrating quirks. There is work underway to provide an improved version of the parser for HCLv2. The best way to read on the current limitations and the plan to overcome them is this fantastic blog series. In the meantime, there are workarounds for most of those issues. They are not pretty and they will fail once v0.12 comes out, but hey, it is what it is.
When State Update Fails
It sometimes happens that Terraform is not able to correctly push an updated state. This is usually due to underlying network issues. The solution is to retry the state update instead of running apply again, which will fork the state .
Another issue might happen when state lock (the synchronization primitive that prevents multiple users to update the same state) fails to be taken down by Terraform. This involves running terraform force-unlock
with the lock ID to take it down manually.
Thankfully, in case of such problems, Terraform provides you with a good description and steps you need to make to fix it.
Not Everything Is Fun to Manage Through Terraform
There are certain cases where Terraform is not my tool of choice. For example, configuring AWS CodePipeline and CodeBuild projects (AWS equivalent of CI/CD pipeline) is cumbersome when done through Terraform. You need to define each step through very verbose configuration blocks and things like “Login via GitHub” are a lot more complicated than using the UI. Of course, it's still possible if you prefer to have it codified. Well, I guess it's a good candidate for a well-written module!
Same thing goes for managing AWS API Gateway endpoints. In this case, using a dedicated serverless framework would be a better option.
When configuring AWS resources with Terraform, you will find yourself writing a lot of policies. Policies that would otherwise often be auto-generated for you (when using the UI). For those, I'd recommend the AWS Visual Editor and then copying the resulting policy JSON into Terraform.
บทสรุป
Using Terraform has been fun and I'll continue doing so. Initial steps can be a bumpy ride, but there are more and more resources that help to ease you in.
I'd definitely recommend taking Terraform for a spin and simply playing with it. Remember, though—be safe and test it out on a non-essential account. If you are eligible for AWS Free Tier, use it as a 12-month free trial. Just be aware it has limitations as to what you can provision. Otherwise, just make sure you spin the cheapest resources, like t3.nano instances.
I highly recommend extensions for Terraform support in various code editors. For Visual Studio Code, there is one with syntax highlighting, formatting, validation and linting support.
It's always valuable to learn new things and evaluate new tools. I found that Terraform helped me immensely in managing my infrastructure. I think working with Terraform will only get easier and more fun, especially once v0.12.0 ships with a major upgrade to the HCL syntax and solve most of the quirks. The traction and community around Terraform are active and vibrant. You can find a lot of great resources on things I didn't manage to cover in a single blogs post, eg, a detailed guide on how to write modules.