Trả lời nhanh: Build mobile là loại việc ngốn phút CI nhất: một lượt Flutter hoặc Android mất mười tới ba mươi phút, gấp nhiều lần một dự án web. Dịch vụ CI tính theo phút nên hóa đơn tăng rất nhanh khi đội build hằng ngày. Máy tự host giải quyết bằng hai cách: trả cố định theo tháng thay vì theo phút, và giữ được bộ nhớ đệm giữa các lượt build nên mỗi lượt còn nhanh hơn hẳn. Đổi lại bạn tự trông máy và phải cẩn thận với khóa ký ứng dụng.
Dự án web build một phút, dự án mobile build hai mươi phút. Cùng một hệ thống CI, cùng một cách tính tiền, nhưng hóa đơn chênh nhau hàng chục lần. Đó là lý do máy build tự host phổ biến trong đội mobile hơn hẳn đội web, và bài này đi vào phần dựng cùng những chỗ dễ sai.
Vì sao build mobile đắt hơn nhiều
Bốn nguyên nhân cộng lại:
- Chuỗi công cụ nặng. Gradle chạy trên máy ảo Java, biên dịch qua nhiều bước, xử lý tài nguyên cho nhiều mật độ màn hình.
- Tải phụ thuộc rất nhiều. Một dự án trung bình kéo về hàng trăm MB thư viện ở lượt đầu.
- Đọc ghi hàng chục nghìn file nhỏ, đúng loại thao tác mà máy ảo dùng chung hay chậm.
- Thường phải build hai lần, một bản gỡ lỗi cho đội kiểm thử và một bản phát hành.
Trên dịch vụ dùng chung, mỗi lượt lại bắt đầu từ máy trắng nên phải tải lại toàn bộ. Đây chính là chỗ máy riêng thắng đậm: thư viện đã nằm sẵn trên đĩa, bộ nhớ đệm của công cụ build còn nguyên, và lượt build thứ hai trở đi nhanh hơn nhiều lần.
Dựng runner trên máy Linux
Máy build đã dựng theo bài máy build Android chỉ cần thêm phần nhận việc từ hệ thống CI. Cách dựng chung cho mọi loại dự án nằm ở bài runner tự host, ở đây chỉ nói phần riêng của mobile:
- Chạy runner dưới tài khoản riêng, không dùng tài khoản quản trị. Tài khoản đó cần quyền đọc bộ công cụ SDK và quyền ghi trong thư mục làm việc.
- Giữ nguyên thư mục bộ nhớ đệm giữa các lượt build. Đây là toàn bộ lý do bạn tự dựng, nên đừng cấu hình xóa sạch thư mục làm việc sau mỗi lượt.
- Đặt giới hạn bộ nhớ cho công cụ build nhỏ hơn RAM thật, tránh cảnh tiến trình bị hệ điều hành giết giữa chừng.
- Chạy runner như dịch vụ hệ thống để nó tự sống lại sau khi máy khởi động.
Bảo vệ khóa ký ứng dụng
Đây là phần khác biệt lớn nhất so với CI cho web, và cũng là chỗ nguy hiểm nhất. Máy build của bạn cần khóa ký để tạo bản phát hành, nghĩa là khóa nằm trên máy đó.
Bốn nguyên tắc:
- Khóa không bao giờ nằm trong repo, kể cả repo riêng tư.
- Đặt ngoài thư mục dự án, ví dụ trong thư mục nhà của tài khoản chạy build, với quyền chỉ tài khoản đó đọc được.
- Mật khẩu khóa lấy từ biến môi trường do hệ thống CI cấp, không ghi thẳng vào file cấu hình.
- Sao lưu khóa ở ít nhất hai nơi an toàn. Mất khóa nghĩa là không bao giờ cập nhật được ứng dụng đó trên cửa hàng nữa.
Thêm một điều đáng cân nhắc với đội đông người: chỉ máy build phát hành mới cần khóa. Máy dựng bản thử hằng ngày dùng khóa gỡ lỗi là đủ, và như vậy bề mặt rủi ro nhỏ hơn nhiều.
Cấu hình luồng cho hợp lý
Ba loại lượt build với ba mức tần suất khác nhau:
- Mỗi lần đẩy code lên nhánh làm việc: chỉ chạy kiểm tra định dạng và kiểm thử đơn vị. Nhanh, vài phút, không dựng bản cài.
- Mỗi lần gộp vào nhánh chính: dựng bản thử rồi đưa lên nơi lưu trữ cho đội kiểm thử tải về.
- Khi gắn thẻ phiên bản: dựng bản phát hành đã ký, đây là lượt duy nhất cần tới khóa thật.
Chia như vậy giúp máy không phải chạy bản dựng đầy đủ ở mỗi lần đẩy code, vốn là nguyên nhân khiến hàng đợi dài và mọi người phải chờ nhau. Nếu đội đông và hàng đợi vẫn dài, cách rẻ nhất thường là nâng ổ đĩa và RAM của một máy chứ chưa cần thêm máy thứ hai, lý do nằm ở bài về ổ đĩa khi build app.
Việc bảo trì phải làm đều
Máy build tự host hỏng theo những cách rất dễ đoán, nên phòng trước được:
Đầy ổ đĩa. Mỗi lượt build để lại vài trăm MB. Đặt tác vụ định kỳ hằng tuần xóa thư mục build cũ và các bản dựng quá hạn. Đây là sự cố phổ biến nhất và luôn xảy ra vào ngày bạn cần phát hành gấp.
Chuỗi công cụ lệch phiên bản. Ghim phiên bản của bộ công cụ cho từng dự án thay vì luôn chạy bản mới nhất, nếu không một bản cập nhật sẽ làm hỏng bản dựng mà không ai đụng vào code.
Bộ nhớ đệm hỏng. Thỉnh thoảng bản dựng lỗi vô lý và cách chữa là xóa bộ nhớ đệm. Hãy chuẩn bị sẵn một nút chạy tay để xóa và dựng lại từ đầu, thay vì lúc gấp phải mò lệnh.
Runner chết im lặng. Chạy nó như dịch vụ có tự khởi động lại, và thêm một cảnh báo khi không có lượt build nào thành công trong khoảng thời gian bất thường.
Bảo vệ khóa ký ứng dụng trên máy chạy tác vụ
| Việc | Vì sao bắt buộc |
|---|---|
| Không lưu khóa ký trong kho mã nguồn | Ai đọc được kho là ký được ứng dụng giả danh bạn |
| Lưu trong kho bí mật của hệ thống tác vụ | Được mã hóa và không hiện trong nhật ký |
| Không bao giờ chạy tác vụ từ nhánh của người ngoài | Người lạ chạy được lệnh và đọc được khóa |
| Xóa tệp khóa sau mỗi lần dựng | Không để lại trên đĩa cho lần chạy sau |
| Ghi nhật ký mỗi lần khóa được dùng | Truy được khi có sự cố |
Dòng thứ ba là rủi ro nghiêm trọng nhất khi tự dựng máy chạy tác vụ: với kho mã nguồn mở, bất kỳ ai cũng gửi được một nhánh, và nếu tác vụ tự chạy trên máy của bạn thì họ đọc được mọi bí mật trong đó, gồm cả khóa ký ứng dụng.
Vì sao dựng ứng dụng di động tốn hơn
- Thời gian dựng dài hơn nhiều so với ứng dụng web, nên số phút tính tiền cộng dồn nhanh.
- Máy dùng chung của dịch vụ không giữ bộ nhớ đệm giữa các lần, nên mỗi lần đều tải lại toàn bộ thư viện.
- Bản iOS cần máy Mac, và đơn giá máy Mac cao hơn nhiều so với máy Linux.
- Hệ quả: tự dựng bản Android trên máy Linux thường hòa vốn rất nhanh; bản iOS thì tùy số lượt.
Dọn bộ nhớ đệm trước khi ổ đầy
# Don bo nho dem dinh ky, day o dia la nguyen nhan that bai hang loatdocker system prune -a --volumes --filter "until=168h"du -sh ~/.gradle ~/.android /var/lib/docker 2>/dev/nulldf -h # Dat canh bao khi o dia con duoi 20% # Cap nhat cong cu dung theo lich thang, khong ngau hung# Bo cong cu cu la nguyen nhan build that bai sau khi thu vien nang phien ban # Kiem may chay tac vu con ket noi khongsystemctl status actions.runner.* 2>/dev/null # Moi lan chay bat dau tu moi truong sach:# chay trong container va xoa container sau moi lanCấu hình gợi ý: 4 nhân, 8 GB bộ nhớ, ổ NVMe 100 GB trở lên. Bộ nhớ là thứ chạm trần trước với dự án lớn. Xem bài về dựng ứng dụng Android.
Câu hỏi thường gặp
Máy tự host tiết kiệm được bao nhiêu?
Tùy số lượt build. Đội build hằng ngày thường thấy chênh lệch rõ ngay tháng đầu, vì mỗi lượt mobile ngốn hàng chục phút. Ngoài tiền còn tiết kiệm thời gian chờ, vì bộ nhớ đệm nằm sẵn trên máy.
Có build được nhánh iOS trên máy Linux không?
Không. Nhánh iOS bắt buộc chạy trên macOS. Nhiều đội tự host nhánh Android và giữ dịch vụ sẵn có cho nhánh iOS, cách này cắt phần lớn chi phí mà không phải mua máy Mac ngay.
Runner tự host có an toàn không?
An toàn nếu bạn chạy dưới tài khoản riêng ít quyền, không để khóa ký trong repo, và không cho repo công khai chạy trên runner của mình. Repo công khai nghĩa là người lạ gửi thay đổi và code của họ sẽ chạy trên máy bạn.
Cấu hình máy bao nhiêu cho CI mobile?
Từ 4 vCPU và 8GB cho một dự án, lên 8 vCPU và 16GB nếu nhiều lượt chạy song song. Ổ nên từ 100GB vì bộ nhớ đệm và các bản dựng tích tụ nhanh, và ưu tiên ổ NVMe hơn là thêm nhân xử lý.
