- ข้อไม่พอใจต่อ GitHub Actions
- ทีมประกอบด้วยวิศวกรราว 15 คน และทุกคน push โค้ดไปที่สาขา main อย่างต่อเนื่อง
- โค้ดอยู่ในรูปแบบ monorepo ที่แบ่งออกเป็นหลายโมดูล และมีการ deploy วันละหลายครั้งด้วยแนวทาง trunk-based development
- แม้จะมีกรณีที่ใช้งาน GitHub Actions ได้ดี แต่ในบางขนาดทีมหรือสภาพแวดล้อม ข้อจำกัดก็แสดงออกมาอย่างชัดเจน
Pull request และเช็กรายการที่บังคับ
- monorepo ถูกแยกเป็นหลายโฟลเดอร์ และแต่ละโฟลเดอร์มีการทดสอบ สร้าง และ deploy อย่างอิสระ
- ใช้ความสามารถ
paths ของ GitHub Actions เพื่อ trigger pipeline เฉพาะเมื่อมีการเปลี่ยนแปลงในโฟลเดอร์นั้น
- การบังคับให้ทุกเช็กต้องผ่านก่อน merge pull request เป็นหลักการที่ดี แต่เมื่อรวมกับโครงสร้าง monorepo แล้วจะเกิดปัญหา
- ตัวอย่าง: ตั้งเช็ก
web-app1 - Unit tests ให้เป็น “บังคับ” แต่ถ้าไม่มีการเปลี่ยนแปลงในโฟลเดอร์ web-app1 เช็กนั้นจะไม่ถูกรัน
- ผลคือ แม้จะมีการเปลี่ยนแปลงเพียงโฟลเดอร์เดียว การทดสอบของโฟลเดอร์อื่นจะไม่ถูกรัน ทำให้ไม่สามารถ merge ได้เลย
- ถ้า GitHub จัดการโดยอิงไม่ใช่ชื่อของเช็กที่บังคับ แต่เป็นแนวทางแบบ “ถ้าเช็กทั้งหมดที่ถูก trigger ในตอนนี้ผ่าน ก็ merge ได้” ก็น่าจะแก้ปัญหาได้ แต่ก็น่าเสียดายที่ผ่านไป 3 ปีก็ยังไม่มีการเปลี่ยนแปลง
- ในเธรด GitHub issue ที่เกี่ยวข้อง 1, 2 ก็เห็นได้ว่าปัญหานี้ส่งผลกระทบมาก
- สุดท้ายแล้วเพื่อเลี่ยงปัญหานี้ จึงต้องเพิ่ม pipeline เสริมหรือดูแลรักษา workaround ที่ทั้งซับซ้อนและมีต้นทุนสูง
การนำกลับมาใช้ซ้ำและ YAML
- ยิ่ง pipeline มีขนาดใหญ่ขึ้น ก็ยิ่งรู้สึกว่าจัดการด้วย GitHub Actions ได้ยากขึ้นเรื่อย ๆ
- ต้องมี
if จำนวนมาก และแม้จะแยก workflow ออกไป ก็ยิ่งมีไฟล์ให้ดูแลมากขึ้นจนความสามารถในการบำรุงรักษาลดลง
- แม้ส่วนที่เรียกใช้ซ้ำควรจะจบในบรรทัดเดียว แต่กลับต้องใช้หลายบรรทัดและมีการตั้งค่าซ้ำ ทำให้ในโฟลเดอร์
.github มีไฟล์สะสมแล้วมากกว่า 30 ไฟล์
- ส่วน
needs ก็มีปัญหาว่า หากตอน refactor ไม่ได้สะท้อน job ที่ถูกลบออก ก็จะใช้เวลาพอสมควรกว่าจะพบ error
- GitHub Actions ไม่สามารถรันบนเครื่องโลคัลได้ ทำให้การพัฒนาและทดสอบทำได้ยาก
- แม้จะมีเครื่องมืออย่าง
act แต่ในทางปฏิบัติมักมีข้อจำกัดมากและไม่เป็นไปตามความคาดหวัง
ความไม่ใส่ใจของ GitHub
- ปัญหาที่ใหญ่ที่สุดในบรรดาประเด็นข้างต้นคือ GitHub ดูเหมือนจะไม่ได้มองว่า issue เหล่านี้สำคัญนัก
- หลาย issue เปิดค้างมาหลายปี และไม่ได้รวมอยู่ใน public roadmap จึงดูเหมือนไม่มีความตั้งใจจะปรับปรุง
- ช่วงหลังยังมีแรงต้านจากชุมชน เมื่อ issue จำนวนมากที่ถูกพูดถึงมายาวนานถูกปิดลงพร้อมกัน
ตัวเลือก
- เมื่อพิจารณาปัญหาเหล่านี้และการที่ GitHub ดูไม่ค่อยมีความตั้งใจจะแก้ไข ก็จำเป็นต้องคิดให้รอบคอบก่อนนำ GitHub Actions มาใช้
- ในตลาดยังมีตัวเลือก CI/CD อื่น ๆ อีกมาก เช่น GitLab, Jenkins, TeamCity
- เครื่องมืออย่าง Dagger ที่เสนอแนวทางใหม่ก็น่าลองนำมาพิจารณาเช่นกัน
6 ความคิดเห็น
CI/CD นั้น gitlab เจ๋งสุด
ผมเองก็จำได้ว่าตอนใช้ GitLab อยู่แล้วต้องมาอยู่ในสภาพแวดล้อมของ GitHub Actions ก็รู้สึกเหมือนไม่มีอะไรที่ใช้ได้เลย ...
อย่างหนึ่งที่ผมไม่พอใจมากเหมือนกันคือ GitHub ไม่สามารถจัดการคลังเก็บให้รวมเป็นกลุ่มตามประเภทได้
ผมคิดว่า GitLab ทำเรื่องไปป์ไลน์ได้ดีมากจริง ๆ นะครับ สิ่งที่พูดถึงข้างบน GitLab ทำได้ทั้งหมดเลย
ถ้าเป็นกรณี monorepo ก็สะดวกในการตั้งค่าว่าเมื่อโฟลเดอร์ไหนมีการเปลี่ยนแปลง ต้องให้รันอะไรบ้าง
เรื่องนี้ต้องรู้ประวัติของ GitHub Actions ก่อนนิดหน่อย...
GitHub Actions รุ่นแรกสุดมีลักษณะที่ต่างจากตอนนี้อยู่พอสมควร...
ก่อนจะเปิดให้ใช้งาน 6 เดือน (จำไม่ค่อยได้แล้ว) GitHub ถูก Microsoft เข้าซื้อกิจการ และดูเหมือนว่าการพัฒนา Actions จะทำร่วมกับทีม Azure DevOps ของ Microsoft
ช่วงนั้น Azure DevOps ไม่มีฟีเจอร์ใหม่ออกมาอีกต่อไป และฟีเจอร์ที่เคยอยู่ใน Azure DevOps ก็เริ่มมีฟีเจอร์ใหม่ออกมาใน GitHub Actions แทน...
ตอนนั้นเปลี่ยนมาใช้ YAML และสภาพแวดล้อมแบบทุกวันนี้ก็ถูกสร้างขึ้นมาในช่วงนั้นเอง.... T_T
หลังจากนั้นดูเหมือนว่านักพัฒนาจะย้ายกลับไปทำงานในส่วนเดิม และอยู่ในสภาพที่ไม่ได้แตะต้องมันต่อแล้ว...
น่าเสียดายนะครับ...
ตอนนี้ที่บริษัทก็วาง CI/CD ไว้บนพื้นฐานของ GitHub Actions... ตอนนี้ยังไม่มีจุดที่ขาดอะไรเลยก็เลยยังใช้อยู่...
คงต้องคอยจับตาดูต่อไปครับ...
ความคิดเห็นบน Hacker News
ไม่ควรใส่ลอจิกจริงไว้ใน pipeline DSL และควรใช้มันแค่สำหรับการประสานงานของงานเท่านั้น งานที่ซับซ้อนควรถูกทำเป็นสคริปต์เพื่อให้รันได้อย่างง่ายดาย วิธีนี้ทำให้สามารถทำงานเดียวกันได้ง่ายใน GitHub Actions, Jenkins, Azure DevOps และระบบอื่น ๆ
เมื่อตั้งค่า GitHub Actions ควรหลีกเลี่ยงแอ็กชันที่สร้างไว้ล่วงหน้า และใช้มันเป็นเพียงตัวรันเชลล์แบบง่ายจะดีกว่า หากเขียนสคริปต์ด้วย Python, Ruby, Bash ฯลฯ แล้วให้ GitHub Action รันสคริปต์เหล่านั้น ก็จะทดสอบบนเครื่องโลคัลได้ง่ายขึ้นและลดความปวดหัวที่ไม่จำเป็น
GitHub Actions สามารถรันการตรวจสอบได้เฉพาะเมื่อเงื่อนไขบางอย่างเป็นจริงเท่านั้น แต่เมื่อใช้กฎเหล่านี้จะเจอกับปัญหา "Pull request กับ required checks" เมื่อใช้ร่วมกับบริการภายนอก required checks ต้องผ่านทั้งหมดเสมอ ไม่เช่นนั้นจะไม่สามารถ merge ได้
วิธีหนึ่งในการแก้ปัญหา 'Pull request กับ required checks' คือสร้างเวอร์ชัน 'no op' ของแต่ละ required check workflow เพื่อให้มันถูกรันเมื่อเงื่อนไขไม่เป็นไปตามที่กำหนด และจบการทำงานด้วยโค้ด 0 วิธีนี้ใช้ความสามารถพื้นฐานที่มีอยู่ แต่เป็นทางแก้ที่ค่อนข้างซับซ้อน
Travis CI เคยยอดเยี่ยมมากสำหรับการทดสอบ CI บนเครื่องโลคัล GitHub Actions ถูกสร้างขึ้นมาเพื่อแข่งขันกับ GitLab CI และในเวลานั้นกำลังสูญเสียส่วนแบ่งในตลาดองค์กร
ขอแนะนำให้ลองใช้ Buildkite หากต้องการก้าวข้าม GitHub Actions แล้ว Buildkite อาจเป็นทางเลือกที่ดี เคยมีประสบการณ์ใช้งานมันในบริษัทเทคขนาดใหญ่ของสหรัฐฯ และมันเป็นส่วนเดียวของ CI ที่รู้สึกใช้งานได้อย่างราบรื่น
สถาปัตยกรรมของ GitHub Actions อาจทำให้ตัดสินใจด้านความปลอดภัยผิดพลาดได้ ตัวอย่างเช่น secret ระดับองค์กรหรือระดับ repository นั้นสะดวกก็จริง แต่ก็อาจกลายเป็นช่องโหว่ด้านความปลอดภัยได้ ส่วน repository environment สามารถมี secret แยกต่างหากได้ แต่ต้องทำให้แน่ใจว่าเฉพาะ workflow ที่ถูกต้องเท่านั้นที่เข้าถึง environment ที่ถูกต้องได้
ปรัชญาทั่วไปของระบบ CI นั้นผิดตั้งแต่ต้น แทนที่ CI จะเป็นฝ่ายรันโค้ด ควรเป็นโค้ดที่รัน CI มากกว่า CI ควรมี API เพื่อให้ผู้ใช้สามารถส่งข้อมูลให้ระบบได้
สามารถใช้ Bazel เพื่อให้เครื่องมือ CI build Bazel target และเพิ่มความขนานได้ผ่าน remote build execution เมื่อต้องการ วิธีนี้เหมาะกับโค้ดระดับประมาณ 10M+ บรรทัดหรือบริการขนาดใหญ่
ใน GitHub สามารถกำหนด "required checks" ได้ ซึ่งต้องเป็นสีเขียวเสมอ แต่ถ้ามันถูกตั้งให้รันเฉพาะเมื่อมีการเปลี่ยนแปลงในโฟลเดอร์บางแห่ง ก็จะเกิดปัญหาว่าหากมีการเปลี่ยนแปลงในโฟลเดอร์อื่นจะไม่สามารถ merge ได้ หากไม่รันการทดสอบทั้งหมดก็จะไม่มีความหมายของการรวมระบบ ดังนั้นควรทำให้การทดสอบรันได้รวดเร็ว