ข้อผิดพลาดของ Terraform

ข้อผิดพลาดของ Terraform
เรามาเน้นย้ำถึงข้อผิดพลาดบางประการ รวมถึงที่เกี่ยวข้องกับลูป คำสั่ง if และเทคนิคการใช้งาน ตลอดจนปัญหาทั่วไปอื่นๆ ที่ส่งผลต่อ Terraform โดยทั่วไป:

  • พารามิเตอร์ count และ for_each มีข้อจำกัด
  • จำกัดการปรับใช้การหยุดทำงานเป็นศูนย์
  • แม้แต่แผนการที่ดีก็ล้มเหลวได้
  • การปรับโครงสร้างใหม่อาจมีข้อผิดพลาด
  • การเชื่อมโยงกันที่เลื่อนออกไปนั้นสอดคล้องกับ... กับการเลื่อนออกไป

พารามิเตอร์ count และ for_each มีข้อจำกัด

ตัวอย่างในบทนี้ใช้ประโยชน์จากพารามิเตอร์ count และนิพจน์ for_each ในลูปและตรรกะแบบมีเงื่อนไขอย่างกว้างขวาง ทำงานได้ดี แต่มีข้อจำกัดสำคัญสองประการที่คุณต้องระวัง

  • Count และ for_each ไม่สามารถอ้างอิงตัวแปรเอาต์พุตของทรัพยากรใดๆ ได้
  • count และ for_each ไม่สามารถใช้ในการกำหนดค่าโมดูลได้

count และ for_each ไม่สามารถอ้างอิงตัวแปรเอาต์พุตของทรัพยากรใดๆ ได้

ลองนึกภาพคุณจำเป็นต้องปรับใช้เซิร์ฟเวอร์ EC2 หลายเครื่อง และด้วยเหตุผลบางอย่างที่คุณไม่ต้องการใช้ ASG รหัสของคุณอาจเป็นเช่นนี้:

resource "aws_instance" "example_1" {
   count             = 3
   ami                = "ami-0c55b159cbfafe1f0"
   instance_type = "t2.micro"
}

ลองดูพวกเขาทีละคน

เนื่องจากพารามิเตอร์ count ถูกตั้งค่าเป็นค่าคงที่ โค้ดนี้จึงทำงานได้โดยไม่มีปัญหา: เมื่อคุณรันคำสั่ง Apply จะสร้างเซิร์ฟเวอร์ EC2 สามเซิร์ฟเวอร์ แต่ถ้าคุณต้องการปรับใช้เซิร์ฟเวอร์หนึ่งเซิร์ฟเวอร์ในแต่ละ Availability Zone (AZ) ภายในภูมิภาค AWS ปัจจุบันของคุณล่ะ คุณสามารถให้โค้ดของคุณโหลดรายการโซนจากแหล่งข้อมูล aws_availability_zones จากนั้นวนซ้ำแต่ละโซนและสร้างเซิร์ฟเวอร์ EC2 ในนั้นโดยใช้พารามิเตอร์การนับและการเข้าถึงดัชนีอาร์เรย์:

resource "aws_instance" "example_2" {
   count                   = length(data.aws_availability_zones.all.names)
   availability_zone   = data.aws_availability_zones.all.names[count.index]
   ami                     = "ami-0c55b159cbfafe1f0"
   instance_type       = "t2.micro"
}

data "aws_availability_zones" "all" {}

โค้ดนี้จะทำงานได้ดีเช่นกัน เนื่องจากพารามิเตอร์ count สามารถอ้างอิงแหล่งข้อมูลได้โดยไม่มีปัญหาใดๆ แต่จะเกิดอะไรขึ้นหากจำนวนเซิร์ฟเวอร์ที่คุณต้องสร้างขึ้นอยู่กับผลลัพธ์ของทรัพยากรบางอย่าง เพื่อสาธิตสิ่งนี้ วิธีที่ง่ายที่สุดคือการใช้ทรัพยากร Random_integer ซึ่งส่งคืนจำนวนเต็มแบบสุ่มตามชื่อที่แนะนำ:

resource "random_integer" "num_instances" {
  min = 1
  max = 3
}

โค้ดนี้สร้างตัวเลขสุ่มระหว่าง 1 ถึง 3 มาดูกันว่าเกิดอะไรขึ้นถ้าเราพยายามใช้เอาต์พุตของทรัพยากรนี้ในพารามิเตอร์ count ของทรัพยากร aws_instance:

resource "aws_instance" "example_3" {
   count             = random_integer.num_instances.result
   ami                = "ami-0c55b159cbfafe1f0"
   instance_type = "t2.micro"
}

หากคุณรันแผน Terraform บนโค้ดนี้ คุณจะได้รับข้อผิดพลาดต่อไปนี้:

Error: Invalid count argument

   on main.tf line 30, in resource "aws_instance" "example_3":
   30: count = random_integer.num_instances.result

The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the -target argument to first apply only the resources that the count depends on.

Terraform ต้องการให้คำนวณจำนวนและ for_each ในระหว่างขั้นตอนการวางแผน ก่อนที่จะสร้างหรือแก้ไขทรัพยากรใดๆ ซึ่งหมายความว่า count และ for_each สามารถอ้างอิงถึงตัวอักษร ตัวแปร แหล่งข้อมูล และแม้กระทั่งรายการทรัพยากร (ตราบใดที่ความยาวสามารถกำหนดได้ ณ เวลาที่กำหนด) แต่ไม่สามารถคำนวณถึงตัวแปรเอาต์พุตของทรัพยากรที่คำนวณได้

count และ for_each ไม่สามารถใช้ในการกำหนดค่าโมดูลได้

สักวันหนึ่งคุณอาจถูกล่อลวงให้เพิ่มพารามิเตอร์การนับให้กับการกำหนดค่าโมดูลของคุณ:

module "count_example" {
     source = "../../../../modules/services/webserver-cluster"

     count = 3

     cluster_name = "terraform-up-and-running-example"
     server_port = 8080
     instance_type = "t2.micro"
}

รหัสนี้พยายามใช้การนับภายในโมดูลเพื่อสร้างสำเนาสามชุดของทรัพยากรเว็บเซิร์ฟเวอร์คลัสเตอร์ หรือคุณอาจต้องการทำให้การเชื่อมต่อโมดูลเป็นทางเลือกตามเงื่อนไขบูลีนบางอย่างโดยการตั้งค่าพารามิเตอร์การนับเป็น 0 ซึ่งอาจดูเหมือนโค้ดที่สมเหตุสมผล แต่คุณจะได้รับข้อผิดพลาดนี้เมื่อรันแผน Terraform:

Error: Reserved argument name in module block

   on main.tf line 13, in module "count_example":
   13: count = 3

The name "count" is reserved for use in a future version of Terraform.

น่าเสียดายที่ Terraform 0.12.6 ไม่รองรับการใช้ count หรือ for_each ในทรัพยากรโมดูล ตามบันทึกประจำรุ่น Terraform 0.12 (http://bit.ly/3257bv4) HashiCorp วางแผนที่จะเพิ่มความสามารถนี้ในอนาคต ดังนั้นความสามารถนี้อาจพร้อมใช้งานอยู่แล้วทั้งนี้ขึ้นอยู่กับว่าคุณอ่านหนังสือเล่มนี้เมื่อใด หากต้องการทราบอย่างแน่นอน อ่านบันทึกการเปลี่ยนแปลงของ Terraform ที่นี่.

ข้อจำกัดของการปรับใช้ Zero Downtime

การใช้บล็อก create_before_destroy ร่วมกับ ASG เป็นโซลูชันที่ยอดเยี่ยมสำหรับการสร้างการใช้งานแบบไม่ต้องหยุดทำงาน ยกเว้นข้อแม้ประการหนึ่ง: ไม่รองรับกฎการปรับขนาดอัตโนมัติ หรือเพื่อให้แม่นยำยิ่งขึ้น วิธีนี้จะรีเซ็ตขนาด ASG กลับเป็น min_size ในทุกการใช้งาน ซึ่งอาจเป็นปัญหาได้หากคุณใช้กฎการปรับขนาดอัตโนมัติเพื่อเพิ่มจำนวนเซิร์ฟเวอร์ที่ทำงานอยู่

ตัวอย่างเช่น โมดูลเว็บเซิร์ฟเวอร์-คลัสเตอร์ประกอบด้วยทรัพยากร aws_autoscaling_schedule หนึ่งคู่ ซึ่งเวลา 9 น. จะเพิ่มจำนวนเซิร์ฟเวอร์ในคลัสเตอร์จากสองเป็นสิบ หากคุณใช้งานเวลา 11 น. ASG ใหม่จะบูตด้วยเซิร์ฟเวอร์เพียง 9 เครื่องแทนที่จะเป็น XNUMX เครื่องและคงอยู่เช่นนั้นจนถึง XNUMX น. ของวันถัดไป

ข้อจำกัดนี้สามารถหลีกเลี่ยงได้หลายวิธี

  • เปลี่ยนพารามิเตอร์การเกิดซ้ำใน aws_autoscaling_schedule จาก 0 9 * * * (“วิ่งเวลา 9 น.”) เป็น 0-59 9-17 * * * (“วิ่งทุกนาทีตั้งแต่ 9 น. ถึง 5 น.”) หาก ASG มีเซิร์ฟเวอร์อยู่แล้ว XNUMX เครื่อง การเรียกใช้กฎการปรับขนาดอัตโนมัตินี้อีกครั้งจะไม่เปลี่ยนแปลงสิ่งใด ซึ่งเป็นสิ่งที่เราต้องการ แต่หาก ASG เพิ่งถูกใช้งาน กฎนี้จะรับประกันว่าภายในเวลาสูงสุดหนึ่งนาที จำนวนเซิร์ฟเวอร์จะถึงสิบ นี่ไม่ใช่แนวทางที่หรูหราโดยสิ้นเชิง และการข้ามเซิร์ฟเวอร์และแบ็คเซิร์ฟเวอร์จำนวนมากจากสิบเป็นสองเซิร์ฟเวอร์ก็อาจทำให้เกิดปัญหากับผู้ใช้ได้เช่นกัน
  • สร้างสคริปต์แบบกำหนดเองที่ใช้ AWS API เพื่อกำหนดจำนวนเซิร์ฟเวอร์ที่ใช้งานอยู่ใน ASG เรียกสคริปต์โดยใช้แหล่งข้อมูลภายนอก (ดู "แหล่งข้อมูลภายนอก" ในหน้า 249) และตั้งค่าพารามิเตอร์ที่ต้องการของ ASG ให้เป็นค่าที่ส่งคืนโดย บท. ด้วยวิธีนี้ แต่ละอินสแตนซ์ ASG ใหม่จะทำงานที่ความจุเท่ากันกับโค้ด Terraform ที่มีอยู่เสมอ และทำให้บำรุงรักษายากขึ้น

แน่นอนว่า Terraform น่าจะมีการสนับสนุนในตัวสำหรับการปรับใช้แบบไม่ต้องหยุดทำงาน แต่ ณ เดือนพฤษภาคม 2019 ทีม HashiCorp ไม่มีแผนที่จะเพิ่มฟังก์ชันการทำงานนี้ (รายละเอียด - ที่นี่).

แผนที่ถูกต้องอาจปฏิบัติไม่สำเร็จ

บางครั้งคำสั่ง plan จะสร้างแผนการปรับใช้ที่ถูกต้องสมบูรณ์ แต่คำสั่ง Apply ส่งกลับข้อผิดพลาด ตัวอย่างเช่น ลองเพิ่มทรัพยากร aws_iam_user ด้วยชื่อเดียวกันกับที่คุณใช้สำหรับผู้ใช้ IAM ที่คุณสร้างไว้ก่อนหน้าในบทที่ 2:

resource "aws_iam_user" "existing_user" {
   # Подставьте сюда имя уже существующего пользователя IAM,
   # чтобы попрактиковаться в использовании команды terraform import
   name = "yevgeniy.brikman"
}

ตอนนี้ หากคุณรันคำสั่ง plan Terraform จะส่งออกแผนการปรับใช้ที่ดูเหมือนสมเหตุสมผล:

Terraform will perform the following actions:

   # aws_iam_user.existing_user will be created
   + resource "aws_iam_user" "existing_user" {
         + arn                  = (known after apply)
         + force_destroy   = false
         + id                    = (known after apply)
         + name               = "yevgeniy.brikman"
         + path                 = "/"
         + unique_id         = (known after apply)
      }

Plan: 1 to add, 0 to change, 0 to destroy.

หากคุณรันคำสั่ง Apply คุณจะได้รับข้อผิดพลาดต่อไปนี้:

Error: Error creating IAM User yevgeniy.brikman: EntityAlreadyExists:
User with name yevgeniy.brikman already exists.

   on main.tf line 10, in resource "aws_iam_user" "existing_user":
   10: resource "aws_iam_user" "existing_user" {

แน่นอนว่าปัญหาคือมีผู้ใช้ IAM ที่มีชื่อนั้นอยู่แล้ว และสิ่งนี้สามารถเกิดขึ้นได้ไม่เพียงแต่กับผู้ใช้ IAM เท่านั้น แต่ยังเกิดขึ้นกับทรัพยากรเกือบทุกประเภทด้วย อาจเป็นไปได้ว่ามีคนสร้างทรัพยากรนี้ด้วยตนเองหรือใช้บรรทัดคำสั่ง แต่อย่างใด การจับคู่ ID จะทำให้เกิดข้อขัดแย้ง ข้อผิดพลาดนี้มีหลายรูปแบบที่มักดึงดูดผู้มาใหม่ถึง Terraform ด้วยความประหลาดใจ

จุดสำคัญคือคำสั่งแผน Terraform จะพิจารณาเฉพาะทรัพยากรที่ระบุในไฟล์สถานะ Terraform เท่านั้น หากทรัพยากรถูกสร้างขึ้นด้วยวิธีอื่น (เช่น ด้วยตนเองโดยการคลิกในคอนโซล AWS) ทรัพยากรเหล่านั้นจะไม่ไปอยู่ในไฟล์สถานะ ดังนั้น Terraform จะไม่คำนึงถึงทรัพยากรเหล่านั้นเมื่อดำเนินการคำสั่งแผน เป็นผลให้แผนที่ดูเหมือนถูกต้องตั้งแต่แรกจะล้มเหลว

มีสองบทเรียนที่ต้องเรียนรู้จากเรื่องนี้

  • หากคุณได้เริ่มทำงานกับ Terraform แล้ว อย่าใช้สิ่งอื่นใด หากส่วนหนึ่งของโครงสร้างพื้นฐานของคุณได้รับการจัดการโดยใช้ Terraform คุณจะไม่สามารถแก้ไขได้ด้วยตนเองอีกต่อไป มิฉะนั้น คุณไม่เพียงเสี่ยงต่อข้อผิดพลาด Terraform แปลกๆ เท่านั้น แต่คุณยังลบล้างข้อดีหลายประการของ IaC ด้วย เนื่องจากโค้ดจะไม่เป็นตัวแทนโครงสร้างพื้นฐานของคุณที่แม่นยำอีกต่อไป
  • หากคุณมีโครงสร้างพื้นฐานอยู่แล้ว ให้ใช้คำสั่งนำเข้า หากคุณเริ่มใช้ Terraform กับโครงสร้างพื้นฐานที่มีอยู่ คุณสามารถเพิ่มลงในไฟล์สถานะได้โดยใช้คำสั่งนำเข้า Terraform ด้วยวิธีนี้ Terraform จะรู้ว่าโครงสร้างพื้นฐานใดบ้างที่ต้องได้รับการจัดการ คำสั่งนำเข้ารับสองอาร์กิวเมนต์ อันดับแรกคือที่อยู่ทรัพยากรในไฟล์การกำหนดค่าของคุณ ไวยากรณ์ที่นี่เหมือนกับลิงก์ทรัพยากร: _ (เช่น aws_iam_user.existing_user) อาร์กิวเมนต์ที่สองคือ ID ของทรัพยากรที่จะนำเข้า สมมติว่า ID ทรัพยากร aws_iam_user คือชื่อผู้ใช้ (เช่น yevgeniy.brikman) และ ID ทรัพยากร aws_instance คือ ID เซิร์ฟเวอร์ EC2 (เช่น i-190e22e5) โดยทั่วไปวิธีการนำเข้าทรัพยากรจะระบุไว้ในเอกสารประกอบที่ด้านล่างของหน้า

    ด้านล่างนี้คือคำสั่งนำเข้าที่จะซิงโครไนซ์ทรัพยากร aws_iam_user ที่คุณเพิ่มลงในการกำหนดค่า Terraform ของคุณพร้อมกับผู้ใช้ IAM ในบทที่ 2 (แน่นอนว่าต้องแทนที่ชื่อของคุณเป็น yevgeniy.brikman):

    $ terraform import aws_iam_user.existing_user yevgeniy.brikman

    Terraform จะเรียกใช้ AWS API เพื่อค้นหาผู้ใช้ IAM ของคุณ และสร้างการเชื่อมโยงไฟล์สถานะระหว่างผู้ใช้กับทรัพยากร aws_iam_user.existing_user ในการกำหนดค่า Terraform ของคุณ จากนี้ไป เมื่อคุณรันคำสั่ง plan Terraform จะรู้ว่ามีผู้ใช้ IAM อยู่แล้ว และจะไม่พยายามสร้างมันขึ้นมาอีก

    เป็นที่น่าสังเกตว่าหากคุณมีทรัพยากรจำนวนมากที่ต้องการนำเข้าสู่ Terraform อยู่แล้ว การเขียนโค้ดด้วยตนเองและการนำเข้าทีละรายการอาจเป็นเรื่องยุ่งยากได้ ดังนั้นจึงคุ้มค่าที่จะลองใช้เครื่องมืออย่าง Terraforming (http://terraforming.dtan4.net/) ซึ่งสามารถนำเข้าโค้ดและสถานะจากบัญชี AWS ของคุณโดยอัตโนมัติ

    การปรับโครงสร้างใหม่อาจมีข้อผิดพลาด

    การปรับโครงสร้างใหม่ เป็นวิธีปฏิบัติทั่วไปในการเขียนโปรแกรมโดยที่คุณเปลี่ยนโครงสร้างภายในของโค้ดโดยปล่อยให้พฤติกรรมภายนอกไม่เปลี่ยนแปลง นี่คือการทำให้โค้ดชัดเจนขึ้น เรียบร้อยขึ้น และดูแลรักษาง่ายขึ้น การรีแฟคเตอร์เป็นเทคนิคที่ขาดไม่ได้ที่ควรใช้เป็นประจำ แต่เมื่อพูดถึง Terraform หรือเครื่องมือ IaC อื่น ๆ คุณต้องระมัดระวังอย่างยิ่งเกี่ยวกับสิ่งที่คุณหมายถึงโดย "พฤติกรรมภายนอก" ของโค้ด ไม่เช่นนั้นปัญหาที่ไม่คาดคิดจะเกิดขึ้น

    ตัวอย่างเช่น การปรับโครงสร้างรูปแบบทั่วไปคือการแทนที่ชื่อของตัวแปรหรือฟังก์ชันด้วยชื่อที่เข้าใจง่ายกว่า IDE จำนวนมากมีการสนับสนุนในตัวสำหรับการปรับโครงสร้างใหม่ และสามารถเปลี่ยนชื่อตัวแปรและฟังก์ชันทั่วทั้งโปรเจ็กต์ได้โดยอัตโนมัติ ในภาษาโปรแกรมทั่วไป นี่เป็นขั้นตอนเล็กๆ น้อยๆ ที่คุณอาจนึกไม่ถึง แต่ใน Terraform คุณต้องใช้ความระมัดระวังเป็นอย่างยิ่ง ไม่เช่นนั้นคุณอาจประสบปัญหาระบบขัดข้องได้

    ตัวอย่างเช่น โมดูลเว็บเซิร์ฟเวอร์คลัสเตอร์มีตัวแปรอินพุตคลัสเตอร์_ชื่อ:

    variable "cluster_name" {
       description = "The name to use for all the cluster resources"
       type          = string
    }

    ลองนึกภาพว่าคุณเริ่มใช้โมดูลนี้เพื่อปรับใช้ไมโครเซอร์วิสที่เรียกว่า foo ต่อมาคุณต้องการเปลี่ยนชื่อบริการของคุณเป็นแถบ การเปลี่ยนแปลงนี้อาจดูเล็กน้อย แต่ในความเป็นจริงแล้ว การเปลี่ยนแปลงดังกล่าวอาจทำให้บริการหยุดชะงักได้

    ความจริงก็คือโมดูลเว็บเซิร์ฟเวอร์คลัสเตอร์ใช้ตัวแปรคลัสเตอร์_name ในทรัพยากรจำนวนหนึ่ง รวมถึงพารามิเตอร์ชื่อของกลุ่มความปลอดภัยสองกลุ่มและ ALB:

    resource "aws_lb" "example" {
       name                    = var.cluster_name
       load_balancer_type = "application"
       subnets = data.aws_subnet_ids.default.ids
       security_groups      = [aws_security_group.alb.id]
    }

    หากคุณเปลี่ยนพารามิเตอร์ชื่อบนทรัพยากร Terraform จะลบเวอร์ชันเก่าของทรัพยากรนั้นและสร้างเวอร์ชันใหม่แทนที่ แต่หากทรัพยากรนั้นเป็น ALB ระหว่างการลบและดาวน์โหลดเวอร์ชันใหม่ คุณจะไม่มีกลไกในการเปลี่ยนเส้นทางการรับส่งข้อมูลไปยังเว็บเซิร์ฟเวอร์ของคุณ ในทำนองเดียวกัน หากกลุ่มความปลอดภัยถูกลบ เซิร์ฟเวอร์ของคุณจะเริ่มปฏิเสธการรับส่งข้อมูลเครือข่ายจนกว่าจะมีการสร้างกลุ่มใหม่

    การปรับโครงสร้างใหม่อีกประเภทหนึ่งที่คุณอาจสนใจคือการเปลี่ยน Terraform ID ลองใช้ทรัพยากร aws_security_group ในโมดูลเว็บเซิร์ฟเวอร์คลัสเตอร์เป็นตัวอย่าง:

    resource "aws_security_group" "instance" {
      # (...)
    }

    ตัวระบุของทรัพยากรนี้เรียกว่าอินสแตนซ์ ลองนึกภาพว่าในระหว่างการปรับโครงสร้างใหม่คุณตัดสินใจเปลี่ยนเป็นชื่อที่เข้าใจได้ง่ายขึ้น (ในความคิดของคุณ)คลัสเตอร์_instance:

    resource "aws_security_group" "cluster_instance" {
       # (...)
    }

    จะเกิดอะไรขึ้นในที่สุด? ถูกต้อง: การหยุดชะงัก

    Terraform เชื่อมโยงรหัสทรัพยากรแต่ละรายการกับรหัสผู้ให้บริการคลาวด์ ตัวอย่างเช่น iam_user เชื่อมโยงกับ ID ผู้ใช้ AWS IAM และ aws_instance เชื่อมโยงกับ ID เซิร์ฟเวอร์ AWS EC2 หากคุณเปลี่ยนรหัสทรัพยากร (เช่น จาก instance เป็นคลัสเตอร์_instance เช่นเดียวกับกรณีของ aws_security_group) เป็น Terraform จะปรากฏเหมือนกับว่าคุณลบทรัพยากรเก่าและเพิ่มทรัพยากรใหม่ หากคุณใช้การเปลี่ยนแปลงเหล่านี้ Terraform จะลบกลุ่มความปลอดภัยเก่าและสร้างกลุ่มใหม่ ในขณะที่เซิร์ฟเวอร์ของคุณเริ่มปฏิเสธการรับส่งข้อมูลเครือข่ายใดๆ

    ต่อไปนี้เป็นบทเรียนสำคัญสี่บทที่คุณควรทำจากการสนทนานี้

    • ใช้คำสั่งแผนเสมอ มันสามารถเปิดเผยอุปสรรค์ทั้งหมดนี้ได้ ตรวจสอบผลลัพธ์อย่างระมัดระวังและใส่ใจกับสถานการณ์ที่ Terraform วางแผนที่จะลบทรัพยากรที่มีแนวโน้มว่าไม่ควรถูกลบมากที่สุด
    • สร้างก่อนที่จะลบ หากคุณต้องการแทนที่ทรัพยากร ให้คิดอย่างรอบคอบว่าคุณจำเป็นต้องสร้างการแทนที่ก่อนที่จะลบต้นฉบับหรือไม่ หากคำตอบคือใช่ create_before_destroy สามารถช่วยได้ คุณสามารถบรรลุผลลัพธ์เดียวกันได้ด้วยตนเองโดยดำเนินการสองขั้นตอน: ขั้นแรกให้เพิ่มทรัพยากรใหม่ให้กับการกำหนดค่าแล้วรันคำสั่ง Apply จากนั้นลบทรัพยากรเก่าออกจากการกำหนดค่า แล้วใช้คำสั่ง Apply อีกครั้ง
    • การเปลี่ยนตัวระบุจำเป็นต้องเปลี่ยนสถานะ หากคุณต้องการเปลี่ยน ID ที่เชื่อมโยงกับทรัพยากร (เช่น เปลี่ยนชื่อ aws_security_group จาก instance เป็นคลัสเตอร์_instance) โดยไม่ต้องลบทรัพยากรและสร้างเวอร์ชันใหม่ คุณต้องอัปเดตไฟล์สถานะ Terraform ให้สอดคล้องกัน อย่าทำเช่นนี้ด้วยตนเอง - ใช้คำสั่ง terraform state แทน เมื่อเปลี่ยนชื่อตัวระบุ คุณควรรันคำสั่ง mv terraform state ซึ่งมีไวยากรณ์ต่อไปนี้:
      terraform state mv <ORIGINAL_REFERENCE> <NEW_REFERENCE>

      ORIGINAL_REFERENCE คือนิพจน์ที่อ้างถึงทรัพยากรในรูปแบบปัจจุบัน และ NEW_REFERENCE คือตำแหน่งที่คุณต้องการย้าย ตัวอย่างเช่น เมื่อเปลี่ยนชื่อกลุ่ม aws_security_group จาก instance เป็นคลัสเตอร์_instance คุณจะต้องรันคำสั่งต่อไปนี้:

      $ terraform state mv 
         aws_security_group.instance 
         aws_security_group.cluster_instance

      สิ่งนี้เป็นการบอก Terraform ว่าสถานะที่เคยเชื่อมโยงกับ aws_security_group.instance ก่อนหน้านี้ควรเชื่อมโยงกับ aws_security_group.cluster_instance แล้ว หากหลังจากเปลี่ยนชื่อและรันคำสั่ง Terraform Plan แล้วไม่แสดงการเปลี่ยนแปลงใด ๆ แสดงว่าคุณทำทุกอย่างถูกต้องแล้ว

    • การตั้งค่าบางอย่างไม่สามารถเปลี่ยนแปลงได้ พารามิเตอร์ของทรัพยากรจำนวนมากไม่สามารถเปลี่ยนแปลงได้ หากคุณพยายามเปลี่ยนแปลง Terraform จะลบทรัพยากรเก่าและสร้างทรัพยากรใหม่แทนที่ โดยปกติแล้วหน้าแหล่งข้อมูลแต่ละหน้าจะระบุว่าจะเกิดอะไรขึ้นเมื่อคุณเปลี่ยนการตั้งค่าเฉพาะ ดังนั้นโปรดตรวจสอบเอกสารประกอบ ใช้คำสั่ง plan เสมอและพิจารณาใช้กลยุทธ์ create_before_destroy

    ความสม่ำเสมอที่เลื่อนออกไปนั้นสอดคล้องกับ...กับการเลื่อนเวลา

    API ของผู้ให้บริการระบบคลาวด์บางราย เช่น AWS เป็นแบบอะซิงโครนัสและมีความสอดคล้องล่าช้า ความไม่ตรงกันหมายความว่าอินเทอร์เฟซสามารถส่งคืนการตอบสนองได้ทันทีโดยไม่ต้องรอให้การดำเนินการที่ร้องขอเสร็จสิ้น ความสอดคล้องที่ล่าช้าหมายความว่าการเปลี่ยนแปลงอาจต้องใช้เวลาในการเผยแพร่ทั่วทั้งระบบ ในขณะที่สิ่งนี้เกิดขึ้น การตอบสนองของคุณอาจไม่สอดคล้องกันและขึ้นอยู่กับแบบจำลองแหล่งข้อมูลที่ตอบสนองต่อการเรียก API ของคุณ

    ตัวอย่างเช่น ลองจินตนาการว่าคุณทำการเรียก API ไปที่ AWS เพื่อขอให้สร้างเซิร์ฟเวอร์ EC2 API จะส่งคืนการตอบกลับที่ "สำเร็จ" (สร้างแล้ว 201 รายการ) เกือบจะในทันที โดยไม่ต้องรอให้สร้างเซิร์ฟเวอร์เอง หากคุณพยายามเชื่อมต่อทันที เกือบจะล้มเหลวอย่างแน่นอน เนื่องจาก ณ จุดนี้ AWS ยังคงเริ่มต้นทรัพยากร หรืออีกทางหนึ่ง เซิร์ฟเวอร์ยังไม่ได้บูต นอกจากนี้ หากคุณโทรอีกครั้งเพื่อรับข้อมูลเกี่ยวกับเซิร์ฟเวอร์นี้ คุณอาจได้รับข้อผิดพลาด (404 Not Found) ประเด็นก็คือข้อมูลเกี่ยวกับเซิร์ฟเวอร์ EC2 นี้อาจยังคงเผยแพร่ไปทั่ว AWS ก่อนที่จะสามารถใช้ได้ทุกที่ คุณจะต้องรอสักครู่

    เมื่อใดก็ตามที่คุณใช้ API แบบอะซิงโครนัสที่มีความสอดคล้องแบบ Lazy คุณต้องลองคำขอของคุณอีกครั้งเป็นระยะ ๆ จนกว่าการดำเนินการจะเสร็จสิ้นและเผยแพร่ผ่านระบบ น่าเสียดายที่ AWS SDK ไม่มีเครื่องมือที่ดีสำหรับสิ่งนี้ และโปรเจ็กต์ Terraform เคยประสบปัญหาข้อบกพร่องมากมายเช่น 6813 (https://github.com/hashicorp/terraform/issues/6813):

    $ terraform apply
    aws_subnet.private-persistence.2: InvalidSubnetID.NotFound:
    The subnet ID 'subnet-xxxxxxx' does not exist

    กล่าวอีกนัยหนึ่ง คุณสร้างทรัพยากร (เช่น ซับเน็ต) จากนั้นลองรับข้อมูลบางอย่างเกี่ยวกับทรัพยากรนั้น (เช่น ID ของซับเน็ตที่สร้างขึ้นใหม่) และ Terraform ไม่พบทรัพยากรนั้น ข้อบกพร่องเหล่านี้ส่วนใหญ่ (รวมถึง 6813) ได้รับการแก้ไขแล้ว แต่ยังคงพบปัญหาอยู่บ้างเป็นครั้งคราว โดยเฉพาะอย่างยิ่งเมื่อ Terraform เพิ่มการรองรับสำหรับทรัพยากรประเภทใหม่ สิ่งนี้น่ารำคาญ แต่โดยส่วนใหญ่แล้วจะไม่ก่อให้เกิดอันตรายใดๆ เมื่อคุณเรียกใช้ Terraform Apply อีกครั้ง ทุกอย่างควรจะทำงานได้ เนื่องจากในเวลานี้ข้อมูลจะแพร่กระจายไปทั่วระบบแล้ว

    ข้อความที่ตัดตอนมานี้นำเสนอจากหนังสือของ Evgeniy Brikman "Terraform: โครงสร้างพื้นฐานในระดับโค้ด".

ที่มา: will.com

เพิ่มความคิดเห็น