https://github.com/genius-wizard-dev/gitsync
https://github.com/genius-wizard-dev/gitsync
Last synced: 6 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/genius-wizard-dev/gitsync
- Owner: genius-wizard-dev
- Created: 2026-05-14T08:58:00.000Z (20 days ago)
- Default Branch: main
- Last Pushed: 2026-05-14T09:22:53.000Z (20 days ago)
- Last Synced: 2026-05-14T11:33:45.966Z (20 days ago)
- Language: Go
- Size: 13.7 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# gitsync (POC)
Tool sync 1 Git repository → S3 bucket remote (S3-compatible: AWS / MinIO / Ceph / R2 / Wasabi / Backblaze / ...).
**Behaviour MVP**: Go orchestrator (clone shallow, parse tree) + **rclone** lo phần S3 (incremental sync với MD5 checksum, delete orphan an toàn). Mỗi sync chỉ upload file thực sự đổi → tiết kiệm băng thông, nhanh hơn 10-100× cho repo có ít file đổi giữa các commit.
## Behavior
```
gitsync sync
→ git clone --depth=1 vào tempdir
→ git ls-tree -r HEAD (log số file)
→ exec rclone sync workdir → s3:bucket/prefix
• --checksum : so sánh MD5 (Git không preserve mtime, không dùng được mtime)
• --delete-after : xoá orphan SAU upload thành công (fail → giữ nguyên)
• --transfers=N : worker pool song song
• --exclude=.git/** : skip metadata git
→ parse output → stats (transferred / skipped / deleted / errors)
→ cleanup tempdir
```
Sau mỗi sync: state S3 = state Git tree (file giống → giữ, file đổi → overwrite, file orphan → xoá).
## Yêu cầu
- `git` binary trong PATH
- `rclone` binary trong PATH (https://rclone.org/install/)
- Go 1.25+ (để build từ source)
Docker image đã đóng gói sẵn cả 2.
## Quick start
```bash
cd Source/gitsync
# 1. Copy env template, điền S3 remote + Git URL của bạn
cp .env.example .env
# 2. Chạy local (yêu cầu rclone đã cài)
make run
# Hoặc Docker (rclone đã có trong image)
make docker-run
```
Tương đương inline (không dùng make):
```bash
set -a; source .env; set +a
go run ./cmd sync
# Docker:
docker build -t gitsync:poc .
docker run --rm --env-file .env gitsync:poc sync
```
## Cấu hình (env vars)
| Biến | Bắt buộc | Default | Mô tả |
| ------------------- | -------- | ------------- | ------------------------------------------------------ |
| `GIT_URL` | yes | | HTTPS Git URL |
| `GIT_BRANCH` | no | `main` | Branch / tag / ref |
| `GIT_PAT` | no | | Personal Access Token (để trống cho public repo) |
| `S3_ENDPOINT` | yes | | Remote endpoint URL (S3-compatible: MinIO, Ceph, R2, ...) |
| `S3_REGION` | no | `us-east-1` | Placeholder cho non-AWS |
| `S3_BUCKET` | yes | | Bucket name |
| `S3_PREFIX` | no | `""` (root) | Key prefix (auto thêm `/`) |
| `S3_ACCESS_KEY` | yes | | Access key |
| `S3_SECRET_KEY` | yes | | Secret key |
### Tuning (optional)
rclone đọc trực tiếp các env vars sau — không cần wrapper:
| Env | Default | Mô tả |
| -------------------------------- | ------- | -------------------------------------- |
| `RCLONE_TRANSFERS` | 4 | File upload song song |
| `RCLONE_CHECKERS` | 8 | Worker MD5 check song song |
| `RCLONE_S3_UPLOAD_CONCURRENCY` | 4 | Parts song song mỗi file (multipart) |
| `RCLONE_S3_CHUNK_SIZE` | 5M | Part size cho multipart |
Default 4 transfers + 8 checkers đã tuned tốt cho 99% case. Chỉ tăng khi sync repo cực lớn (>10GB) hoặc latency S3 cao, và sau khi đo thực tế. Set quá cao → S3 throttle 503 → tổng thời gian CHẬM hơn.
## Exit codes
| Code | Ý nghĩa |
| ---- | ---------------------------------------------------- |
| 0 | Thành công |
| 10 | Lỗi retryable (network, S3 5xx transient, rclone fail) |
| 20 | Lỗi không retry (config sai) |
| 30 | Cancel bởi SIGTERM/SIGINT |
## Vì sao dùng rclone thay vì AWS SDK?
Trước đây code dùng `aws-sdk-go-v2` upload từng file. Vấn đề:
| Tính năng | AWS SDK custom code | rclone |
| ------------------------------- | ------------------- | ------ |
| Upload mới + overwrite trùng | ✅ tự code | ✅ |
| Skip file không đổi | ❌ re-upload all | ✅ `--checksum` |
| Delete orphan (state khớp Git) | ❌ phải tự code | ✅ `--delete-after` |
| Retry network/5xx | ⚠️ default SDK retry | ✅ `--retries=5 --low-level-retries=10` |
| Multipart cho file lớn | ✅ | ✅ tự động |
| Resume sync fail giữa chừng | ❌ | ✅ lần sau tự skip phần đã xong |
→ Tự viết là re-invent rclone. rclone là static binary single-file, đóng gói trong Docker image gọn gàng.
## Behavior khi file đổi/giữ/xoá
Với `--checksum`, rclone so sánh:
- **MD5 file local** vs **ETag object S3**
- Trùng → **skip** (không re-upload)
- Khác → **upload overwrite**
- Object có trên S3 mà không có trong local tree → **delete** (sau khi upload xong, an toàn)
S3 không có "folder" thật — key là string định danh duy nhất. Upload overwrite là atomic per-key (S3 default).
## Kiến trúc folder
```
gitsync/
├── cmd/main.go # entry, signal handler, subcommand `sync`
├── internal/
│ ├── config/ # env loader + validate
│ ├── git/ # shallow clone + walk tree + RedactPAT (os/exec git)
│ └── sync/ # flow: clone → walk → exec rclone → parse stats
├── Dockerfile # multi-stage: gitsync + rclone + git, user 65532
├── Makefile # build/run/docker shortcuts
├── .env.example
└── go.mod
```
## Build image
```bash
make docker # build → gitsync:poc (gitsync + rclone + git)
make docker-push # push (sửa IMAGE/TAG trong Makefile)
```
Image này sẵn sàng làm K8s Job pod ở Phase 2: spawn Job với image này + K8s Secret per-workflow inject env qua `envFrom`.
## S3-compatible compatibility
rclone hỗ trợ thuần native qua `RCLONE_S3_PROVIDER=Other` + `RCLONE_S3_FORCE_PATH_STYLE=true` (đã set trong code).
| Provider | `S3_ENDPOINT` |
| ------------ | ------------- |
| AWS S3 | (để trống — rclone discover qua region) |
| MinIO (self-hosted) | `https://minio.example.com:9000` |
| Ceph RGW | Custom endpoint của cluster |
| Cloudflare R2| `https://.r2.cloudflarestorage.com` + `S3_REGION=auto` |
| Wasabi | `https://s3..wasabisys.com` |
| Backblaze B2 | `https://s3..backblazeb2.com` |
**Caveat ETag** với một số provider (R2, B2 cũ) có thể không trả MD5 chuẩn → `--checksum` có thể không match. Test bằng:
```bash
# Check sau lần sync đầu tiên
rclone hashsum md5 s3:bucket/prefix/some-file
md5sum ./workdir/some-file
# Trùng → --checksum hoạt động đúng
# Khác → cần fallback (sẽ thêm flag `--size-only` ở Phase 1)
```
## Chạy trên K8s (Helm)
Chart trong `chart/` deploy gitsync như **one-shot Job**. K8s tự GC Job + Pod sau khi xong (`ttlSecondsAfterFinished=600`).
### Quick start
```bash
# 1. Copy values template, điền credentials
cp chart/values-example.yaml chart/values-dev.yaml
# edit chart/values-dev.yaml: git.url, s3.endpoint, s3.bucket, s3.accessKey, s3.secretKey
# 2. Verify lint + render (không apply)
helm lint chart -f chart/values-dev.yaml
helm template gitsync chart -f chart/values-dev.yaml | less
# 3. Install — chart tự tạo: ServiceAccount + Secret + Job
helm install gitsync chart \
-f chart/values-dev.yaml \
-n gitsync --create-namespace
# 4. Theo dõi (chart đã tạo NOTES.txt với command hướng dẫn)
kubectl logs -n gitsync job/gitsync-gitsync -f
kubectl get job -n gitsync gitsync-gitsync -w
# 5. Re-run với commit mới (Job spec immutable → upgrade dùng pre-install hook delete+recreate)
helm upgrade gitsync chart -f chart/values-dev.yaml -n gitsync
# 6. Cleanup (Job tự GC sau 10 phút, hoặc force ngay)
helm uninstall gitsync -n gitsync
```
### Quan trọng về Job immutable
K8s Job spec **không thể patch** sau khi tạo. Chart đã handle bằng hook `helm.sh/hook: post-install,post-upgrade` + `hook-delete-policy: before-hook-creation` → mỗi lần `helm upgrade`, Job cũ bị xoá trước, Job mới tạo lại.
→ Re-run sync = `helm upgrade`.
### Secret management
| Cách | Use case | Setup |
|---|---|---|
| `secret.create: true` (default) | Dev local, test nhanh | Điền `s3.accessKey/secretKey` vào values, chart tự tạo Secret |
| `secret.create: false` + `secret.existingName: my-secret` | Prod, Temporal, Provisioner | Tự tạo Secret trước (qua kubectl/ExternalSecrets/Vault), chart chỉ reference |
Secret tự tạo có keys: `S3_ACCESS_KEY`, `S3_SECRET_KEY`, `GIT_PAT` (optional).
Ví dụ tạo Secret từ ngoài (cho prod):
```bash
kubectl create secret generic gitsync-creds -n gitsync \
--from-literal=S3_ACCESS_KEY=... \
--from-literal=S3_SECRET_KEY=... \
--from-literal=GIT_PAT=...
helm install gitsync chart \
--set secret.create=false \
--set secret.existingName=gitsync-creds \
--set git.url=... --set s3.endpoint=... --set s3.bucket=... \
-n gitsync
```
### Tích hợp Provisioner / Temporal (Phase 2+)
Workflow tương lai:
```
Temporal Workflow
└─ Activity "spawn gitsync job"
├─ Tạo Secret per-workflow (random suffix, TTL)
├─ helm install (hoặc kubectl apply rendered manifest)
│ --set secret.create=false
│ --set secret.existingName=gitsync-creds-
│ --set git.url=... --set s3.bucket=...
├─ Watch Job status (kubectl get job -w hoặc client-go)
├─ Stream pod logs về Temporal
└─ Cleanup Secret + Job (ttlSecondsAfterFinished tự lo Job)
```
Vì chart đã separate Secret + Job logic, Provisioner có thể:
- Pre-create Secret với credentials per-tenant
- Apply chỉ Job phần (via `helm template ... | kubectl apply`)
- Hoặc dùng `client-go` để tạo Job spec trực tiếp (skip Helm)
### Local dev với kind/k3d/minikube
```bash
# kind
kind create cluster --name dev
make docker # build local
kind load docker-image gitsync:poc --name dev # load vào node, không cần registry
helm install gitsync chart \
--set image.repository=gitsync \
--set image.tag=poc \
--set image.pullPolicy=Never \
-f chart/values-dev.yaml
# k3d
k3d cluster create dev
make docker && k3d image import gitsync:poc -c dev
helm install gitsync chart \
--set image.repository=gitsync --set image.tag=poc --set image.pullPolicy=Never \
-f chart/values-dev.yaml
# minikube
minikube start
eval $(minikube docker-env)
make docker
helm install gitsync chart \
--set image.repository=gitsync --set image.tag=poc --set image.pullPolicy=Never \
-f chart/values-dev.yaml
```
### Resource limits (default)
| | Request | Limit |
|---|---|---|
| CPU | 100m | 1000m |
| Memory | 128Mi | 512Mi |
| Workdir (emptyDir) | — | 1Gi |
Repo lớn (>500MB) cần tăng:
```bash
helm upgrade gitsync chart -f values-dev.yaml \
--set workdir.sizeLimit=5Gi \
--set resources.limits.memory=1Gi
```
## Roadmap
- **Phase 0** (đây): Go orchestrator + rclone, chạy local + Docker
- Phase 1: cobra + image push registry + callback HTTP flag
- Phase 2: Provisioner spawn K8s Job với image này, K8s Secret per-workflow inject
- Phase 3: Backend integrate + Helm chart + observability
- Phase 4 (future): preview/diff UI (chuyển sang versioned prefix + HEAD pointer)
Chi tiết xem `.planning/gitsync/phase-*.md`.