การเขียน Kubernetes Controller, Part 4 — Spec แรกของ Controller

Chanwit Kaewkasi
2 min readJan 11, 2022

--

จาก Part ที่แล้ว ที่พูดเกี่ยวกับการใช้คุณสมบัติของ Controller มาเพื่อแก้ปัญหาความเป็นอัตโนมัติในการจัดการ Terraform ใน Part นี้เราก็จะมาเริ่มดู Spec แรกกัน

Spec ที่ใช้เขียนอธิบายพฤติกรรมของ Terraform Controller เมื่อมี Terraform Object เข้าไปในระบบนั้นเป็น Test Case ที่ตอนแรกเขียนด้วย Ginkgo และ Gomega ต่อมา Maintainer ของ Flux มาเล่าให้ฟังว่า Ginkgo นั้นสร้างความลำบากให้กับการเขียน Test เพราะ Logic การ Execute มันซับซ้อนเกินจำเป็น แต่ผมเจอว่า Ginkgo มีการใช้ It(“”) ใช้ By(“”) ในการเพิ่ม Expressiveness ของ Test ได้ดีก็เลยยังอยากได้ฟีเจอร์นี้อยู่

ส่วน Gomega ทุกคนลงความเห็นว่าดี ตัวอย่าง เช่น Eventually(…) มีประโยชน์มากในการ Test ตัว Status ของ Kubernetes Object เป็นต้น

ก็เลยแกะดู Ginkgo เจอว่า It(“”) และ By(“”) เป็นแค่ fmt.Fprintf ก็เลยลอกเอามาใช้แบบดื้อ ๆ แล้วก็ลบ Ginkgo ออกจาก go.mod ไป

ตัว Spec แรกที่ได้ เลยมีหน้าตาแบบนี้

มันไม่ได้ Generate แบบ Automatic นะครับ อันนี้ Print ออกมาปนกับ Log ของ Controller แล้วก็จัด Format ด้วยมือ ไม่อยากเสียเวลาไปเขียน Pretty Printer เลยทำแบบนี้ไปก่อน

ตัว Executable ของ Spec (Test Case) จริง ๆ อยู่ที่นี่

คราวนี้ก็มาไล่ว่า Spec มันทำอะไรบ้าง เราจะคุยเป็นส่วน ๆ แบ่งเป็นพาร์ทด้านการออกแบบ, พาร์ทด้านกลไกทาง Kubernetes Machinery, และพาร์ทด้าน GitOps

พาร์ทด้านการออกแบบ API

จาก Spec เราได้ API หน้าตาแบบนี้ คือมีแค่ .spec.approvePlan เป็นโหมด เรียกว่า “auto” คือทำทั้ง Plan และ Apply ตัว Terraform Resource และ .status.availableOutputs ที่เป็นการลิสต์ออกมาว่ามี output อะไรที่สามารถดึงออกมาได้บ้างจากผลการ reconcile ตัว Terraform

สำหรับส่วนอื่น ๆ ก็จะเป็นการเชื่อมต่อเข้ากับ Flux source ในกรณีนี้คือ GitRepositry และทำการ reconcile ตัว Terraform resource ที่อยู่ในพาธ ./terraform-hello-world-example

พาร์ทด้านกลไกทาง Kubernetes Machinery

ในส่วนของ Kubernetes Machinery เราจะเห็นการใช้ API Machinery หลาย ๆ ส่วน ไม่ว่าจะเป็นการใช้ Controller Runtime Client เพื่อ Create, หรือ Update Object ซึ่งก็คือการเปลี่ยนค่าใน Spec และการ Update Spec ผ่าน API Server เข้าไปเก็บใน ETCD

ส่วนการ Update Status ต้องแยกทำด้วย API อีกชุดซึ่งเป็นกลไกพิเศษที่ต้องทำความเข้าใจไม่งั้นก็จะงงอยู่นานว่าทำไมตั้งค่าใน Status แล้วสั่ง Update ด้วยชุด API สำหรับ Spec แล้วไม่ Work ซักที เป็นต้น

พาร์ทด้าน GitOps

ในเชิงการเปลี่ยน State ไม่มี เพราะกลไกใน Spec นี้เป็นแบบ “auto” เลยยังไม่มีอะไร ใน Spec ตัวอื่นจะมีแง่มุมเชิงการออกแบบที่ต้องคิดเพื่อให้เข้ากับ GitOps Workflow ซึ่งจะเอาไว้เล่าต่อไปครับ

ในเชิงการดึง Artifact มาใช้จาก Source controller จะเป็นขั้นตอนมาตรฐานคือได้ URL มาจาก Status ของ source จากนั้นก็ทำการ Download และ Untar เพื่อเตรียม Directory สำหรับให้ Terraform รัน

ในเชิงการ Emit Event เพื่อให้ Notification Controller ใช้ได้ ตอนนี้มีตรงขั้นตอนการเกิด Error และการ Apply สำหรับ โดยในรายละเอียดการคุยกับ Event Recorder จะเล่าให้ฟังในครั้งถัด ๆ ไปครับ

ในการสร้าง Condition แบบ Ready ที่ตรวจจับได้ด้วย Kustomization Controller เพื่อให้เกิด Health Check ตัว Terraform ตรงนี้มีมาตรฐานอยู่แล้วว่า ถ้า Condition ใน Status เป็น Type แบบ Ready และมีค่า Status เป็น True จะทำให้ Kustomization Controller สรุปว่าตัว object ที่ถูกควบคุมอยู่นั้น (ในกรณีนี้คือ Terraform object) มีสถานะ Healthy ซึ่งถ้าออกแบบให้สอดคล้องกันก็จะทำให้เกิดการ Chain object ได้อย่างน่าสนใจ ซึ่งผมจะเล่าตัว Application ของ Feature นี้ให้ฟังต่อไปครับ

จาก Spec แรกที่เป็นการออกแบบด้วย TDD และได้ฟีเจอร์แรกคือ
ApprovePlan = “auto” ออกมา ก็เริ่มต้นประมาณนี้ครับ

ใน Part ถัดไปก็จะขยับไปที่ Spec อื่น ๆ ที่เกี่ยวข้องกับ GitOps Workflow และ Terraform Workflow มากขึ้นครับ

--

--

Chanwit Kaewkasi
Chanwit Kaewkasi

Written by Chanwit Kaewkasi

Technical Advisor at ConfigHub Inc. ex-weaveworks. Go nut since r57 (pre v1)

No responses yet