Tại sao tôi ngừng chi trả quá mức cho dịch vụ Git Hosting đám mây
Các nhà cung cấp dịch vụ Git Hosting và CI/CD đám mây thông dụng tuy tiện lợi nhưng thường đi kèm với nhiều rắc rối: giá cả khó lường, bị phụ thuộc vào nhà cung cấp (vendor lock-in) và các vấn đề về quyền riêng tư. Trong khi GitLab là một công cụ mạnh mẽ, yêu cầu bộ nhớ của nó rất cao, thường cần ít nhất 4GB RAM chỉ để hoạt động ổn định. Ngược lại, Gitea là một file thực thi (binary) duy nhất được viết bằng Go, có thể chạy mượt mà trên một VPS giá 5 USD/tháng hoặc thậm chí là Raspberry Pi với chỉ 250MB RAM.
Đối với bất kỳ kỹ sư DevOps nào, khả năng triển khai một pipeline CI/CD riêng tư, tách biệt hoàn toàn (air-gapped) là một lợi thế cực lớn. Dù bạn đang làm việc trong môi trường bảo mật cao hay chỉ muốn tránh tình trạng sụt giảm năng suất mỗi khi “GitHub sập”, Gitea mang lại sự tự chủ hoàn toàn. Với sự trưởng thành gần đây của Gitea Actions, bạn không còn cần phải kết nối nhiều công cụ như Jenkins hay Drone nữa. Giờ đây, bạn có thể chạy các workflow bằng cú pháp GitHub Actions quen thuộc ngay trên hạ tầng của riêng mình.
Sức mạnh của Gitea Actions
Gitea xử lý việc quản lý kho mã nguồn (repository), trong khi Gitea Actions đảm nhận các tác vụ tự động hóa nặng nề. Hệ thống này dựa trên act_runner, một công cụ dựa trên dự án nektos/act. Vì nó chia sẻ cùng logic với GitHub Actions, bạn thường có thể chuyển các tệp .github/workflows hiện có sang Gitea mà không cần thay đổi cấu hình. Đây là trải nghiệm gần nhất với GitHub mà bạn có thể đạt được mà không phải trả phí đăng ký hàng tháng.
Triển khai: Khởi chạy Gitea với Docker Compose
Docker Compose là cách đơn giản nhất để quản lý bộ công cụ này. Nó tách biệt logic ứng dụng khỏi dữ liệu, giúp việc nâng cấp trở nên dễ dàng như việc thay đổi tag phiên bản. Mặc dù Gitea hỗ trợ SQLite, tôi khuyên bạn nên sử dụng PostgreSQL cho môi trường nhóm để đảm bảo tính toàn vẹn dữ liệu tốt hơn và xử lý người dùng đồng thời hiệu quả hơn.
Tạo một thư mục dự án và lưu cấu hình này thành tệp docker-compose.yml:
version: "3"
networks:
gitea:
external: false
services:
server:
image: gitea/gitea:1.21.7
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea_password
restart: always
networks:
- gitea
volumes:
- ./gitea-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
depends_on:
- db
db:
image: postgres:15-alpine
restart: always
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=gitea_password
- POSTGRES_DB=gitea
networks:
- gitea
volumes:
- ./postgres-data:/var/lib/postgresql/data
Khởi chạy hệ thống bằng một lệnh duy nhất:
docker-compose up -d
Truy cập http://localhost:3000 để hoàn tất cài đặt. Hãy nhớ đặt **SSH Port** thành 2222 và **Gitea Base URL** thành IP máy chủ thực tế của bạn. Nếu bạn để mặc định, các URL clone Git sẽ bị lỗi ngay từ đầu.
Kích hoạt bộ máy CI/CD
Gitea Actions mặc định bị tắt để tiết kiệm tài nguyên. Để kích hoạt, bạn cần chỉnh sửa tệp app.ini nằm trong volume tại ./gitea-data/gitea/conf/app.ini. Thêm các dòng sau vào cuối tệp:
[actions]
ENABLED = true
Khởi động lại container để các thay đổi có hiệu lực:
docker-compose restart server
Cấu hình Act Runner
Máy chủ Git không trực tiếp thực thi mã; nó ủy thác công việc đó cho một runner. Để bảo mật và hiệu năng tốt hơn, tôi thường đặt runner trên một máy chủ riêng biệt hoặc ít nhất là một container riêng. Điều này ngăn việc một tiến trình build nặng làm treo toàn bộ giao diện web Git của bạn. Thêm dịch vụ sau vào tệp docker-compose.yml của bạn:
runner:
image: gitea/act_runner:latest
environment:
- CONFIG_FILE=/config.yaml
- GITEA_INSTANCE_URL=http://server:3000
- GITEA_RUNNER_REGISTRATION_TOKEN=<YOUR_TOKEN>
- GITEA_RUNNER_NAME=prod-runner-01
volumes:
- ./runner-data:/data
- /var/run/docker.sock:/var/run/docker.sock
networks:
- gitea
depends_on:
- server
Để tìm GITEA_RUNNER_REGISTRATION_TOKEN, hãy đăng nhập với quyền quản trị và đi tới **Quản trị hệ thống > Actions > Runners**. Nhấp vào **Tạo Runner mới** và sao chép chuỗi ký tự được cung cấp.
Lưu ý rằng việc ánh xạ /var/run/docker.sock cấp cho runner quyền hạn đáng kể đối với máy chủ của bạn. Nó cho phép runner tải image và khởi chạy container cho các bước CI. Đối với môi trường production, hãy cân nhắc sử dụng thiết lập Docker rootless để giảm thiểu rủi ro bảo mật.
Kiểm tra Pipeline mới của bạn
Hãy xác nhận mọi thứ hoạt động ổn định. Tạo một kho lưu trữ mới và đảm bảo Actions đã được bật trong phần cài đặt kho lưu trữ. Sau đó, tạo một tệp tại .gitea/workflows/test.yaml với nội dung sau:
name: Kiểm tra Gitea Actions
on: [push]
jobs:
check-environment:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- run: echo "Pipeline đang chạy trên Gitea!"
- run: npx --version
Sau khi bạn push tệp này, hãy kiểm tra tab **Actions**. Bạn sẽ thấy công việc chuyển từ trạng thái “Waiting” (Đang chờ) sang “Success” (Thành công) chỉ trong vài giây. Nếu nó bị treo, hãy kiểm tra log của runner bằng lệnh docker logs -f gitea-runner để xem có vấn đề về kết nối hay không.
Bảo trì và Kiểm tra sức khỏe hệ thống
Tự triển khai (Self-hosting) đồng nghĩa với việc bạn chính là kỹ sư SRE. Gitea tích hợp sẵn một endpoint chỉ số tại /metrics, bạn có thể kích hoạt trong app.ini để đưa dữ liệu vào Prometheus. Điều này rất quan trọng để theo dõi các pool kết nối cơ sở dữ liệu và dung lượng kho lưu trữ.
Một sai lầm phổ biến là bộ nhớ đệm (cache) của Docker. Theo thời gian, act_runner sẽ tích tụ các hình ảnh dư thừa và các lớp build layer có thể dễ dàng chiếm tới 20GB hoặc 30GB dung lượng đĩa. Tôi khuyên bạn nên thiết lập một công việc cron hàng tuần đơn giản để chạy lệnh docker system prune -f trên máy chủ runner. Việc này giúp môi trường CI/CD của bạn luôn tinh gọn và ngăn lỗi “Disk Full” (Đầy ổ đĩa) làm hỏng các bản build.
Chuyển sang Gitea giúp bạn có toàn quyền sở hữu dữ liệu và logic tự động hóa của mình. Mặc dù việc thiết lập tốn nhiều công sức hơn một chút so với tài khoản SaaS, nhưng tốc độ và hiệu quả chi phí là điều khó có thể đánh bại.

