2 คะแนน โดย GN⁺ 2023-09-24 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • GitHub Actions มีประโยชน์ทั้งด้านประสิทธิภาพการทำงานและฟีเจอร์ แต่ในการเขียน workflow จริง ความล่าช้าในการดีบัก, ความผิดพลาดด้านความปลอดภัย, การไม่มี type และการขาดแคลน action ทางการ ล้วนทำให้เสียเวลาซ้ำแล้วซ้ำอีก
  • แม้จะแก้เล็กน้อยก็ต้องทำ git add; git commit; git push และตรวจ log ในเบราว์เซอร์ซ้ำไปมา มีกรณีที่แม้แต่ workflow สำหรับ release แบบง่ายๆ ก็ต้องใช้ commit 4 ครั้งและ release ที่ล้มเหลว 4 ครั้ง
  • จุดอย่างการขยาย ${{... }}, pull_request_target, สิทธิ์เริ่มต้นที่กว้างของ GITHUB_TOKEN และการอ้างอิง SHA ของ fork ล้วนเป็นจุดด้านความปลอดภัยที่พลาดได้ง่าย โดยเฉพาะ fork SHA ที่อาจดูเหมือน commit ของ repository ที่ตั้งใจใช้งาน
  • input ของ action ไม่มีการตรวจสอบ type: และขอบเขตการรองรับก็แตกต่างจาก workflow_call·workflow_dispatch ทำให้แทนที่จะใช้อินพุตแบบ array หรือ object ได้ ต้องจัดการเองด้วย สตริงแบบ CSV หรือ input ที่ถูกทำให้แบน
  • การตรวจสอบตอน push, runtime security check, การลดสิทธิ์ token เริ่มต้นของ repository ส่วนตัว, type checking ที่เข้มงวดขึ้น และ action ทางการ·กึ่งทางการที่มากขึ้น จะช่วยเพิ่มความน่าเชื่อถือของ workflow ได้

GitHub Actions มีประโยชน์ แต่ก็คอยสะดุดซ้ำๆ

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

การดีบักหนักเกินไป แม้เป็นข้อผิดพลาดเล็กๆ

  • มีกรณีที่ระหว่างตั้งค่า workflow สำหรับ release ต้องใช้ commit 4 ครั้ง และ release ที่ล้มเหลว 4 ครั้ง เพื่อจับข้อผิดพลาดเล็กๆ
    • ไม่ได้ใช้ ${{ ... }} ในจุดที่จำเป็น
    • ลืมความสัมพันธ์ needs:
  • วงจรการดีบักปัจจุบันมีหลายขั้นตอนเกินไป แม้เพียงตรวจสอบความผิดพลาดง่ายๆ หนึ่งอย่าง
    • ต้องสลับจากสภาพแวดล้อมพัฒนาไปยังเบราว์เซอร์
    • ต้องหาแท็บที่ถูกต้อง
    • ต้องคลิกเข้าไปในหน้า summary และ status ของ Actions
    • ต้อง refresh log console ที่ถูก buffer ไว้เพื่อหาข้อผิดพลาดถัดไป
  • แม้เป็นการเปลี่ยนแปลงเล็กๆ ทั้งกระบวนการก็อาจใช้เวลา มากกว่า 30 วินาที
  • แนวทางปรับปรุง

    • ควรมี interactive debugging shell หรืออย่างน้อยควรสามารถ rerun workflow จากการเปลี่ยนแปลงเล็กๆ ได้โดยไม่ต้อง git add; git commit; git push
    • ควรมีการตั้งค่า repository ให้ปฏิเสธ workflow ที่ผิดชัดเจนได้ตั้งแต่ตอน push
      • syntax ที่ไม่มีทางทำงานได้
      • การอ้างอิง job หรือ step ที่ไม่มีอยู่จริง
      • กรณีที่ workflow ไม่ทำงานเงียบๆ เพราะ YAML ผิด

ความผิดพลาดด้านความปลอดภัยเกิดขึ้นง่ายเกินไป

  • ใน GitHub Actions workflow ที่ผู้ใช้เขียนอาจเปราะบางโดยไม่ตั้งใจได้ง่าย
  • เมื่อใช้การขยาย ${{ ... }} ใน shell หรือบริบทการรันอื่น หากค่าที่ขยายมาจาก input ที่ผู้ใช้ควบคุมได้ อาจนำไปสู่การ inject โค้ดอันตราย
    • ในตัวอย่าง มีการ inject โค้ดผ่าน inputs.frob และอาจทำให้ $MY_IMPORTANT_SECRET รั่วไหล
  • pull_request_target ใช้อย่างปลอดภัยได้ยากมากใน workflow ที่ไม่ใช่เรื่องเล็กน้อย
    • use case ที่ตั้งใจไว้ดูเหมือนเป็นขอบเขตแคบๆ เช่น การติด label หรือเขียน comment ให้ PR ที่มาจาก fork
    • แต่ในทางปฏิบัติกลับถูกเปิดให้เป็น foot-gun ขนาดใหญ่
  • สิทธิ์ระดับ workflow และ job ก็ถูกตั้งไว้กว้างเกินไปได้ง่าย
    • สิทธิ์เข้าถึงเริ่มต้นของ GITHUB_TOKEN ปกติกว้างมาก
    • ใน repository ของบัญชีส่วนตัว มักลืมลดสิทธิ์ token เริ่มต้น
    • เพราะไม่รู้แน่ชัดว่าต้องใช้สิทธิ์ขอบเขตไหน จึงมักให้สิทธิ์ token มากเกินไป
  • โมเดลสิทธิ์ของ GitHub ยัดทุกอย่างลงในแกนเดียวคือ read/write/none จึงยิ่งทำให้สับสน
    • id-token: write ทำให้อ่าน OpenID Connect token ของ workflow ได้
    • การทำงาน GET บางอย่างของ security advisory ต้องใช้สิทธิ์ write ส่วนบางอย่างใช้แค่ read

Action ที่ปัก SHA อาจสับสนกับ commit ของ fork ได้

  • reference ที่ดูเหมือน actions/checkout@c7d749a2d57b4b375d1ebcd17cfbfb60c676f18e อาจไม่ใช่ commit ของ repository actions/checkout จริงๆ
  • SHA ดังกล่าวเป็น commit ที่อยู่ใน fork ภายใน network ของ actions/checkout และเพราะ GitHub ใช้ alternates จึงอาจดูเหมือนอยู่ใน repository หลัก
  • บทความที่เกี่ยวข้องของ Chainguard แบ่งปัญหาออกเป็นสามข้อ
    • การอ้างอิง SHA ของ fork กับ SHA ของ repository เป้าหมายแยกแยะด้วยตาไม่ออก
    • GitHub REST API /repos/{user}/{repo}/commits/{ref} จะคืน JSON response ที่อ้างอิงแค่ {user}/{repo} แม้ {ref} จะมีอยู่เฉพาะใน fork
    • หากแยก SHA ของ fork กับ non-fork ไม่ได้ อาจเลี่ยงข้อจำกัดด้านแหล่งที่เชื่อถือของ GitHub Actions ได้
  • การตอบสนองของ GitHub จนถึงตอนนี้อยู่ในระดับเพิ่ม ข้อความเพิ่มเติม ลงในเอกสารเท่านั้น
  • แนวทางปรับปรุง

    • ต้องมีโหมด paranoid workflow security ที่ปฏิเสธ workflow ที่เห็นชัดว่าไม่ปลอดภัยตั้งแต่ตอน push
    • เช่นเดียวกับ runtime instrumentation แบบ AddressSanitizer ควรทำให้ pattern ที่เสี่ยงด้านความปลอดภัยล้มเหลวระหว่างรัน workflow ได้
      • ตัวอย่าง: ใน pull_request_target หากใช้ actions/checkout กับ ref ที่ไม่ใช่ repository เป้าหมาย ให้ fail
    • อาจพิจารณาเลิกใช้หรือถอด pull_request_target ออก
    • แม้ใน repository ส่วนตัว ก็ควรตั้งขอบเขต GITHUB_TOKEN เริ่มต้นให้จำกัดมากขึ้นได้เหมือน organization·enterprise
    • action ที่ pin ด้วย SHA ซึ่ง SHA นั้นไม่มีใน repository ที่อ้างถึงและมีอยู่เฉพาะใน fork ควรถูกปฏิเสธโดยค่าเริ่มต้น

Type system ขาดความสม่ำเสมอและพลังในการแสดงข้อมูล

  • GitHub Action แบบ custom สามารถกำหนด input ใต้ inputs: ได้ แต่ input ของ action ไม่มี การบังคับ type
  • declaration อย่าง type: number ใช้ไม่ได้กับ input ของ action
  • ภายใน GitHub Actions เอง ตำแหน่งที่รองรับ type ก็ไม่สม่ำเสมอ
    • workflow_call: รองรับ boolean, number, string
    • workflow_dispatch: รองรับ boolean, choice, number, string
    • action inputs: ไม่รองรับ type
  • แม้ input ที่รองรับ type ก็ไม่รองรับโครงสร้างข้อมูลซับซ้อนอย่าง array หรือ object
    • ใช้ input แบบ array เช่น paths: [foo, bar, baz] ไม่ได้
    • ใช้ input แบบ object ที่มีโครงสร้างลำดับชั้นใต้ headers: ไม่ได้
  • ผู้เขียน action จึงต้องขอ input ในรูปแบบเฉพาะกิจแทน
    • ต้อง implement การ parse แบบ CSV เอง เช่น paths: foo,bar,baz
    • ทำให้โครงสร้างลำดับชั้นที่เป็นธรรมชาติแบนลง เช่น header-foo, header-baz
  • วิธีแบบนี้ไม่ดีทั้งต่อการบำรุงรักษาและความปลอดภัย
    • ต้องจัดการ namespace ของ input แบบแบนเดียวเอง
    • ต้องสร้างภาษาที่ไม่ได้ระบุสเปกอย่างเป็นทางการขึ้นมาเพื่อ input ที่ซับซ้อน
  • แนวทางปรับปรุง

    • ผู้เขียน action และ workflow ควรใช้ type: ได้ทุกที่
    • choice ก็ไม่ควรถูกจำกัดไว้เฉพาะ workflow_dispatch แต่ควรใช้ได้ทุกที่
    • ในกรณีที่อนุมาน type แบบ static ได้ ควรปฏิเสธการเปลี่ยนแปลง workflow ที่ใช้ type ผิดตั้งแต่ตอน push
    • ต้องมี type: object และ type: array
    • แม้อาจไม่สมบูรณ์แบบเพราะ type ภายในอาจหลากหลาย แต่ก็ยังดีกว่าปัจจุบัน
    • หากจำเป็น ก็ส่งผ่านเป็นสตริงที่ serialize เป็น JSON ได้
    • GitHub Actions มีฟังก์ชัน fromJSON(...) อยู่แล้ว

Action ทางการเชื่อมโยงโดยตรงกับความเชื่อมั่นต่อแพลตฟอร์ม

  • ecosystem ของ third-party ใน GitHub Actions มี action คุณภาพสูงจำนวนมาก
  • ใต้ ecosystem นั้นมี action ทางการที่ GitHub ดูแลอยู่
    • งาน git หลัก: actions/checkout
    • งาน GitHub และการจัดการ repository: actions/{upload,download}-artifact, actions/cache, actions/stale
    • การตั้งค่าที่จำเป็น: actions/setup-python, actions/setup-node
  • Action เหล่านี้มีความทั่วไปและความสำคัญสูง จึงมีคุณค่ามากหากมี implementation ที่ดูแลอย่างเป็นทางการ
  • แต่จำนวน action ทางการมีน้อย และบางงานที่เชื่อมต่อฟีเจอร์ของ GitHub โดยตรงก็ไม่ได้ถูก提供เป็น action ทางการ
    • ตัวอย่าง: action ที่เพิ่ม pull request เข้า merge queue แบบ programmatic
    • GitHub CLI มี gh pr merge แต่ไม่ได้ expose เป็น action
  • ตัวอย่าง action ทางการที่หยุดดูแล

    • actions/create-release: หยุดดูแลตั้งแต่มีนาคม 2021
    • ผู้ใช้ถูกแนะนำให้ย้ายไปใช้ workflow ที่ดูแลโดย community
    • ตัวอย่างที่ถูกกล่าวถึงคือ softprops/action-gh-release
    • actions/upload-release-asset: ถูกระบุว่าหยุดดูแลในช่วงเดียวกับ actions/create-release
    • actions/setup-ruby: หยุดดูแลตั้งแต่กุมภาพันธ์ 2021
    • ผู้ใช้ถูกแนะนำให้ย้ายไป ruby/setup-ruby
    • การย้ายเองค่อนข้างเจ็บปวดน้อย แต่ภาพว่าคอมโพเนนต์หลักอาจถูกทิ้งได้ส่งผลเสียต่อความเชื่อมั่นในแพลตฟอร์ม
    • หาก action ทางการคุณภาพสูงมีไม่พอ ผู้ใช้จะต้องจัดการพื้นผิวของ GitHub API เอง และยังคงสร้างความผิดพลาดด้านความปลอดภัยต่อไป
  • แนวทางปรับปรุง ecosystem

    • งานที่เชื่อมส่วนต่างๆ ของ infrastructure GitHub เข้าด้วยกันโดยตรง และปัจจุบันต้องทำเองผ่าน REST API call หรือรัน gh ควรถูกนำเสนอเป็น action ทางการ
    • อาจร่วมมือกับ third-party action ขนาดใหญ่เพื่อสร้าง องค์กรกึ่งทางการ อย่าง community-actions
      • action ที่ผ่านการ review จาก GitHub
      • ปฏิบัติตาม best practices ด้านความปลอดภัยของ repository
      • อัปเดตตาม semantic version
      • เส้นทางความเชื่อมั่นที่ชัดเจนสำหรับ action สำคัญใน ecosystem

เครื่องมือที่มีอยู่และ roadmap ของ GitHub

  • หลายคนแนะนำ nektos/act ซึ่งเป็นเครื่องมือจำลอง GitHub Actions แบบ local
    • มีประโยชน์ในการ iterate และดีบัก workflow ง่ายๆ อย่างรวดเร็ว
    • แต่บางกรณี image และ event ไม่เหมือนกับสภาพแวดล้อมจริงของ GitHub อย่างสมบูรณ์ จึงถูกมองว่าเป็นเครื่องมือที่มี loss
  • rhysd/actionlint ใช้สำหรับ local linting และ security linting
    • ข้อจำกัดคือ lint ได้เฉพาะ workflows แต่ lint actions ไม่ได้
  • GitHub Actions extension for VS Code ให้การ lint ใน editor และการผสาน repository workflow
    • อ้างอิงจาก public JSON schema
    • แสดง workflow ที่กำลังรัน, เติมตัวแปรให้อัตโนมัติ และอื่นๆ
    • แต่ยังมีปัญหาที่ตรวจไม่พบ เช่น พิมพ์ชื่อ secrets ผิด หรือพิมพ์ชื่อ output ที่สร้างแบบ dynamic ผิด ทำให้การดีบักแบบ add-commit-push ยังจำเป็นอยู่
  • Julian Dunn ผู้รับผิดชอบการจัดการโปรเจกต์ GitHub Actions แชร์ฟีเจอร์และลำดับความสำคัญบางส่วนที่กำลังดำเนินอยู่
    • interactive debugging อยู่ใน public roadmap ของ GitHub Actions
    • งานย้ายจาก workflow pinning แบบ tag·SHA ไปสู่วิธีที่เป็น immutable มากขึ้น ก็อยู่ใน public roadmap
    • GitHub มองว่าสุขภาพและคุณภาพของ ecosystem action ทางการเป็นลำดับความสำคัญ และใช้กลยุทธ์คงจำนวน action ทางการไว้ไม่มาก เพื่อให้สามารถดูแลและให้ความสนใจกับแต่ละ action ได้เพียงพอ

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

 
GN⁺ 2023-09-24
ความคิดเห็นจาก Hacker News
  • เวิร์กโฟลว์ของ GitHub Actions มีอยู่สองแนวทาง 1) “เขียนโปรแกรม” ด้วย GitHub Actions โดยเรื่องอย่างการส่งอีเมลก็เอาเครื่องมือจาก marketplace มาต่อเพิ่ม ทำให้ YAML โตเป็น 500–1000 บรรทัด เต็มไปด้วยเงื่อนไขจนเข้าใจยาก
    2) ใช้ GitHub Actions แค่เป็น “การตั้งค่า” แล้วถามตัวเองอยู่เสมอว่า “ผลักความซับซ้อนของ YAML นี้ไปไว้ในสคริปต์ได้ไหม?” ถ้าใส่การส่งอีเมลไว้ในสคริปต์ เวิร์กโฟลว์ก็จบที่ราว 50–60 บรรทัด และสามารถดีบักสคริปต์ในเครื่องได้ ทำให้วงจร push-debug-commit แบบโง่ ๆ แทบหายไป ทุกครั้งที่ไปทีมใหม่ ผมจะบอกว่าแบบที่ 1 คือเส้นทางสู่ความบ้าคลั่ง ส่วนแบบที่ 2 คือแนวทางที่สมเหตุสมผล แต่ราวครึ่งหนึ่งก็ยังเลือกแบบที่ 1 อยู่ดี ถ้าเลือกแบบที่ 2 ปัญหาเรื่อง เครื่องมือดีบักไม่เพียงพอ และ vendor lock-in ก็จะเป็นปัญหาน้อยลงมาก

    • เห็นด้วยอย่างมากกับมุมมองนี้ ถ้าไม่พยายามเขียนโปรแกรม GitHub Actions ด้วย YAML แต่ปฏิบัติกับมันแค่ในฐานะ ตัวรันงาน ความเจ็บปวดจำนวนมากจะหายไป
      แต่หลายครั้ง การผลักทุกอย่างเข้าไปไว้ในภาษาโปรแกรมที่เหมาะสมก็ยังไม่พอ อาจต้องใช้ฟีเจอร์เฉพาะ vendor ของ GHA, แสดง dependency ระหว่างงาน หรือเรียก REST API ที่ถูก abstract ไว้อย่างดีแล้วในรูปของ action อยู่แล้ว แม้จะนำไปเขียนใหม่ด้วยภาษาที่ต้องการได้ แต่ vendor dependency ก็ไม่ได้หายไป และยังเปราะบางอยู่ดี สุดท้าย value proposition เรื่อง vendor lock-in ของ GHA นั้นแข็งแรงมาก ดังนั้นหากจะโน้มน้าวคนให้เลือกข้อ 2 จำเป็นต้องมีข้อดีที่แรงกว่านี้
    • แนวทางข้อ 2 ยังทำให้นักพัฒนารัน build บนเครื่อง local ได้ง่ายขึ้นด้วย ใช้ build chain เดียวกันได้ทั้งตอนดีบักในเครื่องและในสภาพแวดล้อม test/staging/production โดยไม่ต้องดูแลขั้นตอน build ที่แตกต่างกันหลายชุด
      เรื่องนี้ไม่ได้ใช้ได้เฉพาะกับ GHA แต่กับ build server ทุกตัว Build server ควรเป็น ตัวรันสคริปต์ ที่เพิ่มประวัติ การจัดการ artifact และสิทธิ์/การ audit เข้าไป ส่วนกระบวนการ build จริงควรมอบหมายให้ repository ที่เป็นเป้าหมายของการ build
    • เป็นมุมมองที่ดี อย่างไรก็ตาม ถ้าจะทำ automation กับ GitHub เอง เช่น งานอย่างการกำหนด role หรือการติด tag แบบที่ 1 ก็หลีกเลี่ยงได้ยาก ถึงอย่างนั้น ตอนนี้ผมยังอยากจัดการหลายอย่างด้วยมือมากกว่าต้องเจอกับ debug loop อันเลวร้ายของ GHA
      อนึ่ง มี nektos/act ที่พยายามจำลองการทำงานของ GHA ในเครื่อง: https://github.com/nektos/act
    • สงสัยว่า debug action กันอย่างไร การเสียเวลาอยู่กับลูป commit-action-debug-change นานขนาดนั้นเป็นเรื่องไร้เหตุผลมาก เห็นด้วยเต็มที่ว่าแนวทางข้อ 2 ทำให้การดีบักสคริปต์ง่ายขึ้นมาก CI ควรรันในเครื่อง local ได้ แต่ GitHub Actions แม้จะมีเครื่องมืออยู่บ้าง ก็ไม่ได้ใช้งานแบบนั้นได้ง่ายนัก
    • เหตุผลหลักที่มุ่งไปทางข้อ 2 คืออยากให้แม้ GitHub ล่มก็ยังรัน build ในเครื่องได้ และถ้าจำเป็นก็ย้ายไปที่อื่นได้ง่าย
      ควรเขียน build/test/sign/deploy ฯลฯ เป็นสคริปต์ให้ portable มากที่สุดเท่าที่ทำได้ และสคริปต์เหล่านี้ต้องทำงานบนเครื่อง local ได้เสมอ มอง GitHub เป็นเพียงตัวที่เตรียมสภาพแวดล้อมสำหรับรันสคริปต์นั้นโดยอัตโนมัติและสั่งรันจริงเท่านั้น
  • ลูป git commit, push, wait เป็นประสบการณ์ผู้ใช้ที่แย่มาก ผู้ใช้ควรได้ใช้ pipeline ที่ portable ซึ่งรันได้ทุกที่ รวมถึงบนเครื่อง local ด้วย Act ช่วยแก้ปัญหานี้ได้ระดับหนึ่ง แต่โดยทั่วไปก็ไม่ได้แทนสภาพแวดล้อมจริงได้ตรงทั้งหมด
    มี pipeline จำนวนมากที่รันในเครื่องเหมือน production ไม่ได้ แต่ในขั้นตอนพัฒนาที่สำคัญน้อยกว่า ก็ไม่มีเหตุผลที่จะไม่ capture เวิร์กโฟลว์เหล่านี้แล้วรันในเครื่อง Garden ให้ pipeline แบบ portable และเพิ่ม caching ครอบคลุม dependency graph ทั้งหมด ลูกค้าบางรายลดเวลารันได้มากกว่า 80% และนักพัฒนาเห็นผลว่า test ผ่าน/ไม่ผ่านได้ทันทีโดยไม่ต้อง push เข้า git ก่อน เป็นโอเพนซอร์ส: https://github.com/nektos/act, https://docs.garden.io

    • ถ้าผู้คนไม่ได้ยัด bash script เข้าไปใน action แต่ให้ action เรียก make หรือ bash script เฉย ๆ ปัญหาแบบนี้ก็คงไม่เกิด CI/CD และนักพัฒนาควรใช้ target/command เดียวกัน เช่น make release
    • ดูเหมือนว่าเราสูญเสียหลักการที่ว่า “CI ไม่ควรพิเศษเหมือนเกล็ดหิมะที่ไม่ซ้ำใคร” ไปมาก หลังจากเริ่มสร้างทีมเฉพาะทางด้าน DevOps และเครื่องมือ DevOps พออะไรบางอย่างกลายเป็นอาชีพ ก็รู้สึกว่ามันถึงจุดเปลี่ยนที่ทำให้สิ่งนั้นซับซ้อนเกินจำเป็น เห็นปรากฏการณ์เดียวกันนี้กับ Agile ตัวพิมพ์ใหญ่ และ scrum master ที่ต้องหาอะไรมาเติมเวลาให้เต็ม
    • เคยหลงไปขุดผิดที่หลายครั้งเพราะความไม่สมบูรณ์ของ Act ตอนนี้กลับไปใช้ลูปเดิมก่อน และหวังว่ามันจะดีขึ้นเมื่อเวลาผ่านไป
    • build pipeline ก็ต้องการ อะไรสักอย่างแบบ Terraform เหมือนกัน ถ้าคุณใช้ Bitbucket อยู่ ก็ขอให้พระเจ้าช่วย
    • landing page ของ garden.io แสดงผลพังบน iOS มันล้นออกไปทางขวาของหน้าจอ
  • เห็นด้วยอย่างยิ่งกับความเจ็บปวดในการดีบักการรัน GH Actions เครื่องมือที่มีก็มีแค่เปิดดีบักแล้วรันใหม่เท่านั้น มี คอมมิตขยะ ที่ทำขึ้นมาเพื่อแก้หรือดีบัก pipeline เยอะเกินไป และส่วนใหญ่ก็เป็นแค่การลองโยนอะไรมั่ว ๆ เข้าไปเพื่อดูว่าจะเวิร์กไหม
    แม้แต่งานพื้นฐานมาก ๆ อย่าง logic ที่นำกลับมาใช้ซ้ำได้ ก็ยังซับซ้อนโดยไม่จำเป็นหรือมีเอกสารแย่ พอรู้แล้วมันก็ค่อนข้างง่าย แต่เอกสารของ GitHub แย่มาก ดูเหมือนว่าถ้าต้องการ reuse จะต้องทำ action ให้เป็นสาธารณะหรือเอาไปไว้ใน repository อื่น แต่จริง ๆ แล้วสามารถสร้างไฟล์ YAML ใหม่ที่มี logic สำหรับใช้ซ้ำได้ เพียงแต่ต้องวางไว้ที่ root ของโฟลเดอร์ workflows ถึงจะทำงาน GH Actions ใช้งานแล้วทรมานจริง ๆ แต่พอมันทำงานได้แล้วก็สะดวกมาก อยากให้มีอะไรอย่าง local runner สำหรับทดสอบ action ก่อน commit และ push

    • วิธีหนึ่งสำหรับกรณีนี้คือใช้ draft PR สามารถรันการเปลี่ยนแปลง YAML ของ action ใน draft PR ได้ และเมื่อพอใจแล้ว ใน PR สำหรับ merge จริงก็ค่อย squash commit ให้เหมาะสมเพื่อเอาเข้าไปโดยไม่รก ตอนดีบักหรือพัฒนา logic ของ GH Action นั้น draft PR ถือว่าใช้ได้ดีทีเดียว
    • ไม่ได้ทำได้ทุกอย่าง แต่มีเครื่องมือที่ค่อนข้างใช้ได้: https://github.com/nektos/act
    • เวลาแก้ CI ผมจะ push ขึ้น feature branch เสมอ แล้วพอเสร็จก็ squash merge แทบไม่มีการแก้เร็ว ๆ ที่จบในครั้งเดียว มักจะกลายเป็น 3–10 commit เสมอ
    • เคยลองรัน image ของ GitHub runner หรือ image ที่เลียนแบบมัน แต่การตั้งค่าและพฤติกรรมของบางฟีเจอร์เจ็บปวดเกินไป สองวันต่อมาก็ยอมแพ้
      ไม่ใช่ปัญหาของ GitHub เท่านั้น แพลตฟอร์ม CI รายใหญ่อื่น ๆ ก็ไม่ได้ดีกว่ากันเท่าไรในแง่ workflow และ integration ตอนนี้พยายามทำทุกอย่างให้เป็นสคริปต์ให้มากที่สุด
    • นี่คือเหตุผลหลักที่เราสร้าง Earthly ขึ้นมา เพื่อให้รัน build ในเครื่องได้ และได้ ความสอดคล้อง กับ CI
  • GitHub Actions เป็นระบบ CI/CD ที่แย่มาก ไม่สามารถรันขั้นตอนแบบขนานบน VM เดียวกันได้ และงานที่อิง container ก็ถูกปฏิบัติเหมือนพลเมืองชั้นสอง
    ปัญหาแรกทำให้ไม่สามารถ parallelize การตั้งค่า credentials ในเครื่องหรือ dependency ของ environment ได้ เห็น google-github-actions/setup-gcloud ใช้เวลาเกิน 1 นาทีแล้วหงุดหงิด ปัญหาที่สองทำให้การใช้ Dockerfile ใน repository เพื่อระบุการตั้งค่า environment ของ CI เป็นเรื่องยากมาก รวมถึงให้ CI rebuild image เมื่อเนื้อหา image เปลี่ยน แล้วให้ workflow ที่พึ่งพา image นั้นรอ และถ้าเนื้อหาไม่เปลี่ยนก็ไม่ต้อง rebuild แต่รันได้ทันทีพร้อม dependency ที่ติดตั้งไว้แล้ว ใน GitHub Actions สุดท้ายมักต้องพยายามเติม cache ใหม่ทุกครั้ง cache จำกัดที่ 5GB เพิ่มไม่ได้แม้จะจ่ายเงิน และถูกไล่ออกแบบ FIFO ดังนั้นถ้าเกิน 5GB ก็แทบเหมือนไม่มี cache คิดถึง Concourse มาก มันทำ parallel jobs, custom pipeline triggers, SSH เข้าไปใน CI environment เพื่อดีบัก, รันงานครั้งเดียวโดยไม่ต้องมี pipeline, ส่งต่อเนื้อหา directory ระหว่างงานโดยไม่ต้องสร้าง artifact ได้ GitHub Actions ใกล้เคียงกับ CI/CD ของเล่น ที่ดังเพราะเริ่มใช้ง่าย แค่วางไฟล์หนึ่งไว้ใน .github/workflows ก็ใช้ได้ เหมาะกับการดึงคนเข้ามาใช้ แต่เมื่อเกินฟีเจอร์ช่วงแรกไปแล้ว มันยังไม่ทรงพลังพอจะเรียกว่า “ดีที่สุด”

    • เพราะข้อจำกัด cache 5GB ตอนนี้น่าจะลองไปสืบปัญหา “build caching พังแบบแปลก ๆ” ได้แล้ว ขอบคุณที่บอก
    • Concourse ยอดเยี่ยมมาก ไม่รู้ว่าทีมถูกยุบไปแล้ว น่าเสียดายจริง ๆ วิธีสื่อสารของ Zito ก็สุดยอดเหมือนกัน
    • ผมมองว่าเป็น VMWare หลังการเข้าซื้อที่ยุบทีม มากกว่า Pivotal ภายในมีคนที่ชอบ Concourse เยอะมาก แต่ผมออกมาก่อนการเข้าซื้อ
      การดีบักผ่าน SSH กับงานแบบครั้งเดียวมันเหมือนฝันจริง ๆ
    • สงสัยว่าเคยดู Tekton หรือยัง: https://tekton.dev/
    • มีโซลูชันที่มีอยู่แล้วซึ่งพิจารณาปัญหาพวกนี้ไว้จำนวนมาก อยากฟังความเห็นหน่อย ถ้าแชร์อีเมลหรือเขียนมาที่ lawnchair@lawnchair.net ได้ก็จะดี
  • ไม่เข้าใจว่าทำไมยังไม่แก้เรื่องที่ GitHub แยกการอ้างอิง SHA จาก fork กับ non-fork ไม่ได้ จน fork สามารถหลบการตั้งค่าความปลอดภัยของ GitHub Actions ได้
    ถ้าการควบคุมความปลอดภัยถูกหลบได้ง่าย ๆ นั่นคือ ประเด็นความปลอดภัยร้ายแรง จริงอยู่ที่ต้องโน้มน้าวให้ใครบางคนใช้ SHA ของเรา แต่ social engineering โดยทั่วไปก็เป็นทางที่ง่ายอยู่แล้ว

  • พูดตรง ๆ คือมันแย่จนรู้สึกอายเลยด้วยซ้ำ แปลกด้วยที่ build ล้มเหลวแบบไม่เกี่ยวข้องจะส่งแจ้งเตือนไปหา maintainer ล่าสุดที่ merge เป็นคนสุดท้ายโดยบังเอิญเท่านั้น ถ้า maintainer คนใหม่ไม่บอกทาง Matrix ผมอาจไม่รู้เลยว่า update/build ของผมล้มเหลวมาหนึ่งสัปดาห์แล้ว
    cache action เห็นด้วยตาเปล่าก็ชัดว่าพัง แต่ดูเหมือนไม่มีคนดูแล ถ้า UI พังหรือแท็บถูก unload ก็ tail build log ของขั้นตอนไม่ได้ แทบไม่มี abstraction สำหรับทำให้ workflow portable ระหว่าง worker node image พื้นฐานก็เกือบเป็นหายนะ ตอนแรกแค่รำคาญว่ามันบวมเกินไป แต่ยิ่งขุดลงไปก็ยิ่งรู้สึกว่า “คนของ Microsoft ที่ไม่รู้จัก Linux เป็นคนรับผิดชอบแน่ ๆ” ไม่มีความพยายามจะให้ image ที่เบากว่าสำหรับคนที่ใช้ Nix หรือ Docker เลย กำลังย้ายออกจาก GitHub อยู่ และเหตุผลหลักคือ Actions ทำให้ตาสว่างขึ้นมา เหตุผลที่ไม่อยากเขียนโปรแกรมด้วย YAML คือมองว่า YAML เป็นความอัปยศที่เกิดจากเงิน VC ไหลเข้า ecosystem ที่ไม่รู้จักเทคโนโลยีสมัยใหม่และมีประโยชน์จริง

    • ตอน Microsoft ซื้อ GitHub ก็น่าจะเห็นชัดอยู่แล้วไม่ใช่หรือว่าจะเกิดเรื่องแบบนี้
  • ขอแนะนำ https://pre-commit.ci อย่างยิ่ง ผมไม่ได้เกี่ยวข้องกับบริการนี้ แค่เป็นผู้ใช้ที่พอใจเท่านั้น
    แนวคิดคือเขียน hook หรือใช้ hook ที่มีอยู่แล้วเพื่อตรวจโค้ดก่อน commit และแก้ไขถ้าทำได้ จากนั้นหลัง push แล้ว CI จะตรวจอีกครั้ง และถ้าจำเป็นก็จะทำ commit แก้ไขให้อัตโนมัติด้วย ระบบแคชอัตโนมัติดีมากจนเร็วอย่างไม่น่าเชื่อ และเพราะใช้ การตั้งค่าเดียวกัน ทั้งบนเครื่องพัฒนาใน local และบน CI จึงลดปัญหาในการดีบักไปได้มาก ใช้กับโอเพนซอร์สได้ฟรี มันไม่ได้ทำอย่าง release อัตโนมัติ แค่ตรวจสอบเท่านั้น แต่ก็ทำการตรวจสอบนั้นได้ดีมาก

    • สำหรับโปรเจกต์ Python ถ้าใช้ tox ร่วมด้วยจะดีเป็นพิเศษ tox จะสร้าง virtualenv ให้ตรงกับเวอร์ชัน Python ที่ต้องการทดสอบ แล้วรันการทดสอบภายในนั้น
      ถ้าต้องการตรวจซอร์สโค้ดเอง ก็สามารถรัน static check ได้ด้วย skip_install = True แค่รันในคอนเทนเนอร์ที่ติดตั้ง tox เป็นเครื่องมือ global และมี Python เวอร์ชันที่จำเป็นทั้งหมดอยู่แล้ว ตัวอย่างเช่นมี image อย่าง https://github.com/georgek/docker-python-multiversion แม้จะไม่ได้ดูแลต่อแล้ว แต่ก็อัปเดตได้ง่าย boilerplate ประมาณใส่ [tox] envlist = py{310,311}, [testenv], และใน [testenv:check] ใส่ pre-commit run --all-files --show-diff-on-failure ก็เพียงพอแล้ว
  • หลังจากเจอลูป git commit; git push; repeat มากเกินไป ผมก็พบ https://github.com/mxschmitt/action-tmate มันเปิด shell access ให้ระหว่างขั้นตอนต่าง ๆ จึงไม่ได้แก้ปัญหาทุกอย่าง แต่บางครั้งก็ช่วยลดความเจ็บปวดได้อย่างชัดเจน

  • โดยส่วนตัว อยากให้แนบ รายงาน HTML เข้ากับ action run ได้โดยไม่ต้องใช้ของอย่าง actions/upload-artifact ในตอนนี้
    โดยเฉพาะใน test build มักมีหลายครั้งที่อยากดูรายงาน HTML ที่ output ออกมาอย่างรวดเร็ว วิธีที่รู้ตอนนี้คือ upload-artifact หรือ GH Pages แต่ GH Pages ไม่ค่อยเหมาะเมื่อมี output รายงานหลายชุดใน repository เดียวกัน หรือเมื่ออยากดูรายงานเก่าอย่างรวดเร็วแทนที่จะเป็นรายงานล่าสุด คงจะดีถ้ามี action ง่าย ๆ อย่าง attach-report ที่แนบลิงก์รายงาน HTML ไว้ในสรุปงาน แล้วพอคลิกก็ render HTML ให้ ระบบ CI/CD อัตโนมัติอื่น ๆ รองรับการจับและดูรายงาน HTML เป็นพื้นฐานได้ครบถ้วนกว่านี้มาก

    • แม้จะไม่ใช่ HTML แต่สามารถเพิ่ม Markdown output ลงใน $GITHUB_STEP_SUMMARY ได้โดยตรง โดยไม่ต้องผ่านการอัปโหลด artifact หรือขั้นตอนทำนองนั้น
  • ผมมองว่า GH Actions แทบจะเป็นการ rebrand “Azure Pipelines” ของ Microsoft เสียมากกว่า จากมุมมองของคนที่เคยใช้ build และ release pipelines ของ TFS/VSTS/AzDO มาทุกรูปแบบก่อนหน้านี้ ทีมนี้ทำสิ่งนี้ได้ไม่ค่อยดี
    ที่ Azure Pipelines พอจะใช้งานได้ ก็เพราะวิธีทั้งหมดที่พยายามมาก่อนหน้านั้นล้มเหลวจริง ๆ เคยมีโปรเจกต์สำหรับรัน pipeline ใน local เพื่อให้ทำลูป edit-run-debug ในสภาพแวดล้อมส่วนตัวได้โดยไม่ต้อง commit แต่แน่นอนว่าถูกยกเลิกไป: https://github.com/microsoft/azure-pipelines-agent/pull/2687/files#diff-570b52bcb927a5365c22d17a21e8e19e1ba3427c7f3ec16ea64b7b3d14e4ee20 อย่างไรก็ดี ก็ยังมีเครื่องมือที่ช่วยเพิ่มคุณภาพชีวิตอยู่ เช่น VS Code extension ที่เข้าใจ syntax: https://marketplace.visualstudio.com/items?itemName=ms-azure-devops.azure-pipelines ถ้าพูดแบบชวนถกเถียงหน่อย หากใช้ XML แทน YAML แค่ประกาศ xmlns ที่ด้านบน ก็อาจได้การตรวจสอบความถูกต้องจาก code editor ดี ๆ ส่วนใหญ่โดยแทบไม่ต้องให้ผู้ใช้ทำอะไรเพิ่มเติม XML นั้นเลวร้ายก็จริง แต่ก็มีฟีเจอร์มีประโยชน์มากมายที่เราสูญเสียไปพร้อมกับการทิ้งมันทั้งหมด

    • ผมเข้าใจว่า GHA เป็นโปรเจกต์ที่ดำเนินไปค่อนข้างมากภายใน GitHub อย่างเป็นอิสระตั้งแต่ก่อน Microsoft เข้าซื้อกิจการ เลยสงสัยว่าหมายถึง GHA ถูกสร้างขึ้นใหม่บน AzP หรือแค่เอา AzP มาเปลี่ยนชื่อใหม่ หรือหมายถึงอย่างอื่น
    • มีความเป็นไปได้สูงกว่าที่คนส่วนใหญ่คิดมาก หลังการเข้าซื้อ สมาชิกจำนวนมากของ ทีม AzDo ย้ายไปทำงานกับ GitHub Actions/Projects
    • ผมเห็นด้วยจนถึงก่อนย่อหน้าสุดท้าย XML ทำให้ปวดตา ผมขอเลือกเอกสาร YAML ที่จัดรูปแบบสวยงาม แม้จะมีความเจ็บปวดอยู่บ้าง มากกว่าความสยองของวงเล็บมุมและ camelCase