10 คะแนน โดย GN⁺ 2026-01-15 | 3 ความคิดเห็น | แชร์ทาง WhatsApp
  • แชร์ประสบการณ์ความหงุดหงิดของนักพัฒนากับ feedback loop ที่ช้าและกระบวนการดีบักที่ซับซ้อนของ GitHub Actions
  • ในโปรเจกต์ tmplr มีการสร้างเอกสารด้วย CUE ผ่าน build.rs แต่เมื่อ CI build ล้มเหลว ปัญหาก็เริ่มต้นขึ้น
  • จาก 4 แพลตฟอร์ม มีเพียง Linux ARM ที่ build ล้มเหลว โดยสาเหตุมาจากพฤติกรรมของ GitHub Actions ที่ซ่อนไบนารี x86_64 บน runner arm64 ระหว่างการ cross build
  • feedback loop ที่ไม่มีประสิทธิภาพนี้ต้องใช้เวลา 2–3 นาที ต่อการทดสอบการเปลี่ยนแปลงเพียงครั้งเดียว
  • ทางแก้คือการลบ build.rs และเปลี่ยนไปใช้ GNU Makefile เพื่อควบคุมตรรกะของ CI โดยตรงและแก้ปัญหาได้สำเร็จ

ที่มาของปัญหา

  • tmplr เป็นเครื่องมือ scaffold ไฟล์/โปรเจกต์ที่ใช้ไฟล์เทมเพลตซึ่งมนุษย์อ่านและเขียนได้
  • ใน build.rs ใช้ CUE เพื่อสร้าง README.md, CHANGELOG.md และไฟล์เวอร์ชัน/ไฟล์ช่วยเหลือ เพื่อรับประกันความสอดคล้อง
  • งานนี้เสร็จภายในเวลาประมาณ 1.5 ชั่วโมง และเขียนบทความที่เกี่ยวข้องเสร็จแล้วด้วย
  • บนเครื่องโลคัลทำงานได้ตามปกติ แต่ในสภาพแวดล้อม CI ของ GitHub Actions build ล้มเหลวเพราะไม่ได้ติดตั้งไบนารี CUE

สาเหตุของการ build ล้มเหลว

  • จาก 4 แพลตฟอร์ม (Linux ARM, macOS ARM, Linux x86_64, macOS x86_64) มีเพียง Linux ARM ที่เกิดข้อผิดพลาด “command not found”
  • สาเหตุคือ matrix cross build ถูกแยกสภาพแวดล้อมอย่างเข้มงวด ทำให้ CUE ถูกติดตั้งเฉพาะบน โฮสต์ Linux x86_64 และ โฮสต์ macOS ARM เท่านั้น
    • macOS สามารถรันไบนารี x86_64 ได้ไม่มีปัญหา
    • Linux x86_64 ก็รันไบนารี x86_64 ได้ไม่มีปัญหา
    • แต่ GitHub Actions ซ่อนไบนารี x86_64 บน runner arm64 ทำให้ไม่สามารถรันได้

feedback loop ที่ไม่มีประสิทธิภาพ

  • ขั้นตอนที่ต้องทำซ้ำเพื่อแก้ปัญหา:
    1. ค้นหาวิธีแก้ที่เป็นไปได้
    2. แก้ไข ci.yml
    3. commit และ push (jj squash --ignore-immutable && jj git push)
    4. เปิดแท็บ "Actions"
    5. เปิดการรันล่าสุด
    6. เปิดการรัน Linux ARM
    7. รอสักสองสามวินาที
    8. สิ้นหวัง
    9. ทำซ้ำ
  • ใช้เวลา 2–3 นาที ต่อการเปลี่ยนแปลงหนึ่งครั้ง
  • ในอุดมคติ GitHub ควรมี local runner ที่มีฟีเจอร์ครบถ้วน หรืออย่างน้อยก็มีวิธีให้ตรวจสอบความคืบหน้าได้อย่างรวดเร็วหลัง push
    • เช่นฟีเจอร์แบบ "scratch commit": วิธีทดสอบการรันหลายแบบโดยไม่ทำให้ประวัติ Git และบันทึกการรันของ Actions สกปรก
  • แต่ตอนนี้ยังไม่มีความสามารถแบบนั้น

วิธีแก้ปัญหา

  • หลังจากวนลูปอยู่ 30 นาทีจึงหยุด
  • นำวิธีที่เป็นที่รู้จักบนอินเทอร์เน็ตมาใช้: "อย่าให้ GitHub Actions จัดการตรรกะเอง แต่ให้ควบคุมสคริปต์โดยตรง แล้วให้ Actions มีหน้าที่แค่เรียกสคริปต์นั้น"
  • ลบ build.rs (แม้จะรู้สึกเสียดาย แต่ก็ต้องยอมเสียสละ)
  • ย้ายงานสร้างทั้งหมดไปไว้ใน GNU Makefile
  • commit ไฟล์ที่ถูกสร้างไว้ลงในรีโพซิทอรี และย้อนการเปลี่ยนแปลงของ CI กลับ
  • แก้ปัญหาได้เรียบร้อย

บทสรุป

  • GitHub Actions เป็นสาเหตุที่ทำให้บางสิ่งดี ๆ ใช้งานไม่ได้
  • เสียเวลาไปมากกับการดีบัก runner และการปรับแต่งกระบวนการ build
  • แต่ก็ยังมีข้อดีอย่าง การ build บน macOS ที่ยากจะหาได้จากวิธีอื่น
  • แน่นอนว่า ยังไม่รู้จักระบบอื่นที่ตั้งค่าได้ง่ายกว่า GitHub Actions
    > We are all doomed to GitHub Actions. …but at least I dodged the bullet early.

3 ความคิดเห็น

 
iolothebard 2026-01-15

GitHub Actions ควรทำแค่เซ็ตอัปสภาพแวดล้อม (OS, build toolchain, …) กับรันสคริปต์ (shell, Python, bat, ps1…) เท่านั้น ต่อให้ GitHub ล่ม ถ้ามีแค่สภาพแวดล้อมพร้อม ก็ควรจะ build ได้จากที่ไหนก็ได้ พอมอง workflow ของ GitHub Actions ช่วงนี้แล้วก็รู้สึกว่า จำเป็นต้องไปขุดหาของพวกนี้มาใช้ถึงขนาดนั้นเลยเหรอ สมัยนานมาแล้ว(?) Ansible ก็เคยเป็นแบบนั้นแล้วก็พังไป

 
GN⁺ 2026-01-15
ความเห็นจาก Hacker News
  • ปัญหาหลักของ GitHub Actions คือวงจรฟีดแบ็กช้าเกินไป
    แค่จะเช็กความล้มเหลวง่าย ๆ ก็ต้อง push แล้วรอ น่าหงุดหงิดมาก
    คิดว่าควรแยกงาน CI ออกเป็นสคริปต์ที่รันในเครื่องได้ และใช้ความสามารถของ Actions แค่เป็นการเสริมแบบค่อยเป็นค่อยไป
    ชุด workflow_dispatch กับ gh workflow run ก็ใช้ได้ดี แต่ที่ตัวหลังไม่ให้ URL ของ workflow ที่รันทันทีนั้นไม่สะดวก

    • ถ้าใช้ nektos/act ก็รัน Actions ในเครื่องได้
      ถือว่าช่วยให้ได้ฟีดแบ็กเร็วขึ้นค่อนข้างสำเร็จ
    • ฉันทำให้ Actions เป็นมาตรฐานสำหรับการ build และทดสอบอิมเมจ Docker
      ถ้ามีปัญหาก็ debug ได้ในสภาพแวดล้อมที่แทบจะเหมือน GitHub Actions
    • รู้สึกว่าการที่รันขั้นตอน CI ในเครื่องไม่ได้เป็นเรื่องไร้เหตุผล
      มันควรเป็นข้อกำหนดพื้นฐานของทุกระบบ CI
    • เคยคิดจะทำเครื่องมือ CI ที่รันในเครื่องได้เอง
      สุดท้ายสิ่งสำคัญคือฟีเจอร์อย่างการจัดคิว การวิเคราะห์เอาต์พุต และเทเลเมทรีประวัติการบิลด์
    • ตอนใช้ gh workflow run ถ้าอยากได้ URL ต้องไปดึงรายการ workflow run ผ่าน GitHub API อีกรอบ
      ถ้ามีหลายงานรันพร้อมกันอาจสับสนได้ แต่ตอนนี้ก็ยังพอใช้งานได้ดี
  • ลองสรุปทิปสำหรับออกแบบ CI ไว้

    1. ใช้ภาษาสคริปต์ที่เป็นมิตรกับ CI อย่าง pwsh แทน bash
    2. อย่าใส่ logic ลงใน workflow ให้คงความเรียบง่ายไว้
    3. ทำเป็นสคริปต์อิสระเพื่อให้ทดสอบในเครื่องได้
    4. เก็บสถานะเอาต์พุตและข้อมูลเวอร์ชันไว้เพื่อให้ debug ง่าย
    5. ลองพิจารณา third-party runner ที่มีความสามารถด้าน debugging ดี
    • ไม่เห็นด้วยกับข้อ (1) มองว่าถ้ากระบวนการ build หรือทดสอบซับซ้อนขึ้น นั่นคือสัญญาณเตือน
      shell ธรรมดาก็ควรพอ
    • ไม่เห็นด้วยกับข้อ (1) แต่คิดว่าข้อ (2) ถูกต้อง
      ควรกำหนด CI target ใน Makefile แล้วเรียกง่าย ๆ แบบ make ci-test
    • เมื่อก่อนเคยเจอนรกของ Jenkins plugin
      หลังจากนั้นก็จัดการ CI ทั้งหมดด้วยตัวครอบง่าย ๆ อย่าง make build
    • ถ้าครอบทุก build ไว้ในสคริปต์เดียว ระบบ CI จะสูญเสียมุมมองเชิงลึกของแต่ละขั้นตอน
      ถ้ามีตัวแบ่งอย่าง BeginStep("Step Name") ก็คงดี
    • สุดท้ายถ้าโครงสร้างเป็นแบบนี้ ก็อดคิดไม่ได้ว่าเราต้องการเครื่องมือ CI แบบใหม่ที่รันสคริปต์โดยตรงหรือเปล่า
  • ปัญหาไม่ได้อยู่ที่ GitHub Actions เองเท่าไร แต่อยู่ที่ระบบอัตโนมัติที่พอกทับไว้แบบเละเทะด้านบน
    ควรทำ logic เป็นสคริปต์ด้วยภาษาอย่าง Python เพื่อให้รันในเครื่องได้ด้วย

    • สิ่งที่หลายคนไม่พอใจคือไม่สามารถเข้า SSH ไป debug บน VM ที่ล้มเหลวได้โดยตรง
      ทุกครั้งต้องแก้ workflow, push, แล้วรอ
    • บางคนก็แซวว่า “งานทำสคริปต์แบบนั้นคือโปรเจกต์หลายสัปดาห์ที่เอาไปเก็บเงินได้”
    • ฟีเจอร์เฉพาะ CIอย่าง deployment, release, caching นั้นยากจะจำลองในเครื่องให้เหมือนทั้งหมด
    • วิธีนี้ให้อารมณ์เหมือนยุคที่systemd เรียกสคริปต์ init.d แต่ก็ไม่ได้แย่อะไร
    • มีคนยืนยันเลยว่า “นี่เป็นความผิดของ GitHub Actions 100%”
  • ฉันทำ CI ทั้งหมดภายในคอนเทนเนอร์
    แพลตฟอร์ม CI มีหน้าที่แค่รันคอนเทนเนอร์นั้น จึงทำให้รันในเครื่องได้เหมือนกัน
    พวกแพลตฟอร์มไม่ชอบวิธีนี้ เพราะมันทำลายvendor lock-in

    • ชอบSourceHut CI
      ถ้าล้มเหลวสามารถ SSH เข้าไป debug ได้ทันที และแก้ manifest แล้วรันใหม่ได้โดยไม่ต้อง push branch
      แต่ต้อง self-hosting
    • ใน GitLab CI ก็เคยใช้วิธีคล้ายกันโดยทำอิมเมจ Docker เฉพาะขึ้นมา
      ทำให้มาตรฐานง่ายขึ้น แต่ก็มี trade-off เรื่องการดูแลรักษาอิมเมจ
    • ข้อเสียคือการทำบิลด์ macOS ให้เป็นคอนเทนเนอร์นั้นทำได้ยาก
    • webhook ของ GitHub ละเอียดมาก
      จริง ๆ แทบไม่มี lock-in แต่ผู้คนกลับติดอยู่กับCI/CD cargo cult
    • มีคนตอบกลับประมาณว่า “ส่งเรื่องนี้มาเป็นจดหมายข่าวให้หน่อย”
  • ฉันชอบ GitHub Actions
    มันดีกว่า Travis ที่เคยใช้ และมีประโยชน์มากในฐานะทรัพยากรฟรีสำหรับโปรเจกต์ OSS
    หลังจากใช้ Nix แล้ว ความสามารถในการทำซ้ำสภาพแวดล้อมก็ดีขึ้นมาก ทำให้เข้ากับ Actions ได้ดีขึ้นเยอะ

    • ฉันก็เห็นด้วยกับแนวทาง Nix
      คอนเทนเนอร์ที่ทำด้วย flake สามารถรันใน Actions ได้ตรง ๆ
      โปรเจกต์ตัวอย่าง
  • คิดว่า GitHub Actions ควรเป็นโครงสร้างที่แค่เรียกสคริปต์ bash หรือ python
    bash มีข้อจำกัดเยอะ ส่วน Python ยืดหยุ่นกว่าและรันในเครื่องก็ง่าย
    วิธีแบบในบทความนี้ที่ติดตั้ง uv อัตโนมัติและจัดการ dependency ให้ถือว่าเหมาะที่สุด
    แม้จะซับซ้อนกว่า bash แต่ในสภาพแวดล้อมของ Actions ประเด็นเรื่องประสิทธิภาพไม่ได้ใหญ่มาก

    • จริง ๆ แล้ว YAML มีไว้สำหรับนิยามสภาพแวดล้อมรันไทม์ และควรแยก logic การทำงานไว้นอกไฟล์
  • ปัญหาใหญ่ที่สุดของ Actions คือวิธีโฆษณาให้ “ประกอบ workflow เข้าด้วยกัน”
    มันแทบ debug ไม่ได้ และการตั้งค่า cache ก็จุกจิกจนทำให้ build ช้า
    ด้วยเหตุนี้ วิธีแบบรันตรงบน VM ถาวรจึงดูน่าสนใจ

  • ฉันเป็นผู้ก่อตั้ง Depot
    กำลังให้บริการ runner สำหรับ GitHub Actions ที่เร็วกว่าและถูกกว่า
    ความไม่พอใจที่หลายคนรู้สึกนั้นตรงกับความเห็นของคนส่วนใหญ่จริง ๆ
    ระบบ Actions ไม่มีประสิทธิภาพในเชิงโครงสร้าง และเรายังเจอคอขวดใหม่ ๆ ทุกสัปดาห์
    ฉันมั่นใจว่ามีวิธีที่ดีกว่านี้ และกำลังทดลองอยู่
    ดูรายละเอียดเพิ่มเติมได้ที่ depot.dev

  • เมื่อสุดสัปดาห์ก่อนฉันทำเครื่องมือชื่อ gg watch action
    มันเป็นเครื่องมือที่ช่วยหา action ล่าสุดหรือ action ที่กำลังรันอยู่ของ branch ปัจจุบัน
    ลิงก์ GitHub

    • กระแสตอบรับดีมาก มีคนบอกว่า “นี่ควรเป็นฟีเจอร์ของ gh CLI มาตั้งแต่แรก”
      แต่ก็มีบั๊กที่ทำให้ไม่เห็น repository ในคำสั่ง gg tui
  • สงสัยว่าเครื่องมืออย่าง act จะช่วยได้ไหม
    nektos/act
    แม้การรันในเครื่องกับออนไลน์อาจต่างกันเพราะสถาปัตยกรรมไม่เหมือนกัน แต่ก็ดูยังมีประโยชน์

    • ตอนที่เคยดูไว้ก่อนหน้านี้ มันยังแทนที่ทั้งหมดไม่ได้
      มีความเข้ากันได้ประมาณ 80%
    • แม้จะไม่เหมือนกันเป๊ะ แต่ก็มีประโยชน์มากในการสร้างวงจรฟีดแบ็กที่รวดเร็ว
    • จริง ๆ สิ่งที่จำเป็นที่สุดคือฟีเจอร์ที่ให้เข้า SSH ไป debug ได้หลังงานล้มเหลว
      SourceHut รองรับสิ่งนี้ ทำให้สะดวกมาก
 
anyflow 2026-01-18

ดูเหมือนว่านี่จะเป็นปัญหาที่หลีกเลี่ยงไม่ได้ เพราะโครงสร้างบังคับให้ต้องใส่ logic ลงไปใน yaml

ดูเหมือนว่าบทความข้างบนจะเสนอคำตอบไว้คร่าว ๆ แบบด้านล่าง แต่ถ้าแทนส่วนของสคริปต์ด้วย Dagger ก็ชวนให้คิดว่านี่อาจเป็นคำตอบที่ถูกต้องก็ได้

"อย่าปล่อยให้ GitHub Actions จัดการ logic แต่ให้ควบคุมสคริปต์เองโดยตรง และให้ Actions มีหน้าที่แค่เรียกใช้สคริปต์นั้น"