Quản lý 100+ Microservices không ‘đau đầu’: Tại sao bạn nên bỏ Git Submodule để sang dùng Repo?

Git tutorial - IT technology blog
Git tutorial - IT technology blog

Cơn ác mộng 2 giờ sáng: Khi Git Submodule ‘phản bội’ bạn

2 giờ sáng, điện thoại rung liên hồi. Hệ thống microservices của công ty sập. Chúng tôi cần rollback gấp 15 dịch vụ về phiên bản ổn định của tuần trước. Lúc đó, team vẫn dùng Git Submodule để quản lý các repo con bên trong một repo tổng.

Kết quả? Một thảm họa thực sự. Quản lý commit hash cho từng submodule là một cực hình. Lỗi detached HEAD xuất hiện liên tục. Chỉ cần một developer quên push code ở repo con nhưng lại update hash ở repo cha, pipeline CI/CD sẽ ‘ngỏm’ ngay lập tức. Đêm đó, tôi mất 4 tiếng chỉ để dọn dẹp đống hỗn độn của các pointer Git.

Sáng hôm sau, tôi quyết định tìm giải pháp khác. Đó là lúc tôi bén duyên với repo (Git-repo). Đây là công cụ ‘xương sống’ mà Google dùng để điều phối hơn 1.000 repository trong dự án Android (AOSP).

Lựa chọn nào cho dự án Microservices khổng lồ?

Khi dự án phình to từ 10 lên 100 microservices, cách bạn quản lý code sẽ quyết định tốc độ release. Hãy nhìn vào 3 hướng đi phổ biến:

1. Monorepo (Tất cả vào một giỏ)

  • Ưu điểm: Dễ tìm kiếm code, thay đổi nhiều service trong 1 commit.
  • Nhược điểm: Repo nặng hàng chục GB khiến việc clone mất cả buổi. Phân quyền cực khó và build CI/CD chậm nếu thiếu tool xịn như Bazel hay Nx.

2. Git Submodule (Repo trong Repo)

  • Ưu điểm: Tính năng có sẵn của Git.
  • Nhược điểm: UX tệ hại. Việc theo dõi phiên bản giữa repo cha và con rất dễ sai sót. Với 50 submodule trở lên, việc quản lý thủ công gần như là bất khả thi.

3. Repo Tool (Giải pháp Hybrid)

  • Ưu điểm: Giữ các repo độc lập nhưng điều khiển tập trung qua file Manifest (XML). Bạn có thể sync 200 repo chỉ bằng một câu lệnh duy nhất.
  • Nhược điểm: Phải cài thêm script Python bên ngoài.

Với team từ 20-50 người, repo là điểm giao thoa hoàn hảo. Nó giữ được sự linh hoạt của Polyrepo nhưng vẫn mang lại khả năng quản trị tập trung của Monorepo.

Cốt lõi của repo: Sức mạnh từ file Manifest

repo không lưu code trực tiếp. Nó quản lý danh sách repository thông qua file Manifest. Hãy coi nó như một bản đồ tổng thể, chỉ rõ repo nào nằm ở đâu, dùng branch nào và lưu tại thư mục nào trên máy local.

Một file default.xml thực tế thường gọn nhẹ như thế này:

<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote name="origin" fetch=".." />
  <default revision="main" remote="origin" sync-j="8" />

  <!-- Danh sách microservices -->
  <project path="services/auth" name="my-org/auth-service" />
  <project path="services/order" name="my-org/order-service" />
  <project path="libs/common" name="my-org/shared-library" />
</manifest>

Triển khai repo trong 3 bước

Bước 1: Cài đặt công cụ

Bản chất repo là một script Python bọc ngoài Git. Trên Linux hoặc macOS, bạn cài đặt trong ‘một nốt nhạc’:

mkdir -p ~/.bin
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo
chmod a+rx ~/.bin/repo
export PATH=$PATH:~/.bin

Bước 2: Tạo Manifest Repository

Bạn tạo một repo riêng (ví dụ: manifests.git) để chứa file default.xml. Đây sẽ là ‘nguồn sự thật’ duy nhất cho cấu trúc dự án của bạn.

Bước 3: Khởi tạo Project

Thay vì git clone từng cái đến phát mệt, developer chỉ cần chạy:

# Kết nối tới manifest
repo init -u [email protected]:my-org/manifests.git -b main

# Tải toàn bộ 100+ repo về máy
repo sync -j16

Lệnh repo sync sẽ tự động clone hoặc update toàn bộ project. Tham số -j16 cho phép tải song song 16 luồng, giúp tiết kiệm 70% thời gian chờ đợi.

Những lệnh ‘cứu giá’ cho dân DevOps

Làm việc với hệ thống lớn, tôi thường xuyên dùng các ‘tuyệt chiêu’ sau để xử lý nhanh:

Kiểm tra trạng thái toàn hệ thống: Đừng cd vào từng folder. Hãy dùng forall để quét một lượt:

repo forall -c 'git branch | grep "*"'

Tạo branch đồng loạt cho kỳ Release: Bạn cần tạo branch release-v2.0 cho 80 repos cùng lúc? Quá đơn giản:

repo start release-v2.0 --all

Kinh nghiệm ‘xương máu’ từ thực tế

Trong dự án gần nhất với 85 repository, repo giúp chúng tôi giảm từ 20 ticket lỗi cấu hình mỗi tuần xuống còn gần như bằng 0. Tuy nhiên, bạn cần lưu ý:

  • Manifest là tối thượng: Mọi thay đổi cấu trúc thư mục phải được commit vào manifest trước khi báo team sync code.
  • Tận dụng sức mạnh đa nhân: Luôn dùng -j khi sync. Với mạng văn phòng tốc độ cao, -j16 hoặc -j32 sẽ biến việc tải code từ ‘chờ đi cafe’ thành ‘vài giây’.
  • Đừng dùng dao mổ trâu giết gà: Nếu dự án chỉ có 3-5 repo, hãy cứ dùng Git thuần cho nhẹ đầu. repo chỉ thực sự đáng giá khi số lượng repo vượt ngưỡng kiểm soát của con người.

Sau khi áp dụng quy trình này cho team 8 người, tình trạng ‘râu ông nọ chắp cằm bà kia’ giữa các service biến mất hoàn toàn. Quan trọng nhất, không còn ai phải thức đêm chỉ để check xem thư viện dùng chung đã đúng version hay chưa.

Nếu bạn đang ‘vật lộn’ với đống Microservices rời rạc, hãy thử dành một buổi chiều setup repo. Tin tôi đi, workflow của bạn sẽ chuyên nghiệp hơn hẳn đấy.

Share: