docs: Nâng cấp hướng dẫn triển khai Kubernetes cục bộ với sơ đồ quy trình, hướng dẫn chi tiết và chú thích song ngữ.
This commit is contained in:
@@ -1,396 +1,273 @@
|
||||
# Local Kubernetes Deployment Guide
|
||||
|
||||
**Last Updated**: 2026-01-04
|
||||
**Difficulty**: Intermediate
|
||||
> **EN**: Local Kubernetes Deployment Guide
|
||||
>
|
||||
> **VI**: Hướng dẫn triển khai Kubernetes cục bộ
|
||||
|
||||
**Last Updated**: 2026-01-05
|
||||
**Difficulty**: Intermediate
|
||||
**Duration**: 30-45 minutes
|
||||
|
||||
## Workflow
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Start([Start]) --> EnvPrep[1. Environment Prep]
|
||||
EnvPrep --> BuildImg[2. Build Docker Image]
|
||||
BuildImg --> LoadImg[3. Load Image to Cluster<br/>(Kind/Docker Desktop)]
|
||||
LoadImg --> Secrets[4. Configure Secrets<br/>& Environment]
|
||||
Secrets --> Deploy[5. Deploy Service<br/>(K8s Manifests)]
|
||||
Deploy --> Verify[6. Verify Deployment]
|
||||
Verify --> Test[7. Test Service<br/>(Port Forward & Curl)]
|
||||
Test --> End([Complete])
|
||||
|
||||
subgraph "Deployment Details"
|
||||
Deploy --> |Apply| ConfigMap
|
||||
Deploy --> |Apply| Deployment
|
||||
Deploy --> |Apply| Service
|
||||
end
|
||||
|
||||
style Start fill:#d4edda,stroke:#28a745,stroke-width:2px
|
||||
style End fill:#d4edda,stroke:#28a745,stroke-width:2px
|
||||
style EnvPrep fill:#e2e3e5,stroke:#6c757d
|
||||
style BuildImg fill:#fff3cd,stroke:#ffc107
|
||||
style LoadImg fill:#fff3cd,stroke:#ffc107
|
||||
style Secrets fill:#f8d7da,stroke:#dc3545
|
||||
style Deploy fill:#cce5ff,stroke:#007bff
|
||||
style Verify fill:#cce5ff,stroke:#007bff
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
This guide describes how to deploy the IAM Service to a local Kubernetes cluster using Docker Desktop on macOS.
|
||||
This guide details how to deploy the IAM Service (or any microservice in the GoodGo ecosystem) to a local Kubernetes cluster using Docker Desktop on macOS.
|
||||
|
||||
## Prerequisites
|
||||
> **Important Note**: This guide assumes you are using **Docker Desktop** with **Kubernetes enabled**. If you are using Minikube or plain Kind, the steps might differ slightly (especially the image loading part).
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
### Software
|
||||
- Docker Desktop 4.0+ with Kubernetes enabled
|
||||
- kubectl CLI
|
||||
- kind CLI (for loading images into cluster)
|
||||
- pnpm 8+
|
||||
- **Docker Desktop 4.0+**: [Download Link](https://www.docker.com/products/docker-desktop/)
|
||||
- Kubernetes must be enabled in settings.
|
||||
- **kubectl CLI**: Command-line tool for interacting with K8s.
|
||||
```bash
|
||||
brew install kubectl
|
||||
```
|
||||
- **kind CLI**: Required to load images into the cluster if using Kind backend explicitely.
|
||||
```bash
|
||||
brew install kind
|
||||
```
|
||||
- **pnpm 8+**: Project package manager.
|
||||
```bash
|
||||
npm install -g pnpm
|
||||
```
|
||||
|
||||
### Knowledge
|
||||
- Basic understanding of Kubernetes (Pods, Deployments, Services)
|
||||
- Familiarity with Docker and containerization
|
||||
- Command line proficiency
|
||||
- Basic understanding of Kubernetes concepts: **Pod**, **Deployment**, **Service**, **Secret**, **ConfigMap**.
|
||||
- Familiarity with basic Docker commands (`docker build`, `docker images`).
|
||||
- Ability to navigate and run commands in the Terminal.
|
||||
|
||||
## Step 1: Environment Preparation
|
||||
## 2. Environment Preparation
|
||||
|
||||
### 1.1 Enable Kubernetes in Docker Desktop
|
||||
### 2.1 Enable Kubernetes in Docker Desktop
|
||||
|
||||
1. Open **Docker Desktop**
|
||||
2. Go to **Settings → Kubernetes**
|
||||
3. Check **Enable Kubernetes**
|
||||
4. Select cluster provisioning:
|
||||
- **kind** (recommended for development)
|
||||
- or **kubeadm**
|
||||
5. Click **Apply & Restart**
|
||||
6. Wait 2-3 minutes for Kubernetes to start
|
||||
1. Open **Docker Desktop**.
|
||||
2. Click the **Settings (⚙️)** icon.
|
||||
3. Select the **Kubernetes** tab.
|
||||
4. Check **Enable Kubernetes**.
|
||||
5. Select **Show system containers (advanced)** for easier debugging (optional).
|
||||
6. Click **Apply & Restart**.
|
||||
7. Wait 2-3 minutes until the Kubernetes icon in the bottom corner turns green.
|
||||
|
||||
### 1.2 Verify Kubernetes
|
||||
### 2.2 Verify Kubernetes Connection
|
||||
|
||||
Check if `kubectl` is connected to the correct context:
|
||||
|
||||
```bash
|
||||
# Check kubectl context
|
||||
# EN: Check current context
|
||||
# VI: Kiểm tra context hiện tại
|
||||
kubectl config current-context
|
||||
# Output: docker-desktop
|
||||
# Expected Output: docker-desktop
|
||||
|
||||
# Check nodes
|
||||
# EN: List all nodes in the cluster
|
||||
# VI: Liệt kê các node trong cluster
|
||||
kubectl get nodes
|
||||
# Output: docker-desktop Ready control-plane ...
|
||||
|
||||
# Check kind cluster name (if using kind)
|
||||
kind get clusters
|
||||
# Output: desktop
|
||||
# Expected Output:
|
||||
# NAME STATUS ROLES AGE VERSION
|
||||
# docker-desktop Ready control-plane 10m v1.29.1
|
||||
```
|
||||
|
||||
### 1.3 Install kind CLI
|
||||
## 3. Build Docker Image
|
||||
|
||||
We need to build the service image before deploying. Taking `iam-service` as an example.
|
||||
|
||||
```bash
|
||||
# Install kind
|
||||
brew install kind
|
||||
|
||||
# Verify installation
|
||||
kind version
|
||||
```
|
||||
|
||||
## Step 2: Build Docker Image
|
||||
|
||||
```bash
|
||||
# Navigate to deployments directory
|
||||
# EN: Navigate to the kubernetes deployment directory
|
||||
# VI: Di chuyển đến thư mục deployments/local/kubernetes
|
||||
cd deployments/local/kubernetes
|
||||
|
||||
# Build image (script auto-builds)
|
||||
# EN: Build the Docker image from the root context
|
||||
# VI: Build Docker image từ root context
|
||||
# Note: -f points to service Dockerfile, context is root (../../..)
|
||||
docker build -t iam-service:local -f ../../../services/iam-service/Dockerfile ../../..
|
||||
|
||||
# Verify image
|
||||
# EN: Verify the image was built successfully
|
||||
# VI: Kiểm tra image đã build thành công chưa
|
||||
docker images | grep iam-service
|
||||
# Output: iam-service:local ... 1.67GB
|
||||
# Expected Output:
|
||||
# iam-service local [IMAGE_ID] [SIZE] [CREATED]
|
||||
```
|
||||
|
||||
## Step 3: Load Image into Kubernetes Cluster
|
||||
## 4. Load Image into Cluster
|
||||
|
||||
**⚠️ Important**: Docker Desktop Kubernetes with kind backend **does not automatically share images** with Docker Desktop. You must load the image into the cluster:
|
||||
**⚠️ IMPORTANT**: Docker Desktop can use different backends. If you are running Kubernetes inside Docker Desktop, sometimes it doesn't immediately see local images if using a `kind` node underneath.
|
||||
|
||||
If you are using **Kind** (Kubernetes in Docker) separately or a specific Docker Desktop config, you need to load the image:
|
||||
|
||||
```bash
|
||||
# Load image into kind cluster
|
||||
# EN: Load image into kind cluster (if using kind explicitly)
|
||||
# VI: Load image vào kind cluster (nếu dùng kind rõ ràng)
|
||||
kind load docker-image iam-service:local --name desktop
|
||||
|
||||
# Wait for completion (may take 1-2 minutes)
|
||||
# EN: Validating image presence (optional, hard with Docker Desktop K8s directly)
|
||||
# VI: Kiểm tra sự tồn tại của image (tùy chọn)
|
||||
```
|
||||
|
||||
**Note**: If using kubeadm instead of kind, you can skip this step as kubeadm shares images better.
|
||||
> **Tip**: With default Docker Desktop, building the local image (`docker build ...`) is usually automatically available to Docker Desktop's K8s cluster. This loading step is mainly for those using `kind` CLI to create separate clusters.
|
||||
|
||||
## Step 4: Configure Secrets
|
||||
## 5. Configure Secrets & ConfigMap
|
||||
|
||||
### 4.1 Prepare Environment Variables
|
||||
Kubernetes environments need sensitive environment variables (Secrets) and general configuration (ConfigMap).
|
||||
|
||||
Create `.env.k8s` file with the following variables:
|
||||
### 5.1 Create Secrets (Manually)
|
||||
|
||||
You can run a script or the following commands to create secrets securely.
|
||||
|
||||
```bash
|
||||
# Database
|
||||
DATABASE_URL=postgresql://user:password@host:5432/database?sslmode=require
|
||||
|
||||
# JWT Secrets (MUST change in production!)
|
||||
JWT_SECRET=your-strong-jwt-secret-min-32-chars
|
||||
JWT_REFRESH_SECRET=your-strong-refresh-secret-min-32-chars
|
||||
JWT_ID_SECRET=your-strong-id-secret-min-32-chars
|
||||
|
||||
# Encryption (optional)
|
||||
ENCRYPTION_KEY=your-32-char-encryption-key-here
|
||||
```
|
||||
|
||||
### 4.2 Create Kubernetes Secrets
|
||||
|
||||
The `deploy.sh` script will automatically create secrets, or you can create them manually:
|
||||
|
||||
```bash
|
||||
# Create namespace
|
||||
# EN: Create a dedicated namespace for local testing
|
||||
# VI: Tạo namespace riêng cho local testing
|
||||
kubectl create namespace iam-local
|
||||
|
||||
# Create secrets
|
||||
# EN: Generate random secrets and store in Kubernetes
|
||||
# VI: Tạo secrets ngẫu nhiên và lưu vào Kubernetes
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=DATABASE_URL="postgresql://..." \
|
||||
--from-literal=DATABASE_URL="postgresql://user:password@host.docker.internal:5432/iam_db?schema=public" \
|
||||
--from-literal=JWT_SECRET="$(openssl rand -base64 32)" \
|
||||
--from-literal=JWT_REFRESH_SECRET="$(openssl rand -base64 32)" \
|
||||
--from-literal=JWT_ID_SECRET="$(openssl rand -base64 32)" \
|
||||
--from-literal=ENCRYPTION_KEY="$(openssl rand -base64 32)" \
|
||||
-n iam-local
|
||||
|
||||
# Verify secrets
|
||||
# EN: Verify secrets creation
|
||||
# VI: Kiểm tra secrets đã tạo
|
||||
kubectl get secrets -n iam-local
|
||||
```
|
||||
|
||||
## Step 5: Deploy Service
|
||||
> **Note on `host.docker.internal`**: On macOS, for a K8s pod to connect to PostgreSQL running on the host machine (or another container via port mapping), we use `host.docker.internal`.
|
||||
|
||||
### 5.1 Using Automated Script
|
||||
### 5.2 ConfigMap
|
||||
|
||||
The `iam-service-configmap.yaml` file typically contains non-sensitive variables like `NODE_ENV`, `LOG_LEVEL`.
|
||||
|
||||
```bash
|
||||
cd deployments/local/kubernetes
|
||||
|
||||
# Run deployment script
|
||||
./deploy.sh
|
||||
|
||||
# Script will:
|
||||
# 1. Create namespace
|
||||
# 2. Create secrets
|
||||
# 3. Apply ConfigMap
|
||||
# 4. Build Docker image
|
||||
# 5. Deploy service
|
||||
# EN: Apply ConfigMap
|
||||
# VI: Apply ConfigMap
|
||||
kubectl apply -f iam-service-configmap.yaml -n iam-local
|
||||
```
|
||||
|
||||
### 5.2 Manual Deployment
|
||||
## 6. Deploy Service
|
||||
|
||||
Now we will deploy the main resources.
|
||||
|
||||
```bash
|
||||
# Apply ConfigMap
|
||||
kubectl apply -f iam-service-configmap.yaml
|
||||
# EN: Apply Deployment manifest
|
||||
# VI: Apply file Deployment manifest
|
||||
kubectl apply -f iam-service-deployment.yaml -n iam-local
|
||||
|
||||
# Apply Deployment
|
||||
kubectl apply -f iam-service-deployment.yaml
|
||||
|
||||
# Apply Service
|
||||
kubectl apply -f iam-service-service.yaml
|
||||
# EN: Apply Service manifest (LoadBalancer/NodePort)
|
||||
# VI: Apply file Service manifest
|
||||
kubectl apply -f iam-service-service.yaml -n iam-local
|
||||
```
|
||||
|
||||
## Step 6: Verify Deployment
|
||||
## 7. Verify & Debug
|
||||
|
||||
### 6.1 Check Pod Status
|
||||
After deployment, ensure the Pod is stable (Running).
|
||||
|
||||
### 7.1 Check Pods
|
||||
|
||||
```bash
|
||||
# View pods
|
||||
# EN: Get all pods in the namespace
|
||||
# VI: Lấy danh sách pod trong namespace
|
||||
kubectl get pods -n iam-local
|
||||
|
||||
# Expected output:
|
||||
# Expected Output:
|
||||
# NAME READY STATUS RESTARTS AGE
|
||||
# iam-service-68994fdc79-gh2mj 1/1 Running 0 2m
|
||||
# iam-service-68994fdc79-gh2mj 1/1 Running 0 30s
|
||||
```
|
||||
|
||||
### 6.2 Check Logs
|
||||
### 7.2 View Detailed Logs
|
||||
|
||||
If Status is not `Running` (e.g., `CrashLoopBackOff` or `ImagePullBackOff`), check logs:
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
# EN: Stream logs from the pod
|
||||
# VI: Xem logs thời gian thực từ pod
|
||||
kubectl logs -f -n iam-local -l app=iam-service
|
||||
|
||||
# Successful logs:
|
||||
# [iam-service] Database connected successfully
|
||||
# [iam-service] Service started on port 5001
|
||||
# EN: Describe pod to see events (pull error, mounts, scheduling)
|
||||
# VI: Xem chi tiết pod để check events (lỗi pull, mount, scheduling)
|
||||
kubectl describe pod -n iam-local -l app=iam-service
|
||||
```
|
||||
|
||||
### 6.3 Check Service
|
||||
### 7.3 Common Errors
|
||||
|
||||
1. **ImagePullBackOff**:
|
||||
- **Reason**: K8s cannot find `iam-service:local` image.
|
||||
- **Fix**: Ensure `imagePullPolicy: IfNotPresent` or `Never` in local deployment yaml. If using Kind, remember to run `kind load`.
|
||||
|
||||
2. **CrashLoopBackOff**:
|
||||
- **Reason**: Runtime error, usually unable to connect to Database.
|
||||
- **Fix**: Check `DATABASE_URL` in Secret. Ensure Postgres is running and accessible from K8s (use `host.docker.internal`).
|
||||
|
||||
3. **Pending Service**:
|
||||
- **Reason**: `LoadBalancer` type on local sometimes hangs pending IP.
|
||||
- **Fix**: Not a problem, we can use `port-forward` or access via `localhost`.
|
||||
|
||||
## 8. Test Service Access
|
||||
|
||||
To access the service from your local machine, the safest way is `port-forward`.
|
||||
|
||||
```bash
|
||||
# View services
|
||||
kubectl get svc -n iam-local
|
||||
|
||||
# Output:
|
||||
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
|
||||
# iam-service LoadBalancer 10.96.187.160 <pending> 80:30577/TCP
|
||||
```
|
||||
|
||||
**Note**: `EXTERNAL-IP` will be `<pending>` because local cluster doesn't have a cloud load balancer.
|
||||
|
||||
## Step 7: Test Service
|
||||
|
||||
### 7.1 Port Forward
|
||||
|
||||
```bash
|
||||
# Forward port to access service
|
||||
# EN: Port forward from local port 5002 to service port 80
|
||||
# VI: Port forward từ cổng local 5002 tới cổng 80 của service
|
||||
kubectl port-forward svc/iam-service 5002:80 -n iam-local
|
||||
|
||||
# Service will be available at http://localhost:5002
|
||||
# Terminal will hang and show: Forwarding from 127.0.0.1:5002 -> 8000
|
||||
```
|
||||
|
||||
### 7.2 Test Health Endpoints
|
||||
Open another terminal and test:
|
||||
|
||||
```bash
|
||||
# Test liveness probe
|
||||
# EN: Test Health Check
|
||||
# VI: Test Health Check
|
||||
curl http://localhost:5002/health/live
|
||||
# Response: {"status":"ok", ...}
|
||||
|
||||
# Response:
|
||||
# {
|
||||
# "success": true,
|
||||
# "data": {"status": "live"},
|
||||
# "timestamp": "2026-01-04T06:04:03.425Z"
|
||||
# }
|
||||
|
||||
# Test readiness probe
|
||||
curl http://localhost:5002/health/ready
|
||||
|
||||
# Test API docs
|
||||
# EN: View Swagger/OpenAPI docs (if enabled)
|
||||
# VI: Xem tài liệu Swagger/OpenAPI (nếu bật)
|
||||
open http://localhost:5002/api-docs
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
## 9. Cleanup
|
||||
|
||||
### Issue 1: ImagePullBackOff
|
||||
|
||||
**Symptoms**:
|
||||
```bash
|
||||
kubectl get pods -n iam-local
|
||||
# NAME READY STATUS RESTARTS AGE
|
||||
# iam-service-6b8fbb574d-hn27z 0/1 ImagePullBackOff 0 2m
|
||||
```
|
||||
|
||||
**Cause**: kind cluster cannot find image `iam-service:local`
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Load image into kind cluster
|
||||
kind load docker-image iam-service:local --name desktop
|
||||
|
||||
# Restart deployment
|
||||
kubectl rollout restart deployment/iam-service -n iam-local
|
||||
```
|
||||
|
||||
### Issue 2: CrashLoopBackOff
|
||||
|
||||
**Symptoms**:
|
||||
```bash
|
||||
kubectl get pods -n iam-local
|
||||
# NAME READY STATUS RESTARTS AGE
|
||||
# iam-service-xxx 0/1 CrashLoopBackOff 5 5m
|
||||
```
|
||||
|
||||
**Cause**: Service crashes on startup
|
||||
|
||||
**Debug**:
|
||||
```bash
|
||||
# View logs
|
||||
kubectl logs -n iam-local -l app=iam-service --tail=50
|
||||
|
||||
# Describe pod
|
||||
kubectl describe pod -n iam-local -l app=iam-service
|
||||
```
|
||||
|
||||
**Common solutions**:
|
||||
- Check DATABASE_URL in secrets
|
||||
- Verify Prisma migrations have run
|
||||
- Check environment variables in ConfigMap
|
||||
|
||||
### Issue 3: Database Connection Failed
|
||||
|
||||
**Symptoms**: Logs show `Database connection error`
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Verify DATABASE_URL
|
||||
kubectl get secret iam-service-secrets -n iam-local -o jsonpath='{.data.DATABASE_URL}' | base64 -d
|
||||
|
||||
# Test connection from pod
|
||||
kubectl exec -it -n iam-local deployment/iam-service -- sh
|
||||
# Inside pod:
|
||||
# npx prisma db push
|
||||
```
|
||||
|
||||
### Issue 4: Redis Connection Errors
|
||||
|
||||
**Symptoms**: Logs show `Redis connection error`
|
||||
|
||||
**Cause**: Redis not deployed in cluster
|
||||
|
||||
**Solution** (optional - only if Redis needed):
|
||||
```bash
|
||||
# Deploy Redis
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: redis
|
||||
namespace: iam-local
|
||||
spec:
|
||||
serviceName: redis
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis
|
||||
namespace: iam-local
|
||||
spec:
|
||||
selector:
|
||||
app: redis
|
||||
ports:
|
||||
- port: 6379
|
||||
EOF
|
||||
|
||||
# Update ConfigMap with REDIS_HOST=redis
|
||||
kubectl edit configmap iam-service-config -n iam-local
|
||||
|
||||
# Restart deployment
|
||||
kubectl rollout restart deployment/iam-service -n iam-local
|
||||
```
|
||||
|
||||
## Debugging Commands
|
||||
When done, delete resources to free up capacity.
|
||||
|
||||
```bash
|
||||
# View all resources
|
||||
kubectl get all -n iam-local
|
||||
|
||||
# Describe deployment
|
||||
kubectl describe deployment iam-service -n iam-local
|
||||
|
||||
# Describe pod
|
||||
kubectl describe pod -n iam-local -l app=iam-service
|
||||
|
||||
# View events
|
||||
kubectl get events -n iam-local --sort-by='.lastTimestamp'
|
||||
|
||||
# Exec into pod
|
||||
kubectl exec -it -n iam-local deployment/iam-service -- sh
|
||||
|
||||
# View logs realtime
|
||||
kubectl logs -f -n iam-local -l app=iam-service
|
||||
|
||||
# View logs from previous container (if pod restarted)
|
||||
kubectl logs -n iam-local -l app=iam-service --previous
|
||||
```
|
||||
|
||||
## Cleanup
|
||||
|
||||
```bash
|
||||
# Delete deployment
|
||||
kubectl delete -f iam-service-deployment.yaml
|
||||
kubectl delete -f iam-service-service.yaml
|
||||
kubectl delete -f iam-service-configmap.yaml
|
||||
|
||||
# Delete secrets
|
||||
kubectl delete secret iam-service-secrets -n iam-local
|
||||
|
||||
# Delete namespace (deletes everything)
|
||||
# EN: Delete the namespace (removes all resources within)
|
||||
# VI: Xóa namespace (xóa tất cả resource bên trong)
|
||||
kubectl delete namespace iam-local
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Deploy Redis** (optional): To enable caching and rate limiting
|
||||
2. **Setup Ingress**: To expose service externally
|
||||
3. **Configure HPA**: Horizontal Pod Autoscaler for auto-scaling
|
||||
4. **Add Monitoring**: Prometheus + Grafana
|
||||
5. **Setup CI/CD**: Automated deployment on code changes
|
||||
|
||||
## Resources
|
||||
## References
|
||||
|
||||
- [Kubernetes Documentation](https://kubernetes.io/docs/)
|
||||
- [Docker Desktop Kubernetes](https://docs.docker.com/desktop/kubernetes/)
|
||||
- [kind Documentation](https://kind.sigs.k8s.io/)
|
||||
- [kubectl Cheat Sheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/)
|
||||
- [Local Kubernetes README](../../../deployments/local/kubernetes/README.md)
|
||||
- [Docker Desktop for Mac](https://docs.docker.com/desktop/mac/networking/)
|
||||
- [Prisma Deployment Guide](https://www.prisma.io/docs/guides/deployment/deployment-guides/deploying-to-kubernetes)
|
||||
|
||||
@@ -1,494 +1,250 @@
|
||||
# Local Development Guide
|
||||
|
||||
Comprehensive guide for running and developing the project locally with real-time hot reload.
|
||||
> **EN**: Local Development Guide
|
||||
>
|
||||
> **VI**: Hướng dẫn phát triển cục bộ
|
||||
|
||||
## System Requirements
|
||||
**Last Updated**: 2026-01-05
|
||||
**Difficulty**: Intermediate
|
||||
**Setup Time**: 15-30 minutes
|
||||
|
||||
- **Node.js**: >= 20.0.0
|
||||
- **PNPM**: >= 8.0.0
|
||||
- **Docker & Docker Compose**: Latest version
|
||||
- **Git**: For cloning repository
|
||||
- **Neon Account**: https://neon.tech (for database)
|
||||
## Workflow
|
||||
|
||||
## Quick Start (Recommended)
|
||||
```mermaid
|
||||
graph TD
|
||||
Start([Start]) --> Prerequisites[1. System Prerequisites]
|
||||
Prerequisites --> Clone[2. Clone & Install]
|
||||
Clone --> Env[3. Configure Environment<br/>(Shared & Service-Specific)]
|
||||
Env --> DB[4. Setup Database<br/>(Migrate & Seed)]
|
||||
DB --> Run[5. Run Project<br/>(Native/Docker/Hybrid)]
|
||||
Run --> Dev[6. Development Loop<br/>(Watch Mode)]
|
||||
Dev --> Test[7. Testing & Verify]
|
||||
Test --> End([Complete])
|
||||
|
||||
1. **Clone Repository**:
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
```
|
||||
subgraph "Run Modes"
|
||||
Run --> Mode1[Mode 1: Native (Fastest)]
|
||||
Run --> Mode2[Mode 2: Hybrid (Flexible)]
|
||||
Run --> Mode3[Mode 3: Full Docker (Production-like)]
|
||||
end
|
||||
|
||||
2. **Run Initialization Script**:
|
||||
```bash
|
||||
./scripts/setup/init-project.sh
|
||||
```
|
||||
This script will install dependencies, generate clients, and setup environment files.
|
||||
|
||||
## Manual Setup
|
||||
|
||||
|
||||
### 1. Clone Repository
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
style Start fill:#d4edda,stroke:#28a745,stroke-width:2px
|
||||
style End fill:#d4edda,stroke:#28a745,stroke-width:2px
|
||||
style Env fill:#fff3cd,stroke:#ffc107
|
||||
style DB fill:#fff3cd,stroke:#ffc107
|
||||
style Run fill:#cce5ff,stroke:#007bff
|
||||
```
|
||||
|
||||
### 2. Install Dependencies
|
||||
## Overview
|
||||
|
||||
This guide provides a detailed process for setting up a development environment for the GoodGo Microservices ecosystem. You will learn how to run services, set up databases, and establish an efficient workflow with hot-reload.
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
Before starting, ensure your machine has the following tools installed:
|
||||
|
||||
- **Node.js**: Latest LTS version (v20+).
|
||||
- **PNPM**: Main project package manager (`npm install -g pnpm`).
|
||||
- **Docker Desktop**: Required for running infrastructure services (Redis, Local Database).
|
||||
- **Git**: For source code management.
|
||||
- **Neon Account** (Optional): If using Neon Database on cloud (recommended for dev).
|
||||
|
||||
## 2. Initial Setup
|
||||
|
||||
### 2.1 Clone and Install Dependencies
|
||||
|
||||
```bash
|
||||
# EN: Clone the repository
|
||||
# VI: Clone repository về máy
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
|
||||
# EN: Install dependencies using pnpm
|
||||
# VI: Cài đặt các thư viện phụ thuộc bằng pnpm
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 3. Setup Database (Neon)
|
||||
### 2.2 Quick Init Script (Recommended)
|
||||
|
||||
Create environment configuration file:
|
||||
The project includes an automation script for basic initialization:
|
||||
|
||||
```bash
|
||||
# EN: Run initialization script
|
||||
# VI: Chạy script khởi tạo
|
||||
./scripts/setup/init-project.sh
|
||||
```
|
||||
|
||||
> This script will:
|
||||
> - Install dependencies.
|
||||
> - Copy example environment files (`.env.example` -> `.env`).
|
||||
> - Generate Prisma client.
|
||||
|
||||
## 3. Environment Configuration
|
||||
|
||||
The project uses a **Hybrid Environment** strategy to optimize configuration management:
|
||||
|
||||
### 3.1 Shared Configuration
|
||||
|
||||
File: `deployments/local/.env.local`
|
||||
Contains variables shared across the entire system (JWT, Redis, Logging).
|
||||
|
||||
```bash
|
||||
# EN: Create shared env file from example
|
||||
# VI: Tạo file môi trường chung từ file mẫu
|
||||
cp deployments/local/env.local.example deployments/local/.env.local
|
||||
```
|
||||
|
||||
Edit `.env.local` file and add your Neon DATABASE_URL:
|
||||
### 3.2 Service-Specific Configuration
|
||||
|
||||
Each service (e.g., `iam-service`) needs its own `.env.local` file containing specific details like Database URL and Port.
|
||||
|
||||
```bash
|
||||
# Get connection string from Neon Console: https://console.neon.tech
|
||||
DATABASE_URL=postgresql://user:password@ep-xxx.region.neon.tech/dbname?sslmode=require&pgbouncer=true
|
||||
|
||||
# JWT Secrets (can keep defaults for dev)
|
||||
JWT_SECRET=dev-jwt-secret-change-in-production
|
||||
JWT_REFRESH_SECRET=dev-refresh-secret-change-in-production
|
||||
# EN: Create service-specific env file
|
||||
# VI: Tạo file môi trường riêng cho service
|
||||
cp services/iam-service/env.local.example services/iam-service/.env.local
|
||||
```
|
||||
|
||||
**Note**: See [Neon Database Guide](neon-database.md) for detailed setup instructions.
|
||||
**Key contents to check in `services/iam-service/.env.local`**:
|
||||
|
||||
### 4. Run Database Migrations
|
||||
```properties
|
||||
# Database URL (Use Neon Tech or Local Postgres)
|
||||
DATABASE_URL=postgresql://user:password@host:5432/db_name?sslmode=require
|
||||
|
||||
# Service Port (Must be unique per service)
|
||||
PORT=5001
|
||||
|
||||
# Service Name
|
||||
SERVICE_NAME=iam-service
|
||||
|
||||
# Redis Host (localhost for Native Dev, redis for Docker Dev)
|
||||
REDIS_HOST=localhost
|
||||
```
|
||||
|
||||
## 4. Setup Database
|
||||
|
||||
After configuring `DATABASE_URL`, you need to sync the schema and seed initial data.
|
||||
|
||||
```bash
|
||||
# EN: Run migrations for iam-service
|
||||
# VI: Chạy migration cho iam-service
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
### 5. Seed Database (Optional)
|
||||
|
||||
```bash
|
||||
# EN: Seed initial data (optional)
|
||||
# VI: Tạo dữ liệu mẫu (tùy chọn)
|
||||
./scripts/db/seed.sh iam-service
|
||||
```
|
||||
|
||||
## Ways to Run the Project
|
||||
## 5. Run Modes
|
||||
|
||||
### Method 1: Run All Services (Recommended)
|
||||
You can run the project in 3 ways depending on your needs:
|
||||
|
||||
Best for full-stack development or testing the entire system:
|
||||
### Mode 1: Native Development (Recommended for Backend Dev)
|
||||
|
||||
Run directly on the host machine. Fastest speed, fastest hot-reload.
|
||||
|
||||
1. **Start Infrastructure**:
|
||||
```bash
|
||||
# EN: Start Redis and Traefik in Docker background
|
||||
# VI: Khởi động Redis và Traefik chạy ngầm bằng Docker
|
||||
cd deployments/local
|
||||
docker-compose up -d redis traefik
|
||||
cd ../..
|
||||
```
|
||||
|
||||
2. **Run Service**:
|
||||
```bash
|
||||
# EN: Start iam-service in watch mode
|
||||
# VI: Chạy iam-service ở chế độ watch
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
```
|
||||
|
||||
### Mode 2: Hybrid Development (Flexible)
|
||||
|
||||
Use when you need to run multiple auxiliary services in Docker but want to dev the main service directly.
|
||||
|
||||
```bash
|
||||
./scripts/dev/start-all.sh
|
||||
```
|
||||
# EN: Start dependent services in Docker
|
||||
# VI: Chạy các service phụ thuộc trong Docker
|
||||
docker-compose -f deployments/local/docker-compose.yml up -d user-service payment-service
|
||||
|
||||
This script will:
|
||||
1. Check if Docker is running
|
||||
2. Verify DATABASE_URL is configured
|
||||
3. Start infrastructure (Redis, Traefik)
|
||||
4. Start all services with hot reload
|
||||
|
||||
**Or run manually:**
|
||||
|
||||
```bash
|
||||
# Step 1: Start infrastructure
|
||||
cd deployments/local
|
||||
docker-compose up -d
|
||||
cd ../..
|
||||
|
||||
# Step 2: Start all services
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### Method 2: Run Specific Service
|
||||
|
||||
Best when working on a single service:
|
||||
|
||||
```bash
|
||||
# Using script
|
||||
./scripts/dev/start-service.sh iam-service
|
||||
|
||||
# Or run directly
|
||||
cd services/iam-service
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### Method 3: Run Service Groups
|
||||
|
||||
```bash
|
||||
# Run only backend services
|
||||
pnpm --filter "./services/*" dev
|
||||
|
||||
# Run only frontend apps
|
||||
pnpm --filter "./apps/*" dev
|
||||
|
||||
# Run specific service
|
||||
# EN: Run the service you are working on natively
|
||||
# VI: Chạy service bạn đang làm việc trực tiếp trên máy
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
```
|
||||
|
||||
### Method 4: Run With Docker Compose (Full Stack)
|
||||
### Mode 3: Full Docker (Production Simulation)
|
||||
|
||||
Run the entire system in Docker. Good for Integration Testing but no hot-reload.
|
||||
|
||||
```bash
|
||||
# EN: Start everything with Docker Compose
|
||||
# VI: Chạy tất cả bằng Docker Compose
|
||||
cd deployments/local
|
||||
docker-compose up -d
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Stop services
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
## Access Points
|
||||
## 6. Access & Verification
|
||||
|
||||
When services are running, you can access:
|
||||
After startup, you can access the following endpoints:
|
||||
|
||||
| Service | URL | Description |
|
||||
|---------|-----|-------------|
|
||||
| **API Gateway** | http://localhost/api/v1 | Main entry point via Traefik |
|
||||
| **IAM Service** | http://localhost:5001 | Direct IAM service access |
|
||||
| **Auth API** | http://localhost/api/v1/auth | Auth API via gateway (backward compatible) |
|
||||
| **Identity API** | http://localhost/api/v1/identity | Identity management API |
|
||||
| **Access API** | http://localhost/api/v1/access | Access management API |
|
||||
| **Governance API** | http://localhost/api/v1/governance | Governance API |
|
||||
| **Web Admin** | http://admin.localhost or http://localhost:3000 | Admin dashboard |
|
||||
| **Web Client** | http://localhost or http://localhost:3001 | Client web app |
|
||||
| **Traefik Dashboard** | http://localhost:8080 | View routing and services |
|
||||
| **API Gateway** | `http://localhost/api/v1` | Main entry point via Traefik |
|
||||
| **IAM Service** | `http://localhost:5001` | Direct service access |
|
||||
| **Health Check** | `http://localhost:5001/health` | Service status check |
|
||||
| **Metrics** | `http://localhost:5001/metrics` | Prometheus metrics |
|
||||
| **API Docs** | `http://localhost:5001/api-docs` | Swagger UI |
|
||||
|
||||
## Hot Reload & Live Development
|
||||
|
||||
### Backend Services (TypeScript)
|
||||
|
||||
Backend services use `tsx watch` or `nodemon` for automatic restart on code changes:
|
||||
### Health Check Validation
|
||||
|
||||
```bash
|
||||
# In services/iam-service/package.json
|
||||
"scripts": {
|
||||
"dev": "tsx watch src/main.ts"
|
||||
}
|
||||
# EN: Check liveness
|
||||
# VI: Kiểm tra liveness
|
||||
curl http://localhost:5001/health/live
|
||||
|
||||
# EN: Check readiness
|
||||
# VI: Kiểm tra readiness
|
||||
curl http://localhost:5001/health/ready
|
||||
```
|
||||
|
||||
**When you change:**
|
||||
- `.ts` files → Service auto-restarts (1-2 seconds)
|
||||
- `.env` files → Manual restart required
|
||||
- `prisma/schema.prisma` → Need to run migration
|
||||
## 7. Troubleshooting
|
||||
|
||||
### Frontend Apps (Next.js)
|
||||
### Port Already In Use
|
||||
|
||||
Frontend apps use Next.js Fast Refresh:
|
||||
**Error**: `Error: listen EADDRINUSE: address already in use :::5001`
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# In apps/web-admin/package.json
|
||||
"scripts": {
|
||||
"dev": "next dev"
|
||||
}
|
||||
```
|
||||
# EN: Find process using port 5001
|
||||
# VI: Tìm process đang chiếm port 5001
|
||||
lsof -i :5001
|
||||
|
||||
**When you change:**
|
||||
- React components → Updates instantly (no page reload)
|
||||
- CSS/Tailwind → Updates instantly
|
||||
- `next.config.js` → Restart required
|
||||
|
||||
### Shared Packages
|
||||
|
||||
When changing shared packages (in `packages/`):
|
||||
|
||||
```bash
|
||||
# Packages auto-rebuild with Turbo watch mode
|
||||
pnpm --filter @goodgo/logger dev
|
||||
```
|
||||
|
||||
## Real-World Development Workflow
|
||||
|
||||
### Setup 3 Terminals
|
||||
|
||||
**Terminal 1: Run Services**
|
||||
```bash
|
||||
./scripts/dev/start-all.sh
|
||||
# Or: pnpm dev
|
||||
```
|
||||
|
||||
**Terminal 2: View Logs**
|
||||
```bash
|
||||
# View specific service logs
|
||||
./scripts/dev/logs.sh iam-service
|
||||
|
||||
# Or view Docker logs
|
||||
docker logs -f redis-cache-local
|
||||
docker logs -f traefik-local
|
||||
```
|
||||
|
||||
**Terminal 3: Development Tasks**
|
||||
```bash
|
||||
# Run tests
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
|
||||
# Run migrations
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
|
||||
# Format code
|
||||
pnpm format
|
||||
```
|
||||
|
||||
## Health Checks
|
||||
|
||||
### Health Endpoints
|
||||
|
||||
```bash
|
||||
# Check API Gateway
|
||||
curl http://localhost/api/v1/health
|
||||
|
||||
# Check Auth Service directly
|
||||
curl http://localhost:5001/health
|
||||
|
||||
# Check Redis
|
||||
docker exec redis-cache-local redis-cli ping
|
||||
```
|
||||
|
||||
### Traefik Dashboard
|
||||
|
||||
Access http://localhost:8080 to view:
|
||||
- All active routes
|
||||
- Registered services
|
||||
- Service health status
|
||||
|
||||
## Database Development
|
||||
|
||||
### Schema Changes
|
||||
|
||||
```bash
|
||||
# 1. Edit prisma/schema.prisma
|
||||
# 2. Create and apply migration
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate dev --name add_new_field
|
||||
|
||||
# 3. Prisma Client auto-regenerates
|
||||
```
|
||||
|
||||
### Reset Database (Development Only!)
|
||||
|
||||
```bash
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate reset
|
||||
```
|
||||
|
||||
### View Database
|
||||
|
||||
```bash
|
||||
# Open Prisma Studio
|
||||
cd services/iam-service
|
||||
pnpm prisma studio
|
||||
# Access: http://localhost:5555
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
### VS Code Debugging
|
||||
|
||||
Create `.vscode/launch.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug Auth Service",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["--filter", "@goodgo/iam-service", "dev"],
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### View Detailed Logs
|
||||
|
||||
```bash
|
||||
# Service logs
|
||||
./scripts/dev/logs.sh iam-service
|
||||
|
||||
# Docker logs
|
||||
docker logs -f iam-service-local
|
||||
docker logs -f redis-cache-local
|
||||
docker logs -f traefik-local
|
||||
|
||||
# All logs
|
||||
docker-compose -f deployments/local/docker-compose.yml logs -f
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port Already in Use
|
||||
|
||||
```bash
|
||||
# Find process using port
|
||||
lsof -i :5001 # Auth service
|
||||
lsof -i :3000 # Web admin
|
||||
lsof -i :6379 # Redis
|
||||
lsof -i :80 # Traefik
|
||||
|
||||
# Kill process
|
||||
# EN: Kill the process
|
||||
# VI: Tắt process đó
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
### Docker Not Running
|
||||
### Database Connection Error
|
||||
|
||||
```bash
|
||||
# Check Docker
|
||||
docker info
|
||||
**Error**: `P1001: Can't reach database server`
|
||||
|
||||
# Start Docker Desktop (macOS)
|
||||
open -a Docker
|
||||
|
||||
# Restart Docker services
|
||||
docker-compose -f deployments/local/docker-compose.yml restart
|
||||
```
|
||||
|
||||
### Database Connection Failed
|
||||
|
||||
```bash
|
||||
# Check DATABASE_URL
|
||||
cat deployments/local/.env.local | grep DATABASE_URL
|
||||
|
||||
# Test connection
|
||||
cd services/iam-service
|
||||
pnpm prisma db pull
|
||||
```
|
||||
**Solution**:
|
||||
- Re-check `DATABASE_URL` variable.
|
||||
- If using local Postgres Docker, ensure container is running (`docker ps`).
|
||||
- If using Neon, check internet connection.
|
||||
|
||||
### Module Not Found
|
||||
|
||||
**Error**: Cannot find internal packages (e.g., `@goodgo/logger`).
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Cleanup and reinstall
|
||||
./scripts/utils/cleanup.sh
|
||||
pnpm install
|
||||
|
||||
# Or just cleanup node_modules
|
||||
rm -rf node_modules
|
||||
rm -rf services/*/node_modules
|
||||
rm -rf apps/*/node_modules
|
||||
rm -rf packages/*/node_modules
|
||||
# EN: Re-install dependencies and build packages
|
||||
# VI: Cài lại dependencies và build lại packages
|
||||
pnpm install
|
||||
pnpm build
|
||||
```
|
||||
|
||||
### Hot Reload Not Working
|
||||
## References
|
||||
|
||||
```bash
|
||||
# Restart service
|
||||
# Press Ctrl+C to stop, then:
|
||||
pnpm dev
|
||||
|
||||
# Or restart Docker container
|
||||
docker-compose -f deployments/local/docker-compose.yml restart iam-service
|
||||
```
|
||||
|
||||
## Tips & Best Practices
|
||||
|
||||
### 1. Use Turbo Cache
|
||||
|
||||
Turbo cache speeds up builds:
|
||||
|
||||
```bash
|
||||
# First run will be slow
|
||||
pnpm dev
|
||||
|
||||
# Subsequent runs will be faster thanks to cache
|
||||
# Cache stored in node_modules/.cache/turbo
|
||||
```
|
||||
|
||||
### 2. Dev Selective Services
|
||||
|
||||
No need to run everything if working on one service:
|
||||
|
||||
```bash
|
||||
# Run only iam-service
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Run iam-service with dependencies
|
||||
pnpm --filter @goodgo/iam-service... dev
|
||||
```
|
||||
|
||||
### 3. Watch Tests
|
||||
|
||||
```bash
|
||||
# Run tests automatically on code changes
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
```
|
||||
|
||||
### 4. Auto-format Code
|
||||
|
||||
Install Prettier extension in VS Code and enable format on save.
|
||||
|
||||
### 5. Use Git Hooks
|
||||
|
||||
```bash
|
||||
# Pre-commit hook will auto-format and lint
|
||||
git commit -m "feat: add new feature"
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Development (.env.local)
|
||||
|
||||
```bash
|
||||
# Database
|
||||
DATABASE_URL=postgresql://user:pass@ep-xxx.neon.tech/db?sslmode=require&pgbouncer=true
|
||||
|
||||
# Redis
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
|
||||
# JWT
|
||||
JWT_SECRET=dev-jwt-secret
|
||||
JWT_REFRESH_SECRET=dev-refresh-secret
|
||||
|
||||
# Service
|
||||
NODE_ENV=development
|
||||
LOG_LEVEL=debug
|
||||
```
|
||||
|
||||
### Override for Specific Service
|
||||
|
||||
Create `.env.local` file in service directory:
|
||||
|
||||
```bash
|
||||
# services/iam-service/.env.local
|
||||
PORT=5001
|
||||
LOG_LEVEL=debug
|
||||
```
|
||||
|
||||
## Useful Commands
|
||||
|
||||
```bash
|
||||
# Development
|
||||
pnpm dev # Run all services
|
||||
pnpm build # Build all
|
||||
pnpm test # Test all
|
||||
pnpm lint # Lint all
|
||||
pnpm format # Format code
|
||||
|
||||
# Cleanup
|
||||
pnpm clean # Remove build artifacts
|
||||
./scripts/utils/cleanup.sh # Full cleanup
|
||||
|
||||
# Database
|
||||
./scripts/db/migrate.sh iam-service dev # Migration
|
||||
./scripts/db/seed.sh iam-service # Seed data
|
||||
./scripts/db/backup.sh iam-service # Backup
|
||||
|
||||
# Docker
|
||||
docker-compose -f deployments/local/docker-compose.yml up -d # Start
|
||||
docker-compose -f deployments/local/docker-compose.yml down # Stop
|
||||
docker-compose -f deployments/local/docker-compose.yml logs -f # Logs
|
||||
docker-compose -f deployments/local/docker-compose.yml restart # Restart
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Getting Started](getting-started.md) - Initial setup
|
||||
- [Development Guide](development.md) - Development workflow
|
||||
- [Neon Database Guide](neon-database.md) - Database guide
|
||||
- [Troubleshooting](troubleshooting.md) - Problem solving
|
||||
- [Kubernetes Guide](kubernetes-local.md) - Deploy to Local K8s.
|
||||
- [Project Architecture](../../docs/en/ARCHITECTURE.en.md) - System architecture overview.
|
||||
|
||||
@@ -1,396 +1,273 @@
|
||||
# Hướng Dẫn Deploy Kubernetes Local
|
||||
|
||||
**Cập nhật**: 2026-01-04
|
||||
**Độ khó**: Intermediate
|
||||
> **EN**: Local Kubernetes Deployment Guide
|
||||
>
|
||||
> **VI**: Hướng dẫn triển khai Kubernetes cục bộ
|
||||
|
||||
**Cập nhật**: 2026-01-05
|
||||
**Độ khó**: Trung bình (Intermediate)
|
||||
**Thời gian**: 30-45 phút
|
||||
|
||||
## Tổng Quan
|
||||
## Workflow / Quy Trình
|
||||
|
||||
Hướng dẫn này mô tả cách deploy IAM Service lên local Kubernetes cluster sử dụng Docker Desktop trên macOS.
|
||||
```mermaid
|
||||
graph TD
|
||||
Start([Bắt đầu / Start]) --> EnvPrep[1. Chuẩn bị Môi trường<br/>Environment Prep]
|
||||
EnvPrep --> BuildImg[2. Build Docker Image]
|
||||
BuildImg --> LoadImg[3. Load Image vào Cluster<br/>(Kind/Docker Desktop)]
|
||||
LoadImg --> Secrets[4. Cấu hình Secrets<br/>& Environment]
|
||||
Secrets --> Deploy[5. Deploy Service<br/>(K8s Manifests)]
|
||||
Deploy --> Verify[6. Kiểm tra & Verify]
|
||||
Verify --> Test[7. Test Service<br/>(Port Forward & Curl)]
|
||||
Test --> End([Hoàn tất / Complete])
|
||||
|
||||
## Yêu Cầu
|
||||
subgraph "Chi tiết Deploy / Deployment Details"
|
||||
Deploy --> |Apply| ConfigMap
|
||||
Deploy --> |Apply| Deployment
|
||||
Deploy --> |Apply| Service
|
||||
end
|
||||
|
||||
style Start fill:#d4edda,stroke:#28a745,stroke-width:2px
|
||||
style End fill:#d4edda,stroke:#28a745,stroke-width:2px
|
||||
style EnvPrep fill:#e2e3e5,stroke:#6c757d
|
||||
style BuildImg fill:#fff3cd,stroke:#ffc107
|
||||
style LoadImg fill:#fff3cd,stroke:#ffc107
|
||||
style Secrets fill:#f8d7da,stroke:#dc3545
|
||||
style Deploy fill:#cce5ff,stroke:#007bff
|
||||
style Verify fill:#cce5ff,stroke:#007bff
|
||||
```
|
||||
|
||||
### Phần Mềm
|
||||
- Docker Desktop 4.0+ với Kubernetes enabled
|
||||
- kubectl CLI
|
||||
- kind CLI (để load images vào cluster)
|
||||
- pnpm 8+
|
||||
## Tổng Quan / Overview
|
||||
|
||||
### Kiến Thức
|
||||
- Hiểu cơ bản về Kubernetes (Pods, Deployments, Services)
|
||||
- Quen thuộc với Docker và containerization
|
||||
- Biết cách sử dụng terminal/command line
|
||||
Hướng dẫn này mô tả chi tiết cách deploy IAM Service (hoặc bất kỳ microservice nào trong hệ sinh thái GoodGo) lên local Kubernetes cluster sử dụng Docker Desktop trên macOS.
|
||||
|
||||
## Bước 1: Chuẩn Bị Môi Trường
|
||||
> **Lưu ý quan trọng**: Hướng dẫn này giả định bạn đang sử dụng **Docker Desktop** với **Kubernetes enabled**. Nếu bạn sử dụng Minikube hoặc Kind thuần, các bước có thể hơi khác một chút (đặc biệt là phần load image).
|
||||
|
||||
### 1.1 Enable Kubernetes trong Docker Desktop
|
||||
## 1. Yêu Cầu / Prerequisites
|
||||
|
||||
1. Mở **Docker Desktop**
|
||||
2. Vào **Settings → Kubernetes**
|
||||
3. Check **Enable Kubernetes**
|
||||
4. Chọn cluster provisioning:
|
||||
- **kind** (recommended cho development)
|
||||
- hoặc **kubeadm**
|
||||
5. Click **Apply & Restart**
|
||||
6. Đợi 2-3 phút để Kubernetes khởi động
|
||||
### Phần Mềm / Software
|
||||
- **Docker Desktop 4.0+**: [Download Link](https://www.docker.com/products/docker-desktop/)
|
||||
- Kubernetes phải được enable trong settings.
|
||||
- **kubectl CLI**: Công cụ dòng lệnh để tương tác với K8s.
|
||||
```bash
|
||||
brew install kubectl
|
||||
```
|
||||
- **kind CLI**: Cần thiết để load images vào cluster nếu dùng Kind backend (mặc định cho dev).
|
||||
```bash
|
||||
brew install kind
|
||||
```
|
||||
- **pnpm 8+**: Package manager của dự án.
|
||||
```bash
|
||||
npm install -g pnpm
|
||||
```
|
||||
|
||||
### 1.2 Verify Kubernetes
|
||||
### Kiến Thức / Knowledge
|
||||
- Hiểu cơ bản về các khái niệm Kubernetes: **Pod**, **Deployment**, **Service**, **Secret**, **ConfigMap**.
|
||||
- Quen thuộc với các lệnh Docker cơ bản (`docker build`, `docker images`).
|
||||
- Biết cách điều hướng và chạy lệnh trong Terminal.
|
||||
|
||||
## 2. Chuẩn Bị Môi Trường / Environment Preparation
|
||||
|
||||
### 2.1 Enable Kubernetes trong Docker Desktop
|
||||
|
||||
1. Mở **Docker Desktop**.
|
||||
2. Nhấn vào biểu tượng **Settings (⚙️)**.
|
||||
3. Chọn tab **Kubernetes**.
|
||||
4. Check vào ô **Enable Kubernetes**.
|
||||
5. Chọn **Show system containers (advanced)** để dễ debug (tùy chọn).
|
||||
6. Nhấn **Apply & Restart**.
|
||||
7. Đợi 2-3 phút cho đến khi icon Kubernetes ở góc dưới chuyển sang màu xanh lá.
|
||||
|
||||
### 2.2 Verify Kubernetes Connection
|
||||
|
||||
Kiểm tra xem `kubectl` đã kết nối đúng context chưa:
|
||||
|
||||
```bash
|
||||
# Check kubectl context
|
||||
# EN: Check current context
|
||||
# VI: Kiểm tra context hiện tại
|
||||
kubectl config current-context
|
||||
# Output: docker-desktop
|
||||
# Output mong đợi: docker-desktop
|
||||
|
||||
# Check nodes
|
||||
# EN: List all nodes in the cluster
|
||||
# VI: Liệt kê các node trong cluster
|
||||
kubectl get nodes
|
||||
# Output: docker-desktop Ready control-plane ...
|
||||
|
||||
# Check kind cluster name (nếu dùng kind)
|
||||
kind get clusters
|
||||
# Output: desktop
|
||||
# Output mong đợi:
|
||||
# NAME STATUS ROLES AGE VERSION
|
||||
# docker-desktop Ready control-plane 10m v1.29.1
|
||||
```
|
||||
|
||||
### 1.3 Install kind CLI
|
||||
## 3. Build Docker Image
|
||||
|
||||
Chúng ta cần build image của service trước khi deploy. Ở đây lấy ví dụ là `iam-service`.
|
||||
|
||||
```bash
|
||||
# Install kind
|
||||
brew install kind
|
||||
|
||||
# Verify installation
|
||||
kind version
|
||||
```
|
||||
|
||||
## Bước 2: Build Docker Image
|
||||
|
||||
```bash
|
||||
# Di chuyển đến thư mục deployments
|
||||
# EN: Navigate to the kubernetes deployment directory
|
||||
# VI: Di chuyển đến thư mục deployments/local/kubernetes
|
||||
cd deployments/local/kubernetes
|
||||
|
||||
# Build image (script tự động build)
|
||||
# EN: Build the Docker image from the root context
|
||||
# VI: Build Docker image từ root context
|
||||
# Lưu ý: -f trỏ đến Dockerfile của service, context là root (../../..)
|
||||
docker build -t iam-service:local -f ../../../services/iam-service/Dockerfile ../../..
|
||||
|
||||
# Verify image
|
||||
# EN: Verify the image was built successfully
|
||||
# VI: Kiểm tra image đã build thành công chưa
|
||||
docker images | grep iam-service
|
||||
# Output: iam-service:local ... 1.67GB
|
||||
# Output mong đợi:
|
||||
# iam-service local [IMAGE_ID] [SIZE] [CREATED]
|
||||
```
|
||||
|
||||
## Bước 3: Load Image vào Kubernetes Cluster
|
||||
## 4. Load Image vào Cluster
|
||||
|
||||
**⚠️ Quan Trọng**: Docker Desktop Kubernetes với kind backend **không tự động share images** với Docker Desktop. Bạn phải load image vào cluster:
|
||||
**⚠️ QUAN TRỌNG / IMPORTANT**: Docker Desktop có thể sử dụng các backend khác nhau. Nếu bạn đang chạy Kubernetes trong Docker Desktop, đôi khi nó không nhìn thấy image local ngay lập tức nếu sử dụng `kind` node dưới nền.
|
||||
|
||||
Nếu bạn dùng **Kind** (Kubernetes in Docker) riêng biệt hoặc cấu hình Docker Desktop đặc biệt, bạn cần load image:
|
||||
|
||||
```bash
|
||||
# Load image vào kind cluster
|
||||
# EN: Load image into kind cluster (if using kind explicitly)
|
||||
# VI: Load image vào kind cluster (nếu dùng kind rõ ràng)
|
||||
kind load docker-image iam-service:local --name desktop
|
||||
|
||||
# Đợi quá trình hoàn tất (có thể mất 1-2 phút)
|
||||
# EN: Validating image presence (optional, hard with Docker Desktop K8s directly)
|
||||
# VI: Kiểm tra sự tồn tại của image (tùy chọn)
|
||||
```
|
||||
|
||||
**Lưu ý**: Nếu dùng kubeadm thay vì kind, bạn có thể skip bước này vì kubeadm share images tốt hơn.
|
||||
> **Mẹo**: Với Docker Desktop mặc định, việc build image local (`docker build ...`) thường tự động khả dụng cho K8s cluster của Docker Desktop. Bước load này chủ yếu dành cho ai dùng `kind` CLI để tạo cluster riêng.
|
||||
|
||||
## Bước 4: Cấu Hình Secrets
|
||||
## 5. Cấu Hình Secrets & ConfigMap
|
||||
|
||||
### 4.1 Chuẩn Bị Environment Variables
|
||||
Môi trường Kubernetes cần các biến môi trường nhạy cảm (Secrets) và cấu hình chung (ConfigMap).
|
||||
|
||||
Tạo file `.env.k8s` với các biến sau:
|
||||
### 5.1 Tạo Secrets (Thủ công)
|
||||
|
||||
Bạn có thể chạy script hoặc lệnh sau để tạo secrets an toàn.
|
||||
|
||||
```bash
|
||||
# Database
|
||||
DATABASE_URL=postgresql://user:password@host:5432/database?sslmode=require
|
||||
|
||||
# JWT Secrets (PHẢI thay đổi trong production!)
|
||||
JWT_SECRET=your-strong-jwt-secret-min-32-chars
|
||||
JWT_REFRESH_SECRET=your-strong-refresh-secret-min-32-chars
|
||||
JWT_ID_SECRET=your-strong-id-secret-min-32-chars
|
||||
|
||||
# Encryption (optional)
|
||||
ENCRYPTION_KEY=your-32-char-encryption-key-here
|
||||
```
|
||||
|
||||
### 4.2 Tạo Kubernetes Secrets
|
||||
|
||||
Script `deploy.sh` sẽ tự động tạo secrets, hoặc bạn có thể tạo thủ công:
|
||||
|
||||
```bash
|
||||
# Tạo namespace
|
||||
# EN: Create a dedicated namespace for local testing
|
||||
# VI: Tạo namespace riêng cho local testing
|
||||
kubectl create namespace iam-local
|
||||
|
||||
# Tạo secrets
|
||||
# EN: Generate random secrets and store in Kubernetes
|
||||
# VI: Tạo secrets ngẫu nhiên và lưu vào Kubernetes
|
||||
kubectl create secret generic iam-service-secrets \
|
||||
--from-literal=DATABASE_URL="postgresql://..." \
|
||||
--from-literal=DATABASE_URL="postgresql://user:password@host.docker.internal:5432/iam_db?schema=public" \
|
||||
--from-literal=JWT_SECRET="$(openssl rand -base64 32)" \
|
||||
--from-literal=JWT_REFRESH_SECRET="$(openssl rand -base64 32)" \
|
||||
--from-literal=JWT_ID_SECRET="$(openssl rand -base64 32)" \
|
||||
--from-literal=ENCRYPTION_KEY="$(openssl rand -base64 32)" \
|
||||
-n iam-local
|
||||
|
||||
# Verify secrets
|
||||
# EN: Verify secrets creation
|
||||
# VI: Kiểm tra secrets đã tạo
|
||||
kubectl get secrets -n iam-local
|
||||
```
|
||||
|
||||
## Bước 5: Deploy Service
|
||||
> **Lưu ý về `host.docker.internal`**: Trên macOS, để pod trong K8s kết nối được với PostgreSQL chạy trên máy host (hoặc container khác qua port mapping), ta dùng `host.docker.internal`.
|
||||
|
||||
### 5.1 Sử Dụng Script Tự Động
|
||||
### 5.2 ConfigMap
|
||||
|
||||
File `iam-service-configmap.yaml` thường chứa các biến không nhạy cảm như `NODE_ENV`, `LOG_LEVEL`.
|
||||
|
||||
```bash
|
||||
cd deployments/local/kubernetes
|
||||
|
||||
# Run deployment script
|
||||
./deploy.sh
|
||||
|
||||
# Script sẽ:
|
||||
# 1. Tạo namespace
|
||||
# 2. Tạo secrets
|
||||
# 3. Apply ConfigMap
|
||||
# 4. Build Docker image
|
||||
# 5. Deploy service
|
||||
# EN: Apply ConfigMap
|
||||
# VI: Apply ConfigMap
|
||||
kubectl apply -f iam-service-configmap.yaml -n iam-local
|
||||
```
|
||||
|
||||
### 5.2 Deploy Thủ Công
|
||||
## 6. Deploy Service
|
||||
|
||||
Bây giờ chúng ta sẽ deploy các resource chính.
|
||||
|
||||
```bash
|
||||
# Apply ConfigMap
|
||||
kubectl apply -f iam-service-configmap.yaml
|
||||
# EN: Apply Deployment manifest
|
||||
# VI: Apply file Deployment manifest
|
||||
kubectl apply -f iam-service-deployment.yaml -n iam-local
|
||||
|
||||
# Apply Deployment
|
||||
kubectl apply -f iam-service-deployment.yaml
|
||||
|
||||
# Apply Service
|
||||
kubectl apply -f iam-service-service.yaml
|
||||
# EN: Apply Service manifest (LoadBalancer/NodePort)
|
||||
# VI: Apply file Service manifest
|
||||
kubectl apply -f iam-service-service.yaml -n iam-local
|
||||
```
|
||||
|
||||
## Bước 6: Verify Deployment
|
||||
## 7. Verify & Debug / Kiểm Tra & Gỡ Lỗi
|
||||
|
||||
### 6.1 Check Pod Status
|
||||
Sau khi deploy, cần đảm bảo Pod đang chạy ổn định (Running).
|
||||
|
||||
### 7.1 Kiểm tra Pods
|
||||
|
||||
```bash
|
||||
# Xem pods
|
||||
# EN: Get all pods in the namespace
|
||||
# VI: Lấy danh sách pod trong namespace
|
||||
kubectl get pods -n iam-local
|
||||
|
||||
# Output mong đợi:
|
||||
# NAME READY STATUS RESTARTS AGE
|
||||
# iam-service-68994fdc79-gh2mj 1/1 Running 0 2m
|
||||
# iam-service-68994fdc79-gh2mj 1/1 Running 0 30s
|
||||
```
|
||||
|
||||
### 6.2 Check Logs
|
||||
### 7.2 Xem Logs Chi Tiết
|
||||
|
||||
Nếu Status không phải `Running` (ví dụ `CrashLoopBackOff` hoặc `ImagePullBackOff`), hãy xem logs:
|
||||
|
||||
```bash
|
||||
# Xem logs
|
||||
# EN: Stream logs from the pod
|
||||
# VI: Xem logs thời gian thực từ pod
|
||||
kubectl logs -f -n iam-local -l app=iam-service
|
||||
|
||||
# Logs thành công:
|
||||
# [iam-service] Database connected successfully
|
||||
# [iam-service] Service started on port 5001
|
||||
# EN: Describe pod to see events (pull error, mounts, scheduling)
|
||||
# VI: Xem chi tiết pod để check events (lỗi pull, mount, scheduling)
|
||||
kubectl describe pod -n iam-local -l app=iam-service
|
||||
```
|
||||
|
||||
### 6.3 Check Service
|
||||
### 7.3 Common Errors / Lỗi Thường Gặp
|
||||
|
||||
1. **ImagePullBackOff**:
|
||||
- **Lý do**: K8s không tìm thấy image `iam-service:local`.
|
||||
- **Fix**: Đảm bảo `imagePullPolicy: IfNotPresent` hoặc `Never` trong file yaml deployment local. Nếu dùng Kind, nhớ chạy lệnh `kind load`.
|
||||
|
||||
2. **CrashLoopBackOff**:
|
||||
- **Lý do**: Lỗi runtime, thường là không kết nối được Database.
|
||||
- **Fix**: Check biến `DATABASE_URL` trong Secret. Đảm bảo Postgres đang chạy và accessible từ K8s (dùng `host.docker.internal`).
|
||||
|
||||
3. **Pending Service**:
|
||||
- **Lý do**: Type `LoadBalancer` trên local đôi khi mãi pending IP.
|
||||
- **Fix**: Không sao cả, chúng ta có thể dùng `port-forward` hoặc truy cập qua `localhost`.
|
||||
|
||||
## 8. Test Service Access
|
||||
|
||||
Để truy cập service từ máy local, cách an toàn nhất là dùng `port-forward`.
|
||||
|
||||
```bash
|
||||
# Xem services
|
||||
kubectl get svc -n iam-local
|
||||
|
||||
# Output:
|
||||
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
|
||||
# iam-service LoadBalancer 10.96.187.160 <pending> 80:30577/TCP
|
||||
```
|
||||
|
||||
**Lưu ý**: `EXTERNAL-IP` sẽ là `<pending>` vì local cluster không có cloud load balancer.
|
||||
|
||||
## Bước 7: Test Service
|
||||
|
||||
### 7.1 Port Forward
|
||||
|
||||
```bash
|
||||
# Forward port để access service
|
||||
# EN: Port forward from local port 5002 to service port 80
|
||||
# VI: Port forward từ cổng local 5002 tới cổng 80 của service
|
||||
kubectl port-forward svc/iam-service 5002:80 -n iam-local
|
||||
|
||||
# Service sẽ available tại http://localhost:5002
|
||||
# Terminal sẽ treo và hiện: Forwarding from 127.0.0.1:5002 -> 8000
|
||||
```
|
||||
|
||||
### 7.2 Test Health Endpoints
|
||||
Mở terminal khác và test:
|
||||
|
||||
```bash
|
||||
# Test liveness probe
|
||||
# EN: Test Health Check
|
||||
# VI: Test Health Check
|
||||
curl http://localhost:5002/health/live
|
||||
# Response: {"status":"ok", ...}
|
||||
|
||||
# Response:
|
||||
# {
|
||||
# "success": true,
|
||||
# "data": {"status": "live"},
|
||||
# "timestamp": "2026-01-04T06:04:03.425Z"
|
||||
# }
|
||||
|
||||
# Test readiness probe
|
||||
curl http://localhost:5002/health/ready
|
||||
|
||||
# Test API docs
|
||||
# EN: View Swagger/OpenAPI docs (if enabled)
|
||||
# VI: Xem tài liệu Swagger/OpenAPI (nếu bật)
|
||||
open http://localhost:5002/api-docs
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
## 9. Cleanup / Dọn Dẹp
|
||||
|
||||
### Issue 1: ImagePullBackOff
|
||||
|
||||
**Triệu chứng**:
|
||||
```bash
|
||||
kubectl get pods -n iam-local
|
||||
# NAME READY STATUS RESTARTS AGE
|
||||
# iam-service-6b8fbb574d-hn27z 0/1 ImagePullBackOff 0 2m
|
||||
```
|
||||
|
||||
**Nguyên nhân**: kind cluster không thể tìm thấy image `iam-service:local`
|
||||
|
||||
**Giải pháp**:
|
||||
```bash
|
||||
# Load image vào kind cluster
|
||||
kind load docker-image iam-service:local --name desktop
|
||||
|
||||
# Restart deployment
|
||||
kubectl rollout restart deployment/iam-service -n iam-local
|
||||
```
|
||||
|
||||
### Issue 2: CrashLoopBackOff
|
||||
|
||||
**Triệu chứng**:
|
||||
```bash
|
||||
kubectl get pods -n iam-local
|
||||
# NAME READY STATUS RESTARTS AGE
|
||||
# iam-service-xxx 0/1 CrashLoopBackOff 5 5m
|
||||
```
|
||||
|
||||
**Nguyên nhân**: Service crash khi start
|
||||
|
||||
**Debug**:
|
||||
```bash
|
||||
# Xem logs
|
||||
kubectl logs -n iam-local -l app=iam-service --tail=50
|
||||
|
||||
# Describe pod
|
||||
kubectl describe pod -n iam-local -l app=iam-service
|
||||
```
|
||||
|
||||
**Giải pháp phổ biến**:
|
||||
- Check DATABASE_URL trong secrets
|
||||
- Verify Prisma migrations đã chạy
|
||||
- Check environment variables trong ConfigMap
|
||||
|
||||
### Issue 3: Database Connection Failed
|
||||
|
||||
**Triệu chứng**: Logs hiển thị `Database connection error`
|
||||
|
||||
**Giải pháp**:
|
||||
```bash
|
||||
# Verify DATABASE_URL
|
||||
kubectl get secret iam-service-secrets -n iam-local -o jsonpath='{.data.DATABASE_URL}' | base64 -d
|
||||
|
||||
# Test connection từ pod
|
||||
kubectl exec -it -n iam-local deployment/iam-service -- sh
|
||||
# Inside pod:
|
||||
# npx prisma db push
|
||||
```
|
||||
|
||||
### Issue 4: Redis Connection Errors
|
||||
|
||||
**Triệu chứng**: Logs hiển thị `Redis connection error`
|
||||
|
||||
**Nguyên nhân**: Redis chưa được deploy trong cluster
|
||||
|
||||
**Giải pháp** (optional - chỉ nếu cần Redis):
|
||||
```bash
|
||||
# Deploy Redis
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: redis
|
||||
namespace: iam-local
|
||||
spec:
|
||||
serviceName: redis
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis
|
||||
namespace: iam-local
|
||||
spec:
|
||||
selector:
|
||||
app: redis
|
||||
ports:
|
||||
- port: 6379
|
||||
EOF
|
||||
|
||||
# Update ConfigMap với REDIS_HOST=redis
|
||||
kubectl edit configmap iam-service-config -n iam-local
|
||||
|
||||
# Restart deployment
|
||||
kubectl rollout restart deployment/iam-service -n iam-local
|
||||
```
|
||||
|
||||
## Debugging Commands
|
||||
Khi hoàn tất, hãy xóa resources để giải phóng tài nguyên.
|
||||
|
||||
```bash
|
||||
# Xem tất cả resources
|
||||
kubectl get all -n iam-local
|
||||
|
||||
# Describe deployment
|
||||
kubectl describe deployment iam-service -n iam-local
|
||||
|
||||
# Describe pod
|
||||
kubectl describe pod -n iam-local -l app=iam-service
|
||||
|
||||
# Xem events
|
||||
kubectl get events -n iam-local --sort-by='.lastTimestamp'
|
||||
|
||||
# Exec vào pod
|
||||
kubectl exec -it -n iam-local deployment/iam-service -- sh
|
||||
|
||||
# Xem logs realtime
|
||||
kubectl logs -f -n iam-local -l app=iam-service
|
||||
|
||||
# Xem logs từ container trước (nếu pod restart)
|
||||
kubectl logs -n iam-local -l app=iam-service --previous
|
||||
```
|
||||
|
||||
## Cleanup
|
||||
|
||||
```bash
|
||||
# Xóa deployment
|
||||
kubectl delete -f iam-service-deployment.yaml
|
||||
kubectl delete -f iam-service-service.yaml
|
||||
kubectl delete -f iam-service-configmap.yaml
|
||||
|
||||
# Xóa secrets
|
||||
kubectl delete secret iam-service-secrets -n iam-local
|
||||
|
||||
# Xóa namespace (xóa tất cả)
|
||||
# EN: Delete the namespace (removes all resources within)
|
||||
# VI: Xóa namespace (xóa tất cả resource bên trong)
|
||||
kubectl delete namespace iam-local
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Deploy Redis** (optional): Để enable caching và rate limiting
|
||||
2. **Setup Ingress**: Để expose service ra ngoài
|
||||
3. **Configure HPA**: Horizontal Pod Autoscaler cho auto-scaling
|
||||
4. **Add Monitoring**: Prometheus + Grafana
|
||||
5. **Setup CI/CD**: Tự động deploy khi có code changes
|
||||
|
||||
## Resources
|
||||
## Tài Liệu Tham Khảo / References
|
||||
|
||||
- [Kubernetes Documentation](https://kubernetes.io/docs/)
|
||||
- [Docker Desktop Kubernetes](https://docs.docker.com/desktop/kubernetes/)
|
||||
- [kind Documentation](https://kind.sigs.k8s.io/)
|
||||
- [kubectl Cheat Sheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/)
|
||||
- [Local Kubernetes README](../../../deployments/local/kubernetes/README.md)
|
||||
- [Docker Desktop for Mac](https://docs.docker.com/desktop/mac/networking/)
|
||||
- [Prisma Deployment Guide](https://www.prisma.io/docs/guides/deployment/deployment-guides/deploying-to-kubernetes)
|
||||
|
||||
@@ -1,756 +1,250 @@
|
||||
# Hướng Dẫn Development Local
|
||||
# Hướng Dẫn Phát Triển Local (Local Development)
|
||||
|
||||
Hướng dẫn chi tiết cách chạy và phát triển dự án trên máy local với hot reload real-time.
|
||||
> **EN**: Local Development Guide
|
||||
>
|
||||
> **VI**: Hướng dẫn phát triển cục bộ
|
||||
|
||||
## Yêu Cầu Hệ Thống
|
||||
**Cập nhật**: 2026-01-05
|
||||
**Độ khó**: Trung bình (Intermediate)
|
||||
**Thời gian thiết lập**: 15-30 phút
|
||||
|
||||
- **Node.js**: >= 20.0.0
|
||||
- **PNPM**: >= 8.0.0
|
||||
- **Docker & Docker Compose**: Phiên bản mới nhất
|
||||
- **Git**: Để clone repository
|
||||
- **Tài khoản Neon**: https://neon.tech (cho database)
|
||||
## Workflow / Quy Trình
|
||||
|
||||
## Bắt Đầu Nhanh (Khuyến Nghị)
|
||||
```mermaid
|
||||
graph TD
|
||||
Start([Bắt đầu / Start]) --> Prerequisites[1. Yêu cầu Hệ thống<br/>Prerequisites]
|
||||
Prerequisites --> Clone[2. Clone & Install]
|
||||
Clone --> Env[3. Cấu hình Environment<br/>(Shared & Service-Specific)]
|
||||
Env --> DB[4. Setup Database<br/>(Migrate & Seed)]
|
||||
DB --> Run[5. Chạy Dự án<br/>(Native/Docker/Hybrid)]
|
||||
Run --> Dev[6. Development Loop<br/>(Watch Mode)]
|
||||
Dev --> Test[7. Testing & Verify]
|
||||
Test --> End([Hoàn tất / Complete])
|
||||
|
||||
1. **Clone Repository**:
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
```
|
||||
subgraph "Các Chế độ Chạy / Run Modes"
|
||||
Run --> Mode1[Cách 1: Native (Nhanh nhất)]
|
||||
Run --> Mode2[Cách 2: Hybrid (Linh hoạt)]
|
||||
Run --> Mode3[Cách 3: Full Docker (Production-like)]
|
||||
end
|
||||
|
||||
2. **Chạy Script Khởi Tạo**:
|
||||
```bash
|
||||
./scripts/setup/init-project.sh
|
||||
```
|
||||
Script này sẽ cài đặt dependencies, tạo clients, và thiết lập các file môi trường.
|
||||
|
||||
## Thiết Lập Thủ Công
|
||||
|
||||
|
||||
### 1. Clone Repository
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
style Start fill:#d4edda,stroke:#28a745,stroke-width:2px
|
||||
style End fill:#d4edda,stroke:#28a745,stroke-width:2px
|
||||
style Env fill:#fff3cd,stroke:#ffc107
|
||||
style DB fill:#fff3cd,stroke:#ffc107
|
||||
style Run fill:#cce5ff,stroke:#007bff
|
||||
```
|
||||
|
||||
### 2. Cài Đặt Dependencies
|
||||
## Tổng Quan / Overview
|
||||
|
||||
Hướng dẫn này cung cấp quy trình chi tiết để thiết lập môi trường phát triển (development environment) cho hệ sinh thái GoodGo Microservices. Bạn sẽ học cách chạy các service, thiết lập cơ sở dữ liệu và quy trình làm việc hiệu quả với hot-reload.
|
||||
|
||||
## 1. Yêu Cầu Hệ Thống / Prerequisites
|
||||
|
||||
Trước khi bắt đầu, đảm bảo máy của bạn đã cài đặt các công cụ sau:
|
||||
|
||||
- **Node.js**: Phiên bản LTS mới nhất (v20+).
|
||||
- **PNPM**: Package manager chính của dự án (`npm install -g pnpm`).
|
||||
- **Docker Desktop**: Cần thiết để chạy các dịch vụ hạ tầng (Redis, Database local).
|
||||
- **Git**: Để quản lý mã nguồn.
|
||||
- **Neon Account** (Tùy chọn): Nếu sử dụng Neon Database trên cloud (khuyên dùng cho dev).
|
||||
|
||||
## 2. Cài Đặt Ban Đầu / Initial Setup
|
||||
|
||||
### 2.1 Clone và Cài Đặt Dependencies
|
||||
|
||||
```bash
|
||||
# EN: Clone the repository
|
||||
# VI: Clone repository về máy
|
||||
git clone <repository-url>
|
||||
cd Base
|
||||
|
||||
# EN: Install dependencies using pnpm
|
||||
# VI: Cài đặt các thư viện phụ thuộc bằng pnpm
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 3. Thiết Lập Environment Variables
|
||||
### 2.2 Script Khởi Tạo Nhanh (Khuyến nghị)
|
||||
|
||||
Dự án sử dụng **Hybrid Environment Configuration**:
|
||||
- **Shared configs** (JWT secrets, Redis): `deployments/local/.env.local`
|
||||
- **Service-specific configs** (DATABASE_URL, PORT): `services/<service>/.env.local`
|
||||
|
||||
#### 3.1. Tạo Shared Environment File
|
||||
Dự án có script tự động hóa các bước khởi tạo cơ bản:
|
||||
|
||||
```bash
|
||||
# EN: Run initialization script
|
||||
# VI: Chạy script khởi tạo
|
||||
./scripts/setup/init-project.sh
|
||||
```
|
||||
|
||||
> Script này sẽ:
|
||||
> - Cài đặt dependencies.
|
||||
> - Copy các file môi trường mẫu (`.env.example` -> `.env`).
|
||||
> - Tạo Prisma client.
|
||||
|
||||
## 3. Cấu Hình Environment / Environment Configuration
|
||||
|
||||
Dự án sử dụng chiến lược **Hybrid Environment** để tối ưu hóa việc quản lý cấu hình:
|
||||
|
||||
### 3.1 Shared Configuration (Cấu hình chung)
|
||||
|
||||
File: `deployments/local/.env.local`
|
||||
Chứa các biến dùng chung cho toàn bộ hệ thống (JWT, Redis, Logging).
|
||||
|
||||
```bash
|
||||
# EN: Create shared env file from example
|
||||
# VI: Tạo file môi trường chung từ file mẫu
|
||||
cp deployments/local/env.local.example deployments/local/.env.local
|
||||
```
|
||||
|
||||
File này chứa configs dùng chung cho tất cả services:
|
||||
### 3.2 Service-Specific Configuration (Cấu hình riêng)
|
||||
|
||||
Mỗi service (ví dụ `iam-service`) cần file `.env.local` riêng chứa thông tin đặc thù như Database URL và Port.
|
||||
|
||||
```bash
|
||||
# JWT Secrets - MUST be same across all services
|
||||
JWT_SECRET=dev-jwt-secret-change-in-production-min-32-chars
|
||||
JWT_REFRESH_SECRET=dev-refresh-secret-change-in-production-min-32-chars
|
||||
|
||||
# Redis (Docker)
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
|
||||
# Common configs
|
||||
NODE_ENV=development
|
||||
LOG_LEVEL=debug
|
||||
CORS_ORIGIN=http://localhost:3000,http://localhost:3001
|
||||
```
|
||||
|
||||
#### 3.2. Tạo Service-Specific Environment File
|
||||
|
||||
Mỗi service cần file `.env.local` riêng cho DATABASE_URL và configs cụ thể:
|
||||
|
||||
```bash
|
||||
# Ví dụ: Auth Service
|
||||
# EN: Create service-specific env file
|
||||
# VI: Tạo file môi trường riêng cho service
|
||||
cp services/iam-service/env.local.example services/iam-service/.env.local
|
||||
```
|
||||
|
||||
Chỉnh sửa `services/iam-service/.env.local`:
|
||||
**Nội dung quan trọng cần chú ý trong `services/iam-service/.env.local`**:
|
||||
|
||||
```bash
|
||||
# Database riêng cho iam-service
|
||||
DATABASE_URL=postgresql://user:password@ep-xxx.region.neon.tech/goodgo_auth_dev?sslmode=require&pgbouncer=true
|
||||
```properties
|
||||
# Database URL (Sử dụng Neon Tech hoặc Local Postgres)
|
||||
DATABASE_URL=postgresql://user:password@host:5432/db_name?sslmode=require
|
||||
|
||||
# Service configs
|
||||
# Port của Service (Mỗi service phải khác nhau)
|
||||
PORT=5001
|
||||
|
||||
# Tên Service
|
||||
SERVICE_NAME=iam-service
|
||||
|
||||
# Redis override (native dev - Redis in Docker)
|
||||
# Redis Host (localhost cho Native Dev, redis cho Docker Dev)
|
||||
REDIS_HOST=localhost
|
||||
```
|
||||
|
||||
**Lưu ý**:
|
||||
- Mỗi service có **database riêng** (microservices pattern)
|
||||
- JWT secrets **phải giống nhau** để services verify tokens của nhau
|
||||
- Xem [Hướng Dẫn Neon Database](neon-database.md) để tạo databases
|
||||
## 4. Setup Database
|
||||
|
||||
### 4. Chạy Database Migrations
|
||||
Sau khi cấu hình `DATABASE_URL`, bạn cần đồng bộ schema và tạo dữ liệu mẫu.
|
||||
|
||||
```bash
|
||||
# EN: Run migrations for iam-service
|
||||
# VI: Chạy migration cho iam-service
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
### 5. Seed Database (Tùy chọn)
|
||||
|
||||
```bash
|
||||
# EN: Seed initial data (optional)
|
||||
# VI: Tạo dữ liệu mẫu (tùy chọn)
|
||||
./scripts/db/seed.sh iam-service
|
||||
```
|
||||
|
||||
## Các Cách Chạy Dự Án
|
||||
## 5. Các Chế Độ Chạy / Run Modes
|
||||
|
||||
### Cách 1: Chạy Tất Cả Services (Khuyến nghị)
|
||||
Bạn có thể chạy dự án theo 3 cách tùy thuộc vào nhu cầu:
|
||||
|
||||
Cách này phù hợp khi bạn làm full-stack hoặc cần test toàn bộ hệ thống:
|
||||
### Cách 1: Native Development (Khuyên dùng cho Backend Dev)
|
||||
|
||||
Chạy trực tiếp trên máy host. Tốc độ cao nhất, hot-reload nhanh nhất.
|
||||
|
||||
1. **Khởi động Hạ tầng (Infrastructure)**:
|
||||
```bash
|
||||
# EN: Start Redis and Traefik in Docker background
|
||||
# VI: Khởi động Redis và Traefik chạy ngầm bằng Docker
|
||||
cd deployments/local
|
||||
docker-compose up -d redis traefik
|
||||
cd ../..
|
||||
```
|
||||
|
||||
2. **Chạy Service**:
|
||||
```bash
|
||||
# EN: Start iam-service in watch mode
|
||||
# VI: Chạy iam-service ở chế độ watch
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
```
|
||||
|
||||
### Cách 2: Hybrid Development (Linh hoạt)
|
||||
|
||||
Dùng khi bạn cần chạy nhiều service phụ trợ trong Docker, nhưng muốn dev trực tiếp 1 service chính.
|
||||
|
||||
```bash
|
||||
./scripts/dev/start-all.sh
|
||||
```
|
||||
|
||||
Script này sẽ:
|
||||
1. Kiểm tra Docker đang chạy
|
||||
2. Kiểm tra DATABASE_URL đã được cấu hình
|
||||
3. Khởi động infrastructure (Redis, Traefik)
|
||||
4. Khởi động tất cả services với hot reload
|
||||
|
||||
**Hoặc chạy thủ công:**
|
||||
|
||||
```bash
|
||||
# Bước 1: Khởi động infrastructure
|
||||
cd deployments/local
|
||||
docker-compose up -d
|
||||
cd ../..
|
||||
|
||||
# Bước 2: Khởi động tất cả services
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### Cách 2: Chạy Service Cụ Thể
|
||||
|
||||
Cách này phù hợp khi bạn chỉ làm việc với 1 service:
|
||||
|
||||
```bash
|
||||
# Sử dụng script
|
||||
./scripts/dev/start-service.sh iam-service
|
||||
|
||||
# Hoặc chạy trực tiếp
|
||||
cd services/iam-service
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### Cách 3: Hybrid - Native + Docker (Linh hoạt nhất)
|
||||
|
||||
Cách này kết hợp tốt nhất của cả hai thế giới: Infrastructure chạy Docker, services đang dev chạy native với hot reload nhanh.
|
||||
|
||||
**Phù hợp khi:**
|
||||
- Làm việc với 1-2 services cụ thể
|
||||
- Cần services khác chạy background
|
||||
- Muốn hot reload nhanh cho service đang dev
|
||||
- Tiết kiệm tài nguyên máy
|
||||
|
||||
**Setup:**
|
||||
|
||||
```bash
|
||||
# Bước 1: Khởi động infrastructure (Redis, Traefik)
|
||||
cd deployments/local
|
||||
docker-compose up -d redis traefik
|
||||
cd ../..
|
||||
|
||||
# Bước 2: Chạy service đang dev với native (hot reload nhanh)
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Bước 3: (Tùy chọn) Chạy services khác trong Docker nếu cần
|
||||
# EN: Start dependent services in Docker
|
||||
# VI: Chạy các service phụ thuộc trong Docker
|
||||
docker-compose -f deployments/local/docker-compose.yml up -d user-service payment-service
|
||||
```
|
||||
|
||||
**Ví dụ workflow thực tế:**
|
||||
|
||||
```bash
|
||||
# Scenario 1: Chỉ dev iam-service
|
||||
cd deployments/local && docker-compose up -d redis traefik && cd ../..
|
||||
# EN: Run the service you are working on natively
|
||||
# VI: Chạy service bạn đang làm việc trực tiếp trên máy
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Scenario 2: Dev iam-service + cần web-admin để test
|
||||
cd deployments/local && docker-compose up -d redis traefik && cd ../..
|
||||
pnpm --filter @goodgo/iam-service dev &
|
||||
pnpm --filter @goodgo/web-admin dev
|
||||
|
||||
# Scenario 3: Dev frontend, backend chạy Docker
|
||||
cd deployments/local && docker-compose up -d redis traefik iam-service && cd ../..
|
||||
pnpm --filter @goodgo/web-admin dev
|
||||
```
|
||||
|
||||
**Lợi ích:**
|
||||
- ⚡ Hot reload cực nhanh (1-2s) cho service đang dev
|
||||
- 💻 Tiết kiệm RAM - chỉ chạy Docker cho services cần thiết
|
||||
- 🐛 Debug dễ dàng - attach debugger trực tiếp
|
||||
- 🎯 Linh hoạt - chọn service nào chạy native, service nào chạy Docker
|
||||
### Cách 3: Full Docker (Mô phỏng Production)
|
||||
|
||||
### Cách 4: Chạy Nhóm Services
|
||||
|
||||
```bash
|
||||
# Chỉ chạy backend services
|
||||
pnpm --filter "./services/*" dev
|
||||
|
||||
# Chỉ chạy frontend apps
|
||||
pnpm --filter "./apps/*" dev
|
||||
|
||||
# Chạy service cụ thể với dependencies
|
||||
pnpm --filter @goodgo/iam-service... dev
|
||||
```
|
||||
|
||||
### Cách 5: Chạy Với Docker Compose (Full Stack)
|
||||
Chạy toàn bộ hệ thống trong Docker. Tốt cho việc kiểm tra tích hợp (Integration Test) nhưng không có hot-reload.
|
||||
|
||||
```bash
|
||||
# EN: Start everything with Docker Compose
|
||||
# VI: Chạy tất cả bằng Docker Compose
|
||||
cd deployments/local
|
||||
docker-compose up -d
|
||||
|
||||
# Xem logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Dừng services
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
**Lưu ý:** Dockerfile hiện tại là production build, không có hot reload. Phù hợp để test môi trường giống production.
|
||||
## 6. Access & Verification / Truy Cập & Kiểm Tra
|
||||
|
||||
## So Sánh Các Phương Án
|
||||
|
||||
| Tiêu chí | Cách 1: All Native | Cách 3: Hybrid | Cách 5: Full Docker |
|
||||
|----------|-------------------|----------------|---------------------|
|
||||
| **Hot Reload** | ⚡ Cực nhanh (1-2s) | ⚡ Nhanh cho service native | ❌ Không có (production build) |
|
||||
| **RAM Usage** | 💚 Thấp (~1-2GB) | 💛 Trung bình (~2-3GB) | 🔴 Cao (~3-5GB) |
|
||||
| **Debug** | ✅ Dễ nhất | ✅ Dễ (native services) | ⚠️ Khó hơn (qua container) |
|
||||
| **Setup** | 🟢 Đơn giản | 🟡 Trung bình | 🟢 Đơn giản |
|
||||
| **Giống Production** | ⚠️ Khác biệt | 🟡 Một phần | ✅ Gần giống nhất |
|
||||
| **Khi nào dùng** | Dev hàng ngày | Dev 1-2 services | Test integration/deployment |
|
||||
|
||||
**Khuyến nghị:**
|
||||
- 🎯 **90% thời gian**: Dùng **Cách 1** (All Native) - nhanh nhất, tiện nhất
|
||||
- 🔧 **Khi cần linh hoạt**: Dùng **Cách 3** (Hybrid) - chọn service nào chạy native
|
||||
- 🐳 **Test production-like**: Dùng **Cách 5** (Full Docker) - test networking, deployment
|
||||
|
||||
## Điểm Truy Cập
|
||||
|
||||
Khi các services đang chạy, bạn có thể truy cập:
|
||||
Sau khi khởi động, bạn có thể truy cập các điểm cuối sau:
|
||||
|
||||
| Service | URL | Mô tả |
|
||||
|---------|-----|-------|
|
||||
| **API Gateway** | http://localhost/api/v1 | Điểm truy cập chính qua Traefik |
|
||||
| **Auth Service** | http://localhost:5001 | Truy cập trực tiếp auth service |
|
||||
| **Auth API** | http://localhost/api/v1/auth | Auth API qua gateway |
|
||||
| **Web Admin** | http://admin.localhost hoặc http://localhost:3000 | Admin dashboard |
|
||||
| **Web Client** | http://localhost hoặc http://localhost:3001 | Client web app |
|
||||
| **Traefik Dashboard** | http://localhost:8080 | Xem routing và services |
|
||||
| **API Gateway** | `http://localhost/api/v1` | Cổng truy cập chính qua Traefik |
|
||||
| **IAM Service** | `http://localhost:5001` | Truy cập trực tiếp service |
|
||||
| **Health Check** | `http://localhost:5001/health` | Kiểm tra trạng thái service |
|
||||
| **Metrics** | `http://localhost:5001/metrics` | Prometheus metrics |
|
||||
| **API Docs** | `http://localhost:5001/api-docs` | Swagger UI |
|
||||
|
||||
## Hot Reload & Live Development
|
||||
|
||||
### Backend Services (TypeScript)
|
||||
|
||||
Backend services sử dụng `tsx watch` hoặc `nodemon` để tự động restart khi code thay đổi:
|
||||
### Kiểm tra Health Check
|
||||
|
||||
```bash
|
||||
# Trong services/iam-service/package.json
|
||||
"scripts": {
|
||||
"dev": "tsx watch src/index.ts"
|
||||
}
|
||||
# EN: Check liveness
|
||||
# VI: Kiểm tra liveness
|
||||
curl http://localhost:5001/health/live
|
||||
|
||||
# EN: Check readiness
|
||||
# VI: Kiểm tra readiness
|
||||
curl http://localhost:5001/health/ready
|
||||
```
|
||||
|
||||
**Khi bạn thay đổi:**
|
||||
- `.ts` files → Service tự động restart (1-2 giây)
|
||||
- `.env` files → Cần restart thủ công
|
||||
- `prisma/schema.prisma` → Cần chạy migration
|
||||
## 7. Troubleshooting / Xử Lý Sự Cố
|
||||
|
||||
### Frontend Apps (Next.js)
|
||||
### Port Already In Use
|
||||
|
||||
Frontend apps sử dụng Next.js Fast Refresh:
|
||||
**Lỗi**: `Error: listen EADDRINUSE: address already in use :::5001`
|
||||
|
||||
**Giải pháp**:
|
||||
```bash
|
||||
# Trong apps/web-admin/package.json
|
||||
"scripts": {
|
||||
"dev": "next dev"
|
||||
}
|
||||
```
|
||||
# EN: Find process using port 5001
|
||||
# VI: Tìm process đang chiếm port 5001
|
||||
lsof -i :5001
|
||||
|
||||
**Khi bạn thay đổi:**
|
||||
- React components → Cập nhật ngay lập tức (không reload page)
|
||||
- CSS/Tailwind → Cập nhật ngay lập tức
|
||||
- `next.config.js` → Cần restart
|
||||
|
||||
### Shared Packages
|
||||
|
||||
Khi thay đổi shared packages (trong `packages/`):
|
||||
|
||||
```bash
|
||||
# Packages tự động rebuild với Turbo watch mode
|
||||
pnpm --filter @goodgo/logger dev
|
||||
```
|
||||
|
||||
## Workflow Development Thực Tế
|
||||
|
||||
### Setup 3 Terminals (Khuyến nghị)
|
||||
|
||||
#### Option A: Development Hàng Ngày (All Native)
|
||||
|
||||
**Terminal 1: Chạy Services**
|
||||
```bash
|
||||
./scripts/dev/start-all.sh
|
||||
# Hoặc: pnpm dev
|
||||
```
|
||||
|
||||
**Terminal 2: Watch Tests**
|
||||
```bash
|
||||
# Auto-run tests khi code thay đổi
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
```
|
||||
|
||||
**Terminal 3: Development Tasks**
|
||||
```bash
|
||||
# Prisma Studio
|
||||
pnpm --filter @goodgo/iam-service prisma studio
|
||||
|
||||
# Xem logs
|
||||
./scripts/dev/logs.sh iam-service
|
||||
|
||||
# Migrations
|
||||
./scripts/db/migrate.sh iam-service dev
|
||||
```
|
||||
|
||||
#### Option B: Hybrid Development (Selective Services)
|
||||
|
||||
**Terminal 1: Infrastructure + Service đang dev**
|
||||
```bash
|
||||
# Start infrastructure
|
||||
cd deployments/local && docker-compose up -d redis traefik && cd ../..
|
||||
|
||||
# Dev service cụ thể với hot reload
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
```
|
||||
|
||||
**Terminal 2: Frontend (nếu cần)**
|
||||
```bash
|
||||
pnpm --filter @goodgo/web-admin dev
|
||||
```
|
||||
|
||||
**Terminal 3: Tools & Logs**
|
||||
```bash
|
||||
# Watch tests
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
|
||||
# Xem Docker logs
|
||||
docker logs -f redis-cache-local
|
||||
|
||||
# Quick commands
|
||||
pnpm format
|
||||
```
|
||||
|
||||
### Workflow Theo Use Case
|
||||
|
||||
#### Use Case 1: Dev Backend Service
|
||||
|
||||
```bash
|
||||
# Terminal 1
|
||||
cd deployments/local && docker-compose up -d redis traefik && cd ../..
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Terminal 2
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
|
||||
# Terminal 3
|
||||
pnpm --filter @goodgo/iam-service prisma studio
|
||||
```
|
||||
|
||||
#### Use Case 2: Dev Frontend + Backend
|
||||
|
||||
```bash
|
||||
# Terminal 1: Backend
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Terminal 2: Frontend
|
||||
pnpm --filter @goodgo/web-admin dev
|
||||
|
||||
# Terminal 3: Infrastructure
|
||||
cd deployments/local && docker-compose up -d redis traefik
|
||||
```
|
||||
|
||||
#### Use Case 3: Full Stack Development
|
||||
|
||||
```bash
|
||||
# Terminal 1: All services
|
||||
./scripts/dev/start-all.sh
|
||||
|
||||
# Terminal 2: Watch tests
|
||||
pnpm test --watch
|
||||
|
||||
# Terminal 3: Tools
|
||||
# Prisma Studio, logs, migrations, etc.
|
||||
```
|
||||
|
||||
## Kiểm Tra Health
|
||||
|
||||
### Health Endpoints
|
||||
|
||||
```bash
|
||||
# Kiểm tra API Gateway
|
||||
curl http://localhost/api/v1/health
|
||||
|
||||
# Kiểm tra Auth Service trực tiếp
|
||||
curl http://localhost:5001/health
|
||||
|
||||
# Kiểm tra Redis
|
||||
docker exec redis-cache-local redis-cli ping
|
||||
```
|
||||
|
||||
### Traefik Dashboard
|
||||
|
||||
Truy cập http://localhost:8080 để xem:
|
||||
- Tất cả routes đang hoạt động
|
||||
- Services đã đăng ký
|
||||
- Health status của services
|
||||
|
||||
## Database Development
|
||||
|
||||
### Thay Đổi Schema
|
||||
|
||||
```bash
|
||||
# 1. Chỉnh sửa prisma/schema.prisma
|
||||
# 2. Tạo và áp dụng migration
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate dev --name add_new_field
|
||||
|
||||
# 3. Prisma Client sẽ tự động regenerate
|
||||
```
|
||||
|
||||
### Reset Database (Development Only!)
|
||||
|
||||
```bash
|
||||
cd services/iam-service
|
||||
pnpm prisma migrate reset
|
||||
```
|
||||
|
||||
### Xem Database
|
||||
|
||||
```bash
|
||||
# Mở Prisma Studio
|
||||
cd services/iam-service
|
||||
pnpm prisma studio
|
||||
# Truy cập: http://localhost:5555
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
### VS Code Debugging
|
||||
|
||||
Tạo file `.vscode/launch.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug Auth Service",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "pnpm",
|
||||
"runtimeArgs": ["--filter", "@goodgo/iam-service", "dev"],
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Xem Logs Chi Tiết
|
||||
|
||||
```bash
|
||||
# Service logs
|
||||
./scripts/dev/logs.sh iam-service
|
||||
|
||||
# Docker logs
|
||||
docker logs -f iam-service-local
|
||||
docker logs -f redis-cache-local
|
||||
docker logs -f traefik-local
|
||||
|
||||
# Tất cả logs
|
||||
docker-compose -f deployments/local/docker-compose.yml logs -f
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port Đã Được Sử Dụng
|
||||
|
||||
```bash
|
||||
# Tìm process đang dùng port
|
||||
lsof -i :5001 # Auth service
|
||||
lsof -i :3000 # Web admin
|
||||
lsof -i :6379 # Redis
|
||||
lsof -i :80 # Traefik
|
||||
|
||||
# Kill process
|
||||
# EN: Kill the process
|
||||
# VI: Tắt process đó
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
### Docker Không Chạy
|
||||
### Database Connection Error
|
||||
|
||||
```bash
|
||||
# Kiểm tra Docker
|
||||
docker info
|
||||
**Lỗi**: `P1001: Can't reach database server`
|
||||
|
||||
# Khởi động Docker Desktop (macOS)
|
||||
open -a Docker
|
||||
|
||||
# Restart Docker services
|
||||
docker-compose -f deployments/local/docker-compose.yml restart
|
||||
```
|
||||
|
||||
### Database Connection Failed
|
||||
|
||||
```bash
|
||||
# Kiểm tra DATABASE_URL trong service-specific env
|
||||
cat services/iam-service/.env.local | grep DATABASE_URL
|
||||
|
||||
# Nếu chưa có file .env.local, tạo từ example
|
||||
cp services/iam-service/env.local.example services/iam-service/.env.local
|
||||
|
||||
# Chỉnh sửa DATABASE_URL với connection string từ Neon
|
||||
# DATABASE_URL=postgresql://user:pass@ep-xxx.neon.tech/goodgo_auth_dev?sslmode=require&pgbouncer=true
|
||||
|
||||
# Test connection
|
||||
cd services/iam-service
|
||||
pnpm prisma db pull
|
||||
```
|
||||
|
||||
**Lưu ý**: Mỗi service cần file `.env.local` riêng với DATABASE_URL của service đó.
|
||||
**Giải pháp**:
|
||||
- Kiểm tra lại biến `DATABASE_URL`.
|
||||
- Nếu dùng Docker Postgres local, đảm bảo container đang chạy (`docker ps`).
|
||||
- Nếu dùng Neon, kiểm tra kết nối internet.
|
||||
|
||||
### Module Not Found
|
||||
|
||||
**Lỗi**: Không tìm thấy các package nội bộ (ví dụ `@goodgo/logger`).
|
||||
|
||||
**Giải pháp**:
|
||||
```bash
|
||||
# Cleanup và reinstall
|
||||
./scripts/utils/cleanup.sh
|
||||
pnpm install
|
||||
|
||||
# Hoặc chỉ cleanup node_modules
|
||||
rm -rf node_modules
|
||||
rm -rf services/*/node_modules
|
||||
rm -rf apps/*/node_modules
|
||||
rm -rf packages/*/node_modules
|
||||
# EN: Re-install dependencies and build packages
|
||||
# VI: Cài lại dependencies và build lại packages
|
||||
pnpm install
|
||||
pnpm build
|
||||
```
|
||||
|
||||
### Hot Reload Không Hoạt Động
|
||||
## Tài Liệu Tham Khảo / References
|
||||
|
||||
```bash
|
||||
# Restart service
|
||||
# Ctrl+C để dừng, sau đó:
|
||||
pnpm dev
|
||||
|
||||
# Hoặc restart Docker container
|
||||
docker-compose -f deployments/local/docker-compose.yml restart iam-service
|
||||
```
|
||||
|
||||
## Tips & Best Practices
|
||||
|
||||
### 1. Sử Dụng Turbo Cache
|
||||
|
||||
Turbo cache giúp build nhanh hơn:
|
||||
|
||||
```bash
|
||||
# Lần đầu chạy sẽ chậm
|
||||
pnpm dev
|
||||
|
||||
# Các lần sau sẽ nhanh hơn nhờ cache
|
||||
# Cache được lưu trong node_modules/.cache/turbo
|
||||
```
|
||||
|
||||
### 2. Dev Selective Services
|
||||
|
||||
Không cần chạy tất cả nếu chỉ làm 1 service:
|
||||
|
||||
```bash
|
||||
# Chỉ chạy iam-service
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Chạy iam-service và dependencies
|
||||
pnpm --filter @goodgo/iam-service... dev
|
||||
```
|
||||
|
||||
### 3. Watch Tests
|
||||
|
||||
```bash
|
||||
# Chạy tests tự động khi code thay đổi
|
||||
pnpm --filter @goodgo/iam-service test --watch
|
||||
```
|
||||
|
||||
### 4. Format Code Tự Động
|
||||
|
||||
Cài đặt Prettier extension trong VS Code và bật format on save.
|
||||
|
||||
### 5. Sử Dụng Git Hooks
|
||||
|
||||
```bash
|
||||
# Pre-commit hook sẽ tự động format và lint
|
||||
git commit -m "feat: add new feature"
|
||||
```
|
||||
|
||||
### 6. Hybrid Development (Best of Both Worlds)
|
||||
|
||||
Kết hợp Docker và Native để tối ưu workflow:
|
||||
|
||||
```bash
|
||||
# Infrastructure luôn chạy Docker
|
||||
cd deployments/local && docker-compose up -d redis traefik
|
||||
|
||||
# Service đang dev chạy native (hot reload nhanh)
|
||||
pnpm --filter @goodgo/iam-service dev
|
||||
|
||||
# Services khác có thể chạy Docker nếu cần
|
||||
docker-compose up -d user-service payment-service
|
||||
```
|
||||
|
||||
**Lợi ích:**
|
||||
- ⚡ Hot reload nhanh nhất cho service đang làm
|
||||
- 💻 Tiết kiệm RAM - không chạy tất cả containers
|
||||
- 🐛 Debug dễ dàng - breakpoints, logs trực tiếp
|
||||
- 🎯 Linh hoạt - chọn service nào chạy native
|
||||
|
||||
### 7. Quản Lý Multiple Services
|
||||
|
||||
```bash
|
||||
# Chạy selective services với pnpm workspace
|
||||
pnpm --filter "@goodgo/iam-service" --filter "@goodgo/user-service" dev
|
||||
|
||||
# Hoặc dùng pattern
|
||||
pnpm --filter "./services/{auth,user}-service" dev
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Dự án sử dụng **Hybrid Environment Configuration** với 2 levels:
|
||||
|
||||
### Level 1: Shared Environment (`deployments/local/.env.local`)
|
||||
|
||||
Configs dùng chung cho tất cả services:
|
||||
|
||||
```bash
|
||||
# JWT Secrets - MUST be same across all services
|
||||
JWT_SECRET=dev-jwt-secret-change-in-production-min-32-chars
|
||||
JWT_REFRESH_SECRET=dev-refresh-secret-change-in-production-min-32-chars
|
||||
JWT_EXPIRES_IN=15m
|
||||
JWT_REFRESH_EXPIRES_IN=7d
|
||||
|
||||
# Redis (Docker hostname)
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
|
||||
# Common configs
|
||||
NODE_ENV=development
|
||||
LOG_LEVEL=debug
|
||||
CORS_ORIGIN=http://localhost:3000,http://localhost:3001
|
||||
|
||||
# Monitoring (optional)
|
||||
TRACING_ENABLED=false
|
||||
```
|
||||
|
||||
**Tạo file:**
|
||||
```bash
|
||||
cp deployments/local/env.local.example deployments/local/.env.local
|
||||
```
|
||||
|
||||
### Level 2: Service-Specific Environment (`services/<service>/.env.local`)
|
||||
|
||||
Configs riêng cho từng service:
|
||||
|
||||
```bash
|
||||
# services/iam-service/.env.local
|
||||
|
||||
# Database riêng cho service này
|
||||
DATABASE_URL=postgresql://user:pass@ep-xxx.neon.tech/goodgo_auth_dev?sslmode=require&pgbouncer=true
|
||||
|
||||
# Service configs
|
||||
PORT=5001
|
||||
SERVICE_NAME=iam-service
|
||||
API_VERSION=v1
|
||||
|
||||
# Redis override (native dev - Redis in Docker)
|
||||
REDIS_HOST=localhost
|
||||
|
||||
# Service-specific configs
|
||||
EMAIL_SERVICE_URL=http://notification-service:5003
|
||||
PROMETHEUS_PORT=9090
|
||||
```
|
||||
|
||||
**Tạo file:**
|
||||
```bash
|
||||
cp services/iam-service/env.local.example services/iam-service/.env.local
|
||||
```
|
||||
|
||||
### Cách Hoạt Động
|
||||
|
||||
Services load env theo thứ tự:
|
||||
1. **Shared env** (`deployments/local/.env.local`) - JWT, Redis, common configs
|
||||
2. **Service env** (`.env.local`) - DATABASE_URL, PORT, overrides
|
||||
|
||||
```bash
|
||||
# Trong package.json
|
||||
"dev": "dotenv -e ../../deployments/local/.env.local -e .env.local -- tsx watch src/main.ts"
|
||||
```
|
||||
|
||||
**Lợi ích:**
|
||||
- ✅ JWT secrets giống nhau → services verify tokens của nhau
|
||||
- ✅ Mỗi service có database riêng → microservices pattern
|
||||
- ✅ Override configs dễ dàng → REDIS_HOST=localhost cho native dev
|
||||
- ✅ Không duplicate configs → maintain dễ hơn
|
||||
|
||||
### Important Notes
|
||||
|
||||
1. **JWT Secrets**: MUST be identical across all services
|
||||
2. **Database**: Each service has its own database (e.g., `goodgo_auth_dev`, `goodgo_user_dev`)
|
||||
3. **Redis Host**:
|
||||
- `redis` (Docker hostname) in shared env
|
||||
- `localhost` (override) in service env for native dev
|
||||
4. **Never commit**: `.env.local` files are gitignored
|
||||
|
||||
## Các Lệnh Hữu Ích
|
||||
|
||||
```bash
|
||||
# Development
|
||||
pnpm dev # Chạy tất cả services
|
||||
pnpm build # Build tất cả
|
||||
pnpm test # Test tất cả
|
||||
pnpm lint # Lint tất cả
|
||||
pnpm format # Format code
|
||||
|
||||
# Cleanup
|
||||
pnpm clean # Xóa build artifacts
|
||||
./scripts/utils/cleanup.sh # Cleanup toàn bộ
|
||||
|
||||
# Database
|
||||
./scripts/db/migrate.sh iam-service dev # Migration
|
||||
./scripts/db/seed.sh iam-service # Seed data
|
||||
./scripts/db/backup.sh iam-service # Backup
|
||||
|
||||
# Docker
|
||||
docker-compose -f deployments/local/docker-compose.yml up -d # Start
|
||||
docker-compose -f deployments/local/docker-compose.yml down # Stop
|
||||
docker-compose -f deployments/local/docker-compose.yml logs -f # Logs
|
||||
docker-compose -f deployments/local/docker-compose.yml restart # Restart
|
||||
```
|
||||
|
||||
## Tài Nguyên Thêm
|
||||
|
||||
- [Getting Started](getting-started.md) - Thiết lập ban đầu
|
||||
- [Development Guide](development.md) - Quy trình development
|
||||
- [Neon Database Guide](neon-database.md) - Hướng dẫn database
|
||||
- [Troubleshooting](troubleshooting.md) - Xử lý sự cố
|
||||
- [Kubernetes Guide](kubernetes-local.md) - Triển khai lên K8s Local.
|
||||
- [Project Architecture](../../docs/vi/ARCHITECTURE.vi.md) - Tổng quan kiến trúc hệ thống.
|
||||
|
||||
Reference in New Issue
Block a user