Bỏ qua

football-booking-infra-k3s

Infrastructure-as-Code cho hệ thống Football Booking — tự động hóa quá trình provision 4 VM (UTM, local macOS) và bootstrap cụm K3s + Docker Compose stack bằng Ansible, sau đó bàn giao việc deploy app cho ArgoCD (GitOps).

📋 Xem SERVICES.md để biết danh mục đầy đủ tất cả repo trong hệ thống (mục đích, tech stack, docs, CI/CD). 📐 Xem docs/adr/ để biết các quyết định kiến trúc đã chốt (và lý do).


Kiến trúc tổng quan (môi trường utm-local, 4 VM)

Khác với một cụm K3s "gộp" điển hình, môi trường UTM local tách stateful service và observability stack ra khỏi K3s, chạy trên 2 VM riêng bằng Docker Compose — chỉ 2 VM còn lại (master + 1 worker) thực sự chạy K3s.

┌───────────────────────────┐   ┌───────────────────────────┐
│   VM1 — k3s-master        │   │   VM3 — k3s-worker         │
│   192.168.64.10            │   │   192.168.64.12             │
│                            │   │                            │
│   K3s control plane        │   │   K3s node — app pods       │
│   ├── Traefik (bundled)   │◄──┤   ├── api-gateway           │
│   ├── ArgoCD               │   │   ├── user/field/booking/   │
│   ├── kube-prometheus-stack│   │   │   payment/notification │
│   │   (Prometheus+Grafana)│   │   ├── chatbot-service (Py)  │
│   └── Kubernetes Dashboard │   │   └── 4× Go service         │
│                            │   │       (document-worker,     │
│   node-role: master        │   │        availability-engine, │
│   workload: stateful-adj.  │   │        analytics-pipeline,   │
└─────────────┬──────────────┘   │        webhook-receiver)     │
              │ Flannel VXLAN     │   node-role: worker          │
              │ (pod network)     │   workload: stateless        │
              │                   └───────────────┬──────────────┘
              │                                   │
┌─────────────▼──────────────┐   ┌────────────────▼──────────────┐
│  VM2 — data-node            │   │  VM4 — obs-node                │
│  192.168.64.11               │   │  192.168.64.13                  │
│                              │   │                                │
│  Docker Compose — stateful   │   │  Docker Compose — observability│
│  ├── PostgreSQL 16 (5432)   │   │  ├── ClickHouse (+ Keeper)      │
│  ├── MongoDB 7 (27017)      │   │  ├── SigNoz (query+frontend)    │
│  ├── Redis (6379)           │   │  ├── OTel Collector (4317/4318) │
│  ├── Kafka (9092/9093)      │   │  ├── Loki (logs, 3101 cross-VM) │
│  ├── Keycloak (8080)        │   │  ├── Tempo (traces, 3200)       │
│  ├── OmniRoute LLM (20128)  │   │  ├── LangFuse (LLM obs., 3100)  │
│  └── MinIO (blob storage)   │   │  ├── MinIO (LangFuse blob)      │
│                              │   │  ├── Redis (chatbot session)   │
│  node-role: data             │   │  ├── Kafka UI (9095)            │
└──────────────────────────────┘   │  └── exporters (kafka/pg/cAd.) │
                                    │  node-role: observability      │
                                    └────────────────────────────────┘

Luồng request: Client → Traefik (K3s bundled ingress) → api-gateway → NestJS/Go microservices → data-node (Postgres/Mongo/Redis/Kafka/Keycloak)

Luồng deploy app: git push (app repo) → CI build image → commit tag vào football-booking-gitops → ArgoCD tự sync vào K3s — Ansible không còn tự helm upgrade app nghiệp vụ (xem ADR-0002).

Luồng observability: app pods (K3s) và Traefik export traces/metrics qua OTLP tới OTel Collector trên obs-node → ClickHouse (SigNoz) + Loki + Tempo. Grafana (chạy trong K3s, namespace monitoring) trỏ datasource Prometheus (local) + Loki/Tempo (cross-node, obs-node) để xem chung một chỗ.


Tech Stack

Layer Tool Vai trò
Orchestration K3s v1.29.4 Lightweight Kubernetes, 2 node K3s (1 master + 1 worker) trong tổng 4 VM
Provisioning Ansible Cài đặt OS, K3s, Docker, bootstrap toàn bộ 4 VM
GitOps ArgoCD Deploy/quản lý app từ repo football-booking-gitops — nguồn sự thật duy nhất cho manifest app
Secret management Ansible Vault Encrypt secrets trước khi commit; app pods đọc qua K8s Secret do helm_apps bootstrap
Container registry auth k3s_registry role Cấu hình K3s pull image private từ GHCR trên toàn bộ node cluster
Stateful services Docker Compose (data-node) PostgreSQL, MongoDB, Redis, Kafka, Keycloak, OmniRoute, MinIO
Observability Docker Compose (obs-node) ClickHouse + SigNoz, Loki, Tempo, LangFuse, exporters, Kafka UI
In-cluster monitoring kube-prometheus-stack + K8s Dashboard Prometheus/Grafana/node-exporter + Kubernetes Dashboard, deploy trong namespace monitoring
CI/CD GitHub Actions Reusable workflows (cd-backend.yml, cd-chatbot.yml) + Ansible Lint/Molecule CI cho chính repo này (ci.yml)
Networking / Ingress Traefik (K3s bundled) Thay nginx-ingress cũ — role ingress cấu hình qua HelmChartConfig + deploy Ingress resources
CNI Flannel VXLAN Pod networking giữa k3s-master và k3s-worker
LLM routing OmniRoute Multi-provider router (Groq / Gemini / Anthropic), chạy trên data-node

Cấu trúc thư mục

football-booking-infra-k3s/
├── ansible.cfg                    # Cấu hình mặc định Ansible (inventory, SSH key)
├── secrets/
│   └── vault.yml                  # ⚠ Secrets (PHẢI encrypt trước khi commit)
├── inventory/
│   ├── utm/                       # Môi trường local (UTM VM, 4 node — 192.168.64.10-13)
│   │   ├── hosts.ini               # groups: k3s_master, k3s_workers, data_nodes, obs_nodes
│   │   └── group_vars/
│   └── oracle/                    # Môi trường Oracle Cloud (3 VM — stateful+obs gộp vào master)
│       ├── hosts.ini
│       └── group_vars/
├── playbooks/
│   ├── site.yml                   # Full provision từ đầu (chạy 1 lần, có --tags cho từng bước)
│   ├── argocd.yml                 # Cài ArgoCD lên K3s master (1 lần)
│   ├── k3s-registry.yml           # Cấu hình K3s pull image private từ GHCR
│   ├── deploy.yml                 # Re-deploy tất cả apps (legacy/emergency — xem ADR-0002)
│   └── deploy_service.yml         # Deploy thủ công 1 service cụ thể (legacy/emergency)
├── roles/
│   ├── common/                    # OS baseline: swap, sysctl, UFW, packages (chạy trên cả 4 VM)
│   ├── docker/                    # Cài Docker Engine + Compose plugin (master, data-node, obs-node)
│   ├── k3s_master/                # Cài K3s server, lấy node-token
│   ├── k3s_worker/                # Join cluster bằng token từ master
│   ├── k3s_registry/              # Cấu hình containerd pull image private GHCR
│   ├── kubeconfig/                # Fetch kubeconfig về máy local
│   ├── stateful_stack/            # Deploy Docker Compose stateful stack lên data-node
│   ├── obs_stack/                 # Deploy Docker Compose observability stack lên obs-node
│   ├── helm_apps/                 # Bootstrap namespace + K8s Secrets cho app (KHÔNG deploy app — ArgoCD làm việc đó)
│   ├── ingress/                   # Cấu hình Traefik (bundled) + deploy Ingress resources
│   ├── argocd/                    # Cài ArgoCD + Ingress cho ArgoCD UI
│   └── monitoring/                # kube-prometheus-stack + Kubernetes Dashboard
├── helm/
│   ├── backend/                   # Chart tham chiếu cho NestJS services (đường deploy chính: football-booking-gitops)
│   ├── chatbot/                   # Chart tham chiếu cho chatbot (Python)
│   └── ingress/                   # Ingress routing rules — deploy trực tiếp bởi role `ingress`
├── docker-compose/
│   ├── stateful-stack.yml         # PostgreSQL, MongoDB, Redis, Kafka, Keycloak, OmniRoute, MinIO
│   ├── observability-stack.yml    # ClickHouse, SigNoz, Loki, Tempo, LangFuse, exporters, Kafka UI
│   ├── config/                    # otel-collector, clickhouse-cluster/keeper, loki, tempo config
│   └── init-scripts/              # PostgreSQL & MongoDB init scripts
├── docs/
│   ├── adr/                       # Architecture Decision Records — đọc trước khi đổi quyết định hạ tầng
│   ├── ARCHITECTURE.md / .vi.md   # Chi tiết vai trò từng component
│   └── READING_GUIDE.md / .vi.md  # Sequential reading & debug map
├── .github/workflows/
│   ├── ci.yml                      # Ansible Lint + Molecule cho chính repo này
│   ├── cd-backend.yml              # Reusable: deploy 1 backend service
│   ├── cd-chatbot.yml              # Reusable: deploy chatbot service
│   ├── docs-hub.yml                # Gom docs/ từ các repo khác → Cloudflare Pages
│   └── README.md                   # Hướng dẫn setup GitHub Actions
└── scripts/
    ├── check-before-commit.sh     # Kiểm tra security trước khi commit
    ├── setup-utm-network.sh       # Cấu hình network UTM local
    └── verify-cluster.sh          # Kiểm tra cluster sau khi provision

Môi trường

Env Inventory VM Layout
utm-local inventory/utm 4 VM — 192.168.64.10/.11/.12/.13 master / data-node / worker / obs-node tách riêng (xem sơ đồ trên)
oracle inventory/oracle 3 VM — 140.238.x.x (masked) 1 master + 2 worker; stateful + observability stack gộp chạy trên master (data_nodes/obs_nodes cùng trỏ IP master)

Ghi chú: k3s_cluster (nhóm được K3s quản lý) chỉ gồm k3s_master + k3s_workers. data_nodesobs_nodes là VM Docker Compose thuần, đứng ngoài K3s nhưng vẫn được common/docker role provision baseline.


Quickstart

1. Yêu cầu

# macOS
brew install ansible helm kubectl
pip3 install ansible-lint

# Tạo SSH key cho cụm 4 VM UTM
ssh-keygen -t ed25519 -f ~/.ssh/utm_k3s -C "utm-k3s"

2. Cấu hình secrets

# Copy template và điền giá trị thật
cp secrets/vault.yml secrets/vault.yml.plain  # chỉ để tham khảo
# Chỉnh sửa secrets/vault.yml, thay tất cả CHANGE_ME
# Sau đó encrypt:
ansible-vault encrypt secrets/vault.yml
ansible-vault encrypt roles/stateful_stack/vars/vault.yml

# Lưu vault password vào file local (không commit)
echo "your-vault-password" > ~/.vault_pass
chmod 600 ~/.vault_pass

3. Provision 4 VM từ đầu (chạy 1 lần)

# Kiểm tra kết nối SSH tới cả 4 VM
ansible all -i inventory/utm -m ping

# Provision toàn bộ — chạy tuần tự 10 bước (OS baseline → K3s → stateful → obs → ingress → monitoring)
ansible-playbook -i inventory/utm playbooks/site.yml \
  --vault-password-file ~/.vault_pass

# Có thể chạy riêng từng bước bằng --tags, xem comment đầu playbooks/site.yml
# vd: chỉ deploy lại observability stack lên obs-node
ansible-playbook -i inventory/utm playbooks/site.yml --tags obs \
  --vault-password-file ~/.vault_pass

4. Bootstrap ArgoCD (1 lần, sau khi K3s đã chạy)

ansible-playbook -i inventory/utm playbooks/argocd.yml

Sau bước này, mọi deploy/update app đi qua repo football-booking-gitops — xem ADR-0002. Ansible không tự helm upgrade app nữa; deploy.yml/deploy_service.yml chỉ còn dùng cho trường hợp khẩn cấp.

5. Kiểm tra cluster

export KUBECONFIG=~/.kube/football-k3s.yaml
kubectl get nodes                        # 2 node: k3s-master + k3s-worker
kubectl get pods -n football-booking     # app pods (do ArgoCD sync)
kubectl get pods -n argocd
kubectl get pods -n monitoring

./scripts/verify-cluster.sh

Truy cập nhanh:

Service Cách truy cập
Grafana kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 3000:80
Kubernetes Dashboard kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard 8443:443
ArgoCD UI https://argocd.football-booking.local (qua Traefik Ingress) hoặc kubectl port-forward -n argocd svc/argocd-server 8080:443
SigNoz (APM) http://192.168.64.13:3301
Kafka UI http://192.168.64.13:9095
Traefik Dashboard kubectl port-forward -n kube-system deploy/traefik 9000:9000

Đầy đủ hướng dẫn (kèm token/credential) được in ra cuối bước --tags monitoring của site.yml.


CI/CD với GitHub Actions

Deploy tự động khi push code vào app repo (backend/chatbot/go-service):

git push (app repo)
  → GitHub Actions CI: build Docker image → push GHCR
  → Gọi reusable workflow từ repo này (cd-backend.yml / cd-chatbot.yml)
  → Commit image tag mới vào football-booking-gitops
  → ArgoCD phát hiện thay đổi → tự sync vào K3s (rollback tự động nếu health check fail)

Repo này tự chạy CI riêng (ci.yml): Ansible Lint (non-blocking, ~139 finding tồn đọng chưa dọn) + Molecule test cho từng role.

Setup chi tiết: .github/workflows/README.md

Deploy thủ công (legacy/emergency — không phải đường chính, xem ADR-0002):

ansible-playbook -i inventory/oracle playbooks/deploy_service.yml \
  -e "service=user-service" \
  -e "image_tag=abc1234" \
  --vault-password-file ~/.vault_pass

Security

# Chạy trước mỗi lần git commit
./scripts/check-before-commit.sh

Script kiểm tra: - Vault files đã encrypt chưa - Không có private key content trong tracked files - Không có hardcoded passwords - Không có kubeconfig hoặc .vault_pass bị staged

Quan trọng: secrets/vault.yml phải luôn ở dạng encrypted ($ANSIBLE_VAULT;1.1;AES256) trước khi commit. Xem hướng dẫn chi tiết trong docs/ARCHITECTURE.md.


Tài liệu

File Nội dung
docs/adr/ Architecture Decision Records — quyết định hạ tầng đã chốt + lý do (đọc trước khi đổi CNI, ingress, secret management, ranh giới với repo khác...)
docs/ARCHITECTURE.md Architecture guide (English)
docs/ARCHITECTURE.vi.md Kiến trúc chi tiết, vai trò từng component (Tiếng Việt)
docs/READING_GUIDE.md Sequential reading & debug map (English)
docs/READING_GUIDE.vi.md Hướng dẫn đọc tuần tự + debug map (Tiếng Việt)
.github/workflows/README.md Setup GitHub Actions CI/CD

Xem đầy đủ + mô tả trong SERVICES.md. Tóm tắt:

Repo Mô tả
football-booking-backend-k3s NestJS microservices: api-gateway, user, field, booking, payment, notification
football-booking-chatbot-service-k3s Python/FastAPI chatbot — Groq SDK + RAG (Pinecone)
football-booking-go-service-k3s 4 Go service (document-worker, availability-engine, analytics-pipeline, webhook-receiver) giao tiếp qua Kafka
football-booking-gitops GitOps source of truth — ArgoCD Applications/ApplicationSets + Helm charts thật deploy vào cluster
football-booking-terraform Config-as-code cho resource đã có REST API riêng (Postgres role, Keycloak realm, Kafka topic, Grafana dashboard, MinIO bucket, K8s NetworkPolicy...)