พอร์ต Kubernetes ไปไว้บนเบราว์เซอร์
(ngrok.com)- webernetes เป็นโปรเจ็กต์ที่ย้ายบางส่วนของ Kubernetes มาเป็น TypeScript เพื่อให้สามารถรันคลัสเตอร์ภายในเบราว์เซอร์ได้ โดยสร้างขึ้นในช่วง 2 เดือนด้วย 552 commits, 629 files และขนาดเกือบ 100,000 บรรทัด
- ไม่ได้ใช้วิธีคอมไพล์ Kubernetes เดิมทั้งก้อนไปเป็น WebAssembly แต่สร้างใหม่ทั้ง บางส่วนของ kubelet, คอนโทรลเลอร์หลายตัว, CNI และคอนเทนเนอร์รันไทม์บนเบราว์เซอร์ รวมถึง API สำหรับจัดการคลัสเตอร์
- ไม่ได้ดึงอิมเมจจริงจาก image registry แต่กำหนดอิมเมจผ่าน TypeScript API และเป้าหมายไม่ใช่ดิสทริบิวชันสำหรับโปรดักชัน แต่คือการสร้าง คอนเทนต์ Kubernetes แบบอินเทอร์แอ็กทีฟ
- แม้โค้ดส่วนใหญ่จะเขียนโดย LLM แต่ทุกบรรทัดมีมนุษย์รีวิว และตรวจสอบด้วย integration tests 204 รายการ ที่รันชุดทดสอบแบบเดียวกับ k3s รวมถึง unit tests 1,855 รายการที่พอร์ตมาจากโค้ดเบส Go ของ Kubernetes
- ระหว่างการพอร์ต LLM มักย่อโค้ด, สร้าง helper ขึ้นมาเอง และทำชุดทดสอบตกหล่นซ้ำ ๆ ดังนั้นหากต้องการได้ประโยชน์จากความเร็วในการสร้างโค้ด จึงต้องใช้ การรีวิวและการทดสอบ ควบคู่กัน
สิ่งที่ webernetes รันอยู่ในเบราว์เซอร์
- webernetes เป็นโปรเจ็กต์ที่พอร์ต Kubernetes บางส่วนมาเป็น TypeScript เพื่อให้รันคลัสเตอร์ในเบราว์เซอร์ได้
- เดโมคลัสเตอร์ทำงานทั้งหมดภายในเบราว์เซอร์ และทำงานได้ใกล้เคียงกับสิ่งที่ Kubernetes คลัสเตอร์จริงทำอยู่มาก
-
วงจรชีวิตของ Pod
- DNS และเครือข่ายของคลัสเตอร์
- การเก็บกวาดคอนเทนเนอร์ที่ไม่ใช้แล้ว
- การจัดสรร IP
- การติดตาม
DeploymentและReplicaSet - จุดสีน้ำเงินในเดโมแสดงให้เห็นว่า Pod ส่งคำขอหากันอย่างไร
-
การพอร์ตบางส่วนแทนการคอมไพล์เป็น WebAssembly
- ไม่ได้คอมไพล์ Kubernetes เป็น WebAssembly
- แม้แต่โปรแกรม Go
hello, world!แบบง่าย ๆ เมื่อคอมไพล์เป็น WebAssembly ก็ยังมีขนาดราว 540KiB หลัง gzip ขณะที่ webernetes มีขนาดราว 140KiB หลัง gzip - หากคอมไพล์ Kubernetes ทั้งหมดเป็น WebAssembly ก็อาจต้องส่งข้อมูลระดับหลายเมกะไบต์ และยังเกิดข้อผิดพลาดตอนคอมไพล์จากการเรียกใช้ system-level API ที่ใช้ในเบราว์เซอร์ไม่ได้
- webernetes ประกอบด้วยองค์ประกอบต่อไปนี้
- การพอร์ตบางส่วนของไบนารี Kubernetes kubelet ที่จำเป็นต่อการรัน Pod และ probes
- การพอร์ตคอนโทรลเลอร์ Kubernetes หลายตัว เช่น Pod scheduler, namespace controller, kube-proxy และ deployment controller
- container network interface (CNI) บนเบราว์เซอร์สำหรับการสื่อสารระหว่าง Pod
- คอนเทนเนอร์รันไทม์บนเบราว์เซอร์ที่ทำให้ kubelet สามารถรันคอนเทนเนอร์ผ่าน container runtime interface (CRI)
- webernetes cluster API สำหรับงานอย่างการ apply manifest และการ watch resource
วิธีนิยามอิมเมจและการใช้ API
- เพื่อให้ขนาดเล็ก webernetes จึงไม่ดึงอิมเมจจริงจาก registry อย่าง Docker Hub
- แต่มี registry บนเบราว์เซอร์ของตัวเอง และนิยามอิมเมจผ่าน TypeScript API
- ตัวอย่างอิมเมจ
HelloWorldสืบทอดจากw8s.BaseImageและภายในexecจะตอบ"Hello, world!"ต่อ HTTP request ที่พอร์ต 8080 - ลำดับการใช้งานคลัสเตอร์มีดังนี้
- สร้างคลัสเตอร์ด้วย
new w8s.Cluster() - ลงทะเบียนอิมเมจด้วย
cluster.registerImage(HelloWorld) - apply
Deploymentmanifest ของapps/v1ด้วยcluster.apply() - เรียกดูรายการ Pod ด้วย
cluster.api.corev1.listNamespacedPod() - เฝ้าดูการเปลี่ยนแปลงของ Pod ด้วย
cluster.informer("pods", ...) - สังเกต event คำขอและคำตอบระหว่าง Pod ด้วย
cluster.on("request"),cluster.on("response") - ส่ง HTTP request ไปยัง Pod IP ผ่านเครือข่ายของคลัสเตอร์ด้วย
cluster.fetch()
- สร้างคลัสเตอร์ด้วย
- ดูตัวอย่างเพิ่มเติมได้ที่ webernetes repository examples
เป้าหมายการใช้งานและข้อจำกัดปัจจุบัน
- เป้าหมายของ webernetes คือการสร้าง คอนเทนต์ Kubernetes แบบอินเทอร์แอ็กทีฟ
- มันไม่ใช่ Kubernetes distribution ที่พร้อมใช้งานระดับโปรดักชัน และก็ไม่จำเป็นต้องรันอิมเมจจริง
- เพียงแค่ผู้สร้างคอนเทนต์สามารถตั้งค่า workload เฉพาะเพื่อแสดงแนวคิดของ Kubernetes ที่ต้องการอธิบายได้ก็เพียงพอ
- ความสามารถที่ยังไม่รองรับในตอนนี้ ได้แก่
- ConfigMaps
- Secrets
- ทรัพยากรของ Pod
- persistent volumes
- ฟีเจอร์ Kubernetes อื่น ๆ อีกหลายอย่างที่ยังไม่จำเป็น
- มีแผนจะเพิ่มฟีเจอร์ Kubernetes ที่จำเป็นต่อการสร้างคอนเทนต์ในอนาคต
สร้างด้วย LLM แต่ไม่ปล่อยให้ทำงานลำพัง
- โค้ดเกือบทั้งหมดของ webernetes เขียนโดย LLM
- เพื่อให้โปรเจ็กต์เชื่อถือได้ จึงทำสองอย่างควบคู่กัน
- รีวิวโค้ดทุกบรรทัดด้วยตัวเอง
- สร้างชุดทดสอบหลายร้อยรายการเพื่อตรวจสอบว่า webernetes ทำงานเหมือนคลัสเตอร์จริง
- การรีวิวด้วยมือช่วยให้มั่นใจได้ว่าโค้ดส่วนใหญ่ตรงกับโค้ดเบส Go ของ Kubernetes แบบบรรทัดต่อบรรทัด
- ส่วนชุดทดสอบทำหน้าที่ตรวจสอบว่าความคล้ายกันเชิงถ้อยคำนี้นำไปสู่พฤติกรรมที่เหมือนกันจริงหรือไม่
- ข้อผิดพลาดที่ยังเหลือหลังรีวิวถือเป็นความรับผิดชอบของผู้สร้างโปรเจ็กต์ และหากพบปัญหาก็ขอให้เปิด issue
เหตุผลที่โค้ดที่พอร์ตมาต้องมีการรีวิว
- กรณีอย่างการใช้ LLM เขียน C compiler หรือพอร์ต Bun จาก Zig ไปเป็น Rust มีวิธีตรวจสอบความถูกต้องแบบอัตโนมัติอยู่แล้ว
- Anthropic มี C compiler เดิมไว้ใช้เปรียบเทียบ
- Bun มี test suite ขนาดใหญ่ที่เชื่อถือได้มากพอจะ merge โค้ด Rust ใหม่กว่าล้านบรรทัดโดยไม่ต้องรีวิวด้วยมือ
- แต่ webernetes ไม่มีฐานแบบนั้น
- ถ้าต้องการ test suite ก็ต้องเขียนเอง
- หากต้องการเทียบกับ Kubernetes จริง ก็ต้องสร้างวิธีเทียบขึ้นมาเอง
- โค้ดส่วนใหญ่ของ webernetes พอร์ตมาจากโค้ดเบส Go ของ Kubernetes และจึงใช้ LLM เพราะมองว่าน่าจะเร็วกว่าการพิมพ์ด้วยมือ
- ระหว่างการพอร์ต LLM ทำพลาดซ้ำ ๆ หลายแบบ
- การย่อ: อาจแทนที่ LRU cache, expiring cache, FIFO cache, transforming cache ของ Kubernetes ด้วย
Mapแบบง่าย ๆ จนเกิดพฤติกรรมผิดพลาด - การจัดระเบียบเกินเหตุ: อาจสร้าง helper function ที่ไม่มีในโค้ด Go ต้นฉบับ ทำให้รีวิวยากขึ้นหรือเกิดความต่างแบบละเอียดอ่อน
- การตกหล่น: เวลาพอร์ต table test ของ Go มักทำ test case หลุดหายไปเองบ่อยครั้ง
- การย่อ: อาจแทนที่ LRU cache, expiring cache, FIFO cache, transforming cache ของ Kubernetes ด้วย
- หากจะเชื่อถือผลลัพธ์จากการพอร์ตด้วย LLM ก็จำเป็นต้องรีวิวผลลัพธ์นั้น และผู้สร้างโปรเจ็กต์มองว่า LLM ไม่รู้ทางลัดที่ตัวเองจะใช้ได้
การทดสอบด้วยการเทียบกับคลัสเตอร์จริง
- แม้โค้ดจะดูคล้ายต้นฉบับเมื่อวางเทียบกัน แต่ Go กับ JavaScript runtime ต่างกัน จึงอาจทำให้พฤติกรรมต่างกันได้
- webernetes ยังต้องมี channels, mutexes, คำสั่ง
selectของ Go และพฤติกรรมแบบ Go อื่น ๆ ในเวอร์ชัน JavaScript ด้วย - มีการรันชุดทดสอบเดียวกันทั้งบน webernetes และคลัสเตอร์ k3s เพื่อเปรียบเทียบพฤติกรรม
- เป้าหมายความเข้ากันได้ของ API เลือกใช้ไคลเอนต์ Kubernetes ทางการฝั่ง JavaScript ที่มี TypeScript types คือ kubernetes-client/javascript
- test harness จะสลับสภาพแวดล้อมการรันผ่าน
kubernetes.describe(..)pnpm test:nodeใช้ทดสอบกับ k3s ในสภาพแวดล้อม Nodepnpm test:browserใช้ทดสอบกับ webernetes ใน headless browser
- integration tests ไม่ได้ตรวจแค่โค้ดที่พอร์ตมา แต่ยังตรวจว่า container runtime และ cluster network แบบ custom บนเบราว์เซอร์ทำงานสอดคล้องกับคลัสเตอร์จริงด้วย
- เมื่อพบบั๊ก จะเริ่มจากสร้างเทสต์ที่ผ่านบน k3s แต่ล้มเหลวบน webernetes ก่อน แล้วใช้วงจรป้อนกลับนั้นร่วมกับความช่วยเหลือจาก LLM เพื่อทำความเข้าใจสาเหตุและแก้ไข
- ณ เวลาที่เขียน webernetes มี integration tests 204 รายการ และ unit tests 1,855 รายการ
ทำไมต้องใช้ทั้งการรีวิวและการทดสอบร่วมกัน
- โค้ดที่ LLM สร้างก็ต้องการทั้งการทดสอบที่ดีและโค้ดที่ดี เช่นเดียวกับ PR ที่มนุษย์เขียน
- ความต่างในปี 2026 คือกับเพื่อนร่วมงานที่เป็นมนุษย์ยังพอคาดหวังได้ระดับหนึ่งว่าจะส่งงานที่ดีมา แต่กับ LLM ปลอดภัยกว่าหากตั้งต้นว่ามันจะทำงานได้ไม่ดี
- ถ้าไม่รีวิวแม้แต่โค้ดทดสอบ ก็ยากจะรู้ว่า LLM กำลังทำงานตามเกณฑ์ความสำเร็จแบบใด
- ต่อให้รีวิวโค้ดทั้งหมด แต่ไม่มีชุดทดสอบ ก็ยากจะเชื่อว่ามนุษย์สามารถอนุมานทุกความเป็นไปได้ได้ครบ
- LLM พิมพ์ได้เร็วและไม่เหนื่อย จึงมีประโยชน์หากใช้มันช่วยเสนอ edge case ที่มนุษย์คิดไม่ถึง และถ้าสมเหตุสมผลก็ให้มันเขียนเทสต์ให้
- ผู้เขียนมองว่าการผสานรสนิยมและความเข้าใจของมนุษย์เข้ากับความเร็วในการลงมือเขียนของ LLM เป็นความเปลี่ยนแปลงที่ใหญ่ที่สุดนับตั้งแต่เริ่มอาชีพในปี 2012
ขนาดโปรเจ็กต์และปริมาณการใช้โทเคน
- commit แรกถูกเพิ่มเข้าไปใน webernetes repository ปัจจุบันเมื่อวันที่ 21 เมษายน
- งานช่วงแรกบางส่วนทำใน branch ของ repository ที่อยู่หลังบล็อกนี้ ดังนั้นกราฟจึงอาจไม่สะท้อนภาพรวมทั้งหมดอย่างสมบูรณ์
- กราฟจำนวนบรรทัดโค้ดแสดง 126,642 บรรทัด ในสัปดาห์ของวันที่ 15 มิถุนายน
- ตัวเลขประมาณ 100,000 บรรทัดที่กล่าวไว้ตอนต้น ไม่นับโค้ดที่ไม่ใช่ TypeScript, คอมเมนต์ และ demo app
- จำนวนบรรทัดรวมในแต่ละสัปดาห์เพิ่มขึ้นดังนี้
- สัปดาห์ของ 20 เมษายน: 11,640 บรรทัด
- สัปดาห์ของ 27 เมษายน: 20,660 บรรทัด
- สัปดาห์ของ 4 พฤษภาคม: 25,048 บรรทัด
- สัปดาห์ของ 11 พฤษภาคม: 30,417 บรรทัด
- สัปดาห์ของ 18 พฤษภาคม: 42,301 บรรทัด
- สัปดาห์ของ 25 พฤษภาคม: 54,155 บรรทัด
- สัปดาห์ของ 1 มิถุนายน: 79,704 บรรทัด
- สัปดาห์ของ 8 มิถุนายน: 98,532 บรรทัด
- สัปดาห์ของ 15 มิถุนายน: 126,642 บรรทัด
- การใช้โทเคนในเซสชันของ Codex และ Claude มี cached input token มากกว่าโทเคนประเภทอื่นอย่างชัดเจน โดยยิ่งเห็นชัดเมื่อใช้ context window ยาว ๆ จนเต็มบ่อยครั้ง
- ในสัปดาห์ของ 15 มิถุนายน มีการใช้ uncached input token 104,155,857 โทเคน, cached input token 2,196,467,968 โทเคน และ output token 6,420,826 โทเคน
การพุ่งขึ้นในสัปดาห์สุดท้ายและต้นทุน
- ในสัปดาห์สุดท้าย มีความพยายามเพิ่มการรองรับ Deployments ให้กับ demo app แต่กลายเป็นงานใหญ่กว่าที่คาด
- ความพยายามพอร์ตครั้งแรกของ LLM ทำฟังก์ชันสำคัญขององค์ประกอบที่ต้องใช้ตกหล่นไปหลายส่วน
- จากนั้นจึงระดมหลายเอเจนต์เพื่อระบุ dependency chain และพอร์ตแต่ละองค์ประกอบผ่าน sub-agent เพิ่มเติม รวมถึงใช้อีกชุดของ sub-agent ทำการรีวิว
- วิธีนี้ทำให้งานเสร็จเร็วกว่าการทำด้วยมือ แต่ไม่มีประสิทธิภาพด้านโทเคนอย่างมาก และสุดท้ายก็ยังต้องรีวิวด้วยมืออยู่ดี
- ต้นทุนโทเคน LLM เมื่อตีราคาแบบ API เพิ่มขึ้นทุกสัปดาห์ และในสัปดาห์ของ 15 มิถุนายนอยู่ที่ $1,811.64
- ตลอดทั้งโปรเจ็กต์ เวลาของผู้เขียนยังคงเป็นต้นทุนที่แพงที่สุดจนถึงช่วงท้าย
แหล่งข้อมูลเพิ่มเติมและวิธีมีส่วนร่วม
- มีวิดีโอซีรีส์ที่บันทึกกระบวนการสร้างไว้ด้วย
- ในวิดีโอจะได้เห็นทั้งความมองโลกในแง่ดีผิด ๆ ในช่วงต้น และวิธีทำงานแบบแทบไม่ต้องใช้มือเลยโดยอาศัยการควบคุมด้วยเสียงและการติดตามดวงตา
- มีการขอให้ลองใช้โปรเจ็กต์นี้ เปิด issues หรือหากสร้างอะไรขึ้นมาได้หรือเจอจุดติดขัดก็ให้ติดต่อทาง
s.rose@ngrok.com
1 ความคิดเห็น
ความเห็นจาก Hacker News
ตัวอย่างเช่น ผมทำอันนี้ไว้ https://kubernetes-made-simple.vercel.app/ ตอนนี้ก็น่าจะเอาสิ่งนี้ไปเพิ่มได้
แต่ถึงอย่างนั้นเว็บก็ดูดีมาก
น่าจะขยายเรื่อง Gateway เพิ่มอีกหน่อย และถ้าเป็นไปได้ก็ควรพูดถึง CRD ด้วย
ถ้าจะให้ยกมาสักอย่างหนึ่งที่คนส่วนใหญ่เข้าใจ k8s ผิด จนทำให้การเรียนรู้ยากโดยไม่จำเป็น มันคืออะไร?
ถ้าจำไม่ผิด ตอนแรกผมใช้ Katacoda แล้วหลังจากนั้นก็ใช้แพลตฟอร์มคล้ายกันอีกตัว ซึ่งมันมีประโยชน์มากเพราะสามารถเปิดอินสแตนซ์ใหม่ที่ตั้งค่าเฉพาะไว้ให้ผู้ใช้แต่ละคนได้ทันที
แต่ตอนนี้มันน่าจะเหมาะกับการสอนเรื่องแนวคิดหรือสถาปัตยกรรมมากกว่า ความสนุกจริง ๆ จะเริ่มตอนที่คุณเริ่มใช้ kubectl ได้คล่อง
แพลตฟอร์มคล้าย ๆ กันตัวอื่นก็ดูเหมือนจะหายไปเพราะไม่มีคนช่วยออกค่าใช้จ่าย ซึ่งก็น่าเสียดาย
หวังว่านี่จะเป็นทางเลือกได้ แม้จะมีความเสี่ยงว่าจะล้าสมัยเพราะต่างจากของจริง แต่แก่นหลักก็มักจะยังใช้ได้เสมอ
มันให้ความรู้สึกว่านี่คือวิธีที่ถูกต้องในการมอง LLM-assisted engineering AI สามารถสร้างโค้ดได้เยอะอย่างน่าทึ่ง แต่คุณค่าที่แท้จริงอยู่ที่วินัยในการรีวิวและการทดสอบรอบ ๆ มัน
มุมของการทำ Kubernetes ในเบราว์เซอร์ก็น่าสนใจ แต่ที่น่าสนใจกว่านั้นคือเวิร์กโฟลว์ โดยเฉพาะส่วนที่ทดสอบพฤติกรรมเกี่ยวกับ k8s แทนที่จะเชื่อแค่ว่า “มันดูน่าจะใช่” ผมสงสัยว่าเวลานี้มีทีมมากแค่ไหนแล้วที่ตรวจสอบโค้ดที่ AI เขียนในระดับนี้ และมันอาจเป็นทิศทางที่ทุกคนจะไปในอีกไม่กี่ปีข้างหน้าก็ได้
น่าเสียดายที่งานเขียนโค้ดไม่ได้มีโอกาสแบบนั้นทุกอย่าง
https://youtu.be/t7L2iROVaRg?is=xoV4aiCXcYMVvVDL
ความซับซ้อนที่เพิ่มขึ้นหรือประสิทธิภาพที่ลดลงคงต้องมีเหตุผลมารองรับพอสมควร แต่สำหรับบาง use case ก็ดูเหมือนจะคุ้มค่าแน่นอน
คล้ายกับการแยกระหว่าง ความซับซ้อนโดยเนื้อแท้ กับความซับซ้อนโดยบังเอิญของ Fred Brooks
แน่นอนว่า ถ้าคุณเอา kube ไปใช้กับงานที่ทำแบบง่ายกว่านั้นได้ kube ก็จะกลายเป็นความซับซ้อนโดยบังเอิญอย่างรวดเร็ว
เปรียบเทียบก็คือ ถ้ามีคนพอร์ต DOOM ลงเบราว์เซอร์ นั่นหมายความว่าตอนนี้คุณเล่นมันในเบราว์เซอร์ได้ แต่ฐานข้อมูลต่าง ๆ ที่เห็นอยู่ในแท็บ พวกนั้นไม่ได้รันอยู่ในเบราว์เซอร์จริง ๆ ใช่ไหม?
ถ้าเปิด ruby2d ขึ้นมา ก็พูดไม่ได้อยู่ดีว่าจู่ ๆ มันก็กลายเป็นมี Ruby ฝั่งไคลเอนต์รองรับแล้ว การจะให้มันรันจริงในแท็บเบราว์เซอร์ได้ต้องมีงานคัสตอมอีกมากมาย
ในทางกลับกัน บริการคอนเทนเนอร์แบบแบ็กเอนด์ทั่วไปนั้นสามารถย้ายไปมาและรันได้แทบทุกที่จริง ๆ
เพราะงั้นผมเลยไม่ค่อยเข้าใจประเด็น และถ้าผมเข้าใจผิดก็ช่วยแก้ให้ที มันดูไม่ตรงกับสิ่งที่อ้างด้วยซ้ำ
มันไม่ได้รัน container image จริง ๆ การเรียกมันว่า “Kubernetes แบบจำลอง” อาจจะเหมาะกว่า
สิ่งที่ถูกพอร์ตมาคือ control plane โดย scheduler, kube-proxy, deployment controller และส่วนอื่น ๆ ถูกย้ายมาจากซอร์ส Go จริง และมีการทดสอบความสอดคล้องของพฤติกรรมกับ k3s โดยใช้ client API เดียวกัน ส่วน “การเรนเดอร์” คือแอปเดโมที่ทำภาพเป็นจุดเคลื่อนที่ของคำขอระหว่าง Pod
สนุกดี