8 điểm bởi GN⁺ 2026-02-07 | 3 bình luận | Chia sẻ qua WhatsApp
  • Được dùng rất rộng rãi vì là CI mặc định có sẵn trong repo, nhưng sự kém hiệu quả mang tính cấu trúc và trải nghiệm người dùng thiếu ổn định đang làm giảm năng suất của lập trình viên
  • Trình xem log tải chậm và gây sập trình duyệt, cùng với cú pháp YAML phức tạp và lỗi biểu thức dẫn đến việc debug lặp đi lặp lại
  • Do mô hình không sở hữu tài nguyên compute, công cụ này bộc lộ giới hạn về hiệu năng, khả năng mở rộng và mức độ kiểm soát môi trường
  • Trong nỗ lực lách qua nhiều vấn đề, các nhóm lại liên tục rơi vào cảnh tái tạo chính CI bằng YAML phức tạp hoặc các script Bash khổng lồ
  • Trái lại, Buildkite mang đến một lựa chọn CI bền vững hơn về lâu dài nhờ cấu trúc YAML đơn giản, agent có thể self-host và trải nghiệm log thực dụng

Vấn đề của GitHub Actions

  • Trình xem log của GitHub Actions rất kém hiệu quả: ngay cả việc kiểm tra một lỗi đơn giản cũng cần nhiều bước bấm và tải trang
    • Khi build thất bại, phải đi qua trang tóm tắt check → trang chạy workflow → trang job → bấm vào step đang bị thu gọn, tức là cần 3–4 lần chuyển trang, và mỗi lần đều có tải riêng
    • Liên tục làm sập trình duyệt với log build dung lượng lớn, và hiện tượng Chrome bị treo khi dùng tìm kiếm có thể tái hiện được
    • Với log dài, việc cuộn còn có lúc không hoạt động, cuối cùng dẫn tới tình huống phải tải artifact log thô về rồi mở bằng trình soạn thảo văn bản
    • Nút quay lại đưa người dùng đến một trang UI GitHub Actions khó đoán thay vì trang PR ban đầu, khiến lịch sử trình duyệt bị lấp đầy bằng các URL của Actions
  • Quy trình debug kém năng suất
    • Để kiểm tra biến môi trường, phải thêm step run: env rồi push lại, tạo ra vòng phản hồi 20 phút; với chỉ một thay đổi một dòng, quá trình này có thể lặp lại cả chục lần
    • Các vòng phản hồi 20 phút cứ lặp đi lặp lại, khiến một ngày làm việc bị tiêu tốn vào việc chờ CI
  • Giới hạn mang tính cấu trúc của YAML
    • YAML của GitHub Actions là một dạng đặc thù kết hợp ngôn ngữ biểu thức riêng, mô hình đối tượng context và quy tắc nội suy chuỗi
    • Chỉ cần dùng sai một dấu nháy trong biểu thức ${{ }}, bạn sẽ phải đợi tới 4 phút runner khởi động xong mới phát hiện chuỗi đã bị hỏng
    • Cú pháp biểu thức tồn tại trong một vùng lưng chừng (liminal space): quá phức tạp để viết dưới dạng cấu hình, nhưng lại quá hạn chế để xem như ngôn ngữ lập trình chính thức
    • Đây là kiểu hệ thống mà người dùng học cú pháp không phải qua tài liệu mà qua các lần thất bại
  • Rủi ro bảo mật của Marketplace
    • Khi gọi action bên ngoài bằng cú pháp uses:, bạn đang trao quyền truy cập vào repo, secret và môi trường build cho bên thứ ba chưa được kiểm chứng
    • Có thể pin SHA, nhưng gần như chẳng mấy ai làm; mà kể cả có pin thì cấu trúc vẫn là chạy một đoạn mã mờ đục chưa từng đọc cùng với quyền truy cập GITHUB_TOKEN
    • Marketplace trộn lẫn các action do cộng đồng duy trì với chất lượng rất khác nhau, đa số được cấu thành từ shell script và Dockerfile
    • Việc quản lý phụ thuộc thiếu minh bạch và có khả năng thực thi mã không an toàn
  • Ràng buộc của môi trường compute
    • Runner mặc định của GitHub Actions là runner dùng chung thuộc sở hữu Microsoft, chậm, tài nguyên hạn chế và gần như không thể tùy biến có ý nghĩa
    • Chi phí cho runner lớn hơn đủ để khiến đội tài chính gửi một lời mời họp kiểu “chúng ta cần nói chuyện”, mà ngay cả như vậy bạn vẫn không kiểm soát được môi trường
    • Có ít nhất 6 startup như Namespace, Blacksmith, Actuated, Runs-on, BuildJet chuyên chỉ giải quyết chuyện runner GitHub Actions quá chậm, và riêng điều đó đã chứng minh môi trường compute mặc định đang thiếu sót
    • Thiết lập self-hosted runner có thể giải quyết bài toán compute, nhưng các vấn đề còn lại như biểu thức YAML, mô hình quyền, Marketplace hay trình xem log vẫn y nguyên

Những vấn đề nhỏ nhưng tích lũy theo thời gian

  • actions/cache: khóa cache gây khó hiểu, cache miss xảy ra âm thầm, việc eviction cache thiếu minh bạch, khiến thời gian tiêu tốn để debug cache còn nhiều hơn thời gian nó tiết kiệm được
  • Workflow tái sử dụng: không thể lồng quá sâu, không thể truy cập gọn gàng vào context của workflow gọi, và không thể test một cách cô lập
  • Mô hình quyền của GITHUB_TOKEN: permissions: write-all thì quá rộng, còn các quyền chi tiết lại có tương tác mê cung giữa cấu hình cấp repository, workflow và job
  • Điều khiển đồng thời (concurrency): có thể hủy các lần chạy đang diễn ra trên cùng một nhánh chỉ với một dòng, nhưng không hỗ trợ mức kiểm soát tinh vi hơn thế
  • Không thể dùng secret trong điều kiện if: không thể chạy điều kiện kiểu if: secrets.DEPLOY_KEY != ''; điều này hợp lý về bảo mật, nhưng khi viết workflow phải chạy được cho cả fork lẫn repo chính thì lại cần các cách lách

Cái bẫy của tư duy “cứ dùng Bash script đi”

  • Những kỹ sư đã mệt mỏi với YAML CI thường bị cám dỗ thay mọi thứ bằng script bash trong run:, nhưng theo thời gian sẽ xuất hiện thêm điều kiện, hàm, parse tham số và xử lý song song
  • Ba tháng sau, bạn có thể có 800 dòng bash đang tái hiện song song hóa job bằng wait và file PID, cùng với logic retry và parse output tự chế
  • Kết quả là không phải bạn đã thoát khỏi hệ thống CI, mà là tự viết ra một hệ thống CI còn tệ hơn bằng bash, không có framework test và không ai theo nổi
  • Bash phù hợp làm công cụ keo dán (glue), nhưng nếu dùng làm hệ thống build hay test harness thì đó là hành động chuyển độ phức tạp từ nơi có lan can bảo vệ sang nơi không có gì bảo vệ

Cách tiếp cận thay thế của Buildkite

  • Trình xem log ổn định

    • Trình xem log của Buildkite hiển thị log đúng cách mà không làm sập trình duyệt, đồng thời render nguyên vẹn màu ANSI và định dạng từ các framework test
    • Với tính năng Annotation, step build có thể in trực tiếp Markdown lên trang build như phần tóm tắt lỗi test, báo cáo coverage hay link deploy
    • Vì agent chạy trên hạ tầng riêng của bạn, nên có thể SSH vào máy build để debug trực tiếp
  • Cấu trúc YAML đơn giản

    • YAML của Buildkite là một cấu trúc dữ liệu thuần túy mô tả pipeline, chỉ khai báo step, command và plugin
    • Nếu cần logic thực sự, hãy viết script bằng một ngôn ngữ lập trình thực thụ có thể chạy cục bộ
    • Cách tiếp cận này giữ ranh giới rõ ràng giữa “điều phối nằm trong cấu hình, logic nằm trong mã”, đúng là ranh giới mà GitHub Actions thường làm mờ đi
  • Quyền kiểm soát hoàn toàn với môi trường compute

    • Agent của Buildkite là một binary đơn lẻ, có thể chạy ở cloud riêng, on-premise hay trên phần cứng tùy chỉnh
    • Bạn có thể kiểm soát hoàn toàn loại instance, caching, lưu trữ cục bộ và mạng; từ EC2 cỡ lớn với ổ NVMe và Docker layer cache 20GB cho tới cả Raspberry Pi đều được hỗ trợ
    • Không tồn tại cả một ngành bên thứ ba kiểu “Buildkite nhưng nhanh hơn”; bạn chỉ cần chạy máy lớn hơn là xong
    • Với cá nhân duy trì các thư viện mã nguồn mở nhỏ, free tier cho repo public của GitHub Actions vẫn có giá trị
    • Đối tượng chính của bài viết này là các đội đang vận hành hệ thống production, nơi thời gian CI được đo bằng số giờ kỹ thuật bị mất mỗi tuần, và một build 45 phút tạo ra chi phí cả về compute lẫn nhân công
    • Trong những môi trường như vậy, overhead vận hành agent Buildkite nhanh chóng hoàn vốn
  • Hỗ trợ pipeline động

    • Trong Buildkite, step pipeline là dữ liệu, và script có thể tạo (emit) thêm step động ở runtime rồi upload lên
    • Trong monorepo, cách này cho phép tạo chính xác chỉ các step build/test cần thiết dựa trên file đã thay đổi, không cần matrix hard-code hay mớ spaghetti if: contains(...)
    • matrix, điều kiện if và workflow tái sử dụng của GitHub Actions cố gắng xấp xỉ điều này, nhưng cuối cùng lại thành một cỗ máy Rube Goldberg được xây bằng ngôn ngữ khai báo thiếu sức biểu đạt
  • Sự đơn giản trong cấu trúc plugin

    • Về cấu trúc, nó cũng giống GitHub Actions Marketplace ở chỗ lấy mã từ repo bên thứ ba
    • Điểm khác là plugin của Buildkite thường là các shell hook mỏng chứ không phải Docker image, nên bề mặt nhỏ hơn và có thể đọc toàn bộ trong vài phút
    • Vì chạy trên hạ tầng của chính bạn, nên blast radius có thể do người dùng tự kiểm soát
  • Các chi tiết tính năng xoay quanh trải nghiệm người dùng

    • Buildkite cho phép hiển thị emoji tùy chỉnh (:parrot:, :docker: v.v.) cạnh các step pipeline; nghe có vẻ nhỏ nhặt nhưng cho thấy sự chăm chút với trải nghiệm sử dụng sản phẩm
    • GitHub Actions trông như sản phẩm được thiết kế bởi một ủy ban, chưa từng tự hỏi “dùng cái này có vui không?”

Kết luận: Tiêu chí chọn hệ thống CI

  • GitHub Actions đã chiếm lĩnh thị trường nhờ lợi thế được tích hợp sẵn (default): miễn phí cho repo public, tích hợp ngay trong nền tảng mà ai cũng đang dùng, và đạt mức “đủ dùng” (Good Enough)
    • Nó giống như Internet Explorer của CI: chi phí chuyển đổi là thứ rất thực tế và thời gian thì hữu hạn, nên mọi người vẫn tiếp tục dùng
  • Buildkite vượt trội hơn về khả năng dùng bền vững lâu dài và trải nghiệm lập trình viên
  • Với các dự án mã nguồn mở đơn giản, GitHub Actions là đủ, nhưng trong môi trường production quy mô lớn, Buildkite phù hợp hơn
  • Trong lịch sử các hệ thống CI, thứ giành thị phần không phải là hệ thống tốt nhất, mà là hệ thống dễ bắt đầu nhất
  • GitHub Actions là CI dễ bắt đầu nhất, còn Buildkite là CI tốt nhất để tiếp tục dùng, và về lâu dài điều thứ hai mới quan trọng
  • Nếu cấu trúc của công cụ CI đang bào mòn thời gian của lập trình viên, thì vấn đề không nằm ở lập trình viên mà nằm ở chính công cụ

3 bình luận

 
kimjoin2 2026-02-07

Có vẻ vấn đề nằm ở chỗ bản thân CI ngày càng trở nên phức tạp.

 
tujuc 2026-02-07

Có vẻ như cùng một bài đã được đăng lên hai lần. Nhưng dạo này trông cũng như một sự kết hợp khá ổn để AI dựng nên..

 
GN⁺ 2026-02-07
Ý kiến trên Hacker News
  • Tôi đã dùng nhiều hệ thống CI. Tôi dùng CircleCI và GitHub Actions khá nhiều, nhưng kết luận của tôi khác tác giả
    Trước đây Jenkins gần như dành cho Java, Travis gần như dành cho Rails, nhưng những CI chuyên biệt kiểu đó cuối cùng đều đi vào ngõ cụt. Giờ đây CI đã tiến hóa thành một trình điều phối workflow đơn thuần
    Lý do tôi chuyển từ CircleCI 2 sang GitHub Actions cũng là vì CircleCI không xử lý tốt sự chuyển đổi này. GHA đủ sức biểu đạt
    Những thứ như trình xem log hay cú pháp YAML chỉ là vấn đề nhỏ. Điều quan trọng là quyền sở hữu tài nguyên tính toánpipeline động, trong đó cái đầu tiên CI nào cũng làm được, còn cái sau là điểm mạnh của Buildkite
    Kết luận của tôi là Actions thực tế khá ổn, và nếu lập công ty mới thì tôi sẽ dùng Buildkite, còn với mã nguồn mở thì dùng Actions

    • Tôi có ý kiến ngược lại. Trong phát triển game, hệ thống build là cốt lõi, còn cách tiếp cận CI kiểu tổng quát thì quá chậm
      Nếu không hiểu đồ thị build, bạn sẽ phải duy trì trạng thái build tăng dần, và điều đó gây ra bug thoáng qua. Vì vậy cần những hệ thống hiểu rất sâu cấu trúc build như UnrealEngine Horde hay UBA
      Nếu dùng CI tổng quát, một bản build có thể mất hơn một ngày
    • Actions là một nền tảng đa chức năng: vừa là bộ điều phối sự kiện và orchestrator, vừa là execution engine, hệ thống cache, marketplace, secret manager, v.v.
      Tôi thường chỉ dùng những phần tốt của GHA. Ví dụ, GitHub rất tuyệt với vai trò bộ điều phối sự kiện, nhưng lại không tốt lắm với vai trò workflow orchestrator, nên tôi giao phần đó cho hệ thống khác
    • Tôi không đồng ý với việc xem nhẹ trình duyệt log. Trải nghiệm đọc log mà màu ANSI và định dạng được giữ nguyên là rất quan trọng
      Nếu log bạn phải xem hàng chục lần mỗi ngày lại gây khó chịu thì năng suất sẽ giảm. Đọc log thô và phải tự bỏ qua các escape code thực sự rất đau khổ
    • Có người nói quyền sở hữu tài nguyên tính toán là quan trọng, nhưng GitHub vẫn thu phí ngay cả khi chạy CI trên phần cứng của chính bạn
    • Tôi là khách hàng đời đầu của Buildkite, và thực sự rất hài lòng vì đây là một hệ thống công thái học tốt và có mức độ kiểm soát cao
  • Tôi giữ mọi thứ đơn giản. Tôi đưa toàn bộ orchestration vào script deploy.sh và chạy nó trên máy Mac cục bộ hoặc AWS CodeBuild
    YAML chỉ có đúng một dòng bash deploy.sh. Chỉ cần có container Docker thì nó sẽ chạy giống nhau ở bất cứ đâu, từ Azure đến GitHub Actions

  • Chiến lược cốt lõi của mọi môi trường CI là có một hệ thống build giống hệt local
    Tôi luôn bắt đầu bằng Makefile. Docker, CI build, linting, mọi thứ đều do Makefile điều khiển. Khi dự án lớn hơn thì có thể chuyển sang công cụ khác, nhưng nền tảng ban đầu là một công cụ kích hoạt duy nhất

    • Từ ý tưởng đó mà tôi tạo ra mkincl. Nó giúp mô-đun hóa và tái sử dụng Makefile. Công ty tôi đã dùng nó nhiều năm nay, khá trực quan và linh hoạt
    • Thay vì phụ thuộc vào plugin của nhà cung cấp CI, tốt hơn là chuyển sang một ngôn ngữ bậc cao hơn
      Tôi dùng Fastlane khá nhiều cho mobile, vì nó giảm boilerplate và cung cấp cấu trúc. Cuối cùng nó vẫn là Ruby nên nếu cần thì vẫn thoát ra được
    • Make thực sự là một hệ thống rất kỳ quặc. Một trong các quy tắc mặc định của nó là trích xuất file từ hệ thống quản lý phiên bản
      (liên kết tài liệu GNU Make)
      Chung quy lại thì đây vẫn là kiểu “cứ viết Bash script đi”, chỉ là thêm vào một lớp phức tạp không cần thiết
    • Cách tiếp cận này là lý tưởng, nhưng với các dự án cỡ vừa và lớn thì không thực tế
      Ở công ty hiện tại của tôi cũng vậy, đến lúc không còn thể chạy toàn bộ pipeline trên local nữa thì sẽ xuất hiện một hạ tầng CI khổng lồ, nơi để test một MR mà phải chạy build đến 10 lần
  • Tôi thấy bài này giống quảng cáo cho Nix/Buildkite
    CI chỉ cần ở mức chạy script hay target build là đủ. CI nên chỉ cung cấp môi trường và cấu hình, còn logic phải nằm trong code
    Làm vậy sẽ có được tính độc lập với CI, giúp dễ chuyển đổi giữa các hệ thống

    • “Hãy giữ CI đơn giản” là điều thực tế không thể làm được. Khi quy mô lớn lên, các thứ như trigger có điều kiện, chiến lược nhánh, quyền hạn, cân bằng tải sẽ khiến độ phức tạp tăng lên là điều tất yếu
      GitLab CI xử lý kiểu phức tạp này khá tốt. Tính năng template và cấu hình job của nó rất xuất sắc, nhưng debug thì khó, và logic điều kiện đôi khi lại hỏng theo cách khó lường
    • Đây không phải quảng cáo. Ngay cả với team Buildkite thì đây cũng là một bất ngờ thú vị
    • Tôi cũng đồng ý. Trước đây khi chuyển CI, những team đặt toàn bộ logic trong file .sh thì việc di chuyển cực kỳ dễ
      Ngược lại, những team phân nhỏ mọi thứ trong UI thì đã rất vất vả
    • Ít nhất thì cũng may là không có phản ứng kiểu “à, bài này do AI viết”
  • Vấn đề không phải CI/CD tự thân, mà là văn hóa lập trình bằng file cấu hình
    Vòng lặp git commit -m "try fix" rồi chờ 10 phút là quá phổ biến. Môi trường CI có thể tái hiện trên local vẫn còn thiếu trầm trọng

    • Đây không phải vấn đề công cụ mà là hệ quả của thất bại trong chính sách. Cần phân biệt rõ build, release và debug build
      Nếu thiết lập cách ly môi trường như một chính sách thì dùng công cụ nào cũng không thành vấn đề. Cuối cùng, điều cốt lõi là sự hài hòa giữa công cụ và phương pháp luận
    • Đúng vậy, tôi nghĩ riêng phần này đã chiếm 80% trọng tâm của bài viết
    • Các công cụ như act giúp tái hiện CI trên local rất nhiều
  • Tiêu đề kiểu “giết chết team kỹ sư” là cường điệu. GitHub Actions đủ tốt
    Tôi thích nó hơn Bitbucket hay GitLab

    • Lúc đầu tôi còn bấm vào vì tưởng là “Microsoft đang giết người à?”, nhưng rồi lại thấy thất vọng
    • Tôi cũng tưởng đang nói về GitLab. Đặc biệt là vấn đề vòng phản hồi chậm thì GitLab cũng dính y hệt
  • Gần đây độ tin cậy của GitHub giảm mạnh
    actions/checkout có thể fail vô cớ, job release chạy hai lần, hoặc có lúc chỉ ngồi chờ suốt 40 phút
    Tôi đã dùng nó nhiều năm nhưng độ ổn định cơ bản đang đi xuống. Thật tiếc vì tôi đã bỏ lỡ Buildkite

    • Đúng vậy, các cron job của GHA rất thiếu ổn định. Ngay trong tài liệu cũng có nhắc là không đáng tin cậy
  • GitHub Actions là một trong những công cụ CI tệ nhất tôi từng dùng (ngang hàng Jenkins)
    Trong khi đó Buildkite là tốt nhất. Nhờ pipeline động, bạn có thể tự động tạo step retry khi test fail, hoặc điều chỉnh test song song tùy theo thay đổi mã nguồn
    Khả năng dùng cấu hình máy khác nhau cho từng job CI cũng là một ưu điểm lớn. Rất đáng để khuyến nghị

    • Jenkins có rất nhiều vấn đề, nhưng phần định nghĩa pipeline bằng Groovy lại rất ổn. Tôi thấy nó tốt hơn YAML nhiều
    • Jenkins là một hệ thống ổn định đã được kiểm chứng qua thực chiến. Nó xử lý hàng nghìn job không vấn đề gì và hoạt động ngay sau khi cài đặt. Tôi nghĩ đây là một trong những phần mềm mã nguồn mở tốt nhất suốt 25 năm qua
  • Những người cổ súy cho “CI đơn giản dựa trên script” có lẽ chưa từng có kinh nghiệm với các dự án thực tế ở quy mô lớn