- Updated Mermaid diagrams in the deployment and development guides for better visual representation and consistency. - Improved formatting and clarity in the Kubernetes local deployment and IAM migration guides, including detailed workflows and troubleshooting sections. - Enhanced the Vietnamese documentation to align with the English version, ensuring consistency across guides. - Added quick tips and common issues sections to facilitate user navigation and understanding.
11 KiB
Local Kubernetes Deployment Guide
Last Updated: 2026-01-05 Difficulty: Intermediate Duration: 30-45 minutes
Workflow
graph TD
Start([ Start]) --> EnvPrep[1⃣ Environment Prep<br/>Enable K8s in Docker Desktop]
EnvPrep --> BuildImg[2⃣ Build Docker Image<br/>docker build -t service:local]
BuildImg --> LoadImg[3⃣ Load Image to Cluster<br/>kind load docker-image]
LoadImg --> Secrets[4⃣ Configure Secrets<br/>kubectl create secret]
Secrets --> Deploy[5⃣ Deploy Service<br/>kubectl apply -f manifests]
Deploy --> Verify[6⃣ Verify Deployment<br/>kubectl get pods]
Verify --> Test[7⃣ Test Service<br/>Port Forward & Curl]
Test --> End([ Complete])
subgraph Deployment[" Deployment Resources"]
Deploy --> |Apply| ConfigMap[ConfigMap<br/>Environment Config]
Deploy --> |Apply| K8sDeployment[Deployment<br/>Pod Template]
Deploy --> |Apply| Service[Service<br/>LoadBalancer/NodePort]
end
%% Start/End nodes - Success Green
style Start fill:#004d40,stroke:#00bfa5,stroke-width:3px,color:#e0f2f1
style End fill:#1b5e20,stroke:#66bb6a,stroke-width:3px,color:#e8f5e9
%% Workflow steps - Dark theme with distinct colors
style EnvPrep fill:#263238,stroke:#546e7a,stroke-width:2px,color:#eceff1
style BuildImg fill:#3e2723,stroke:#8d6e63,stroke-width:2px,color:#efebe9
style LoadImg fill:#1a237e,stroke:#5c6bc0,stroke-width:2px,color:#e8eaf6
style Secrets fill:#b71c1c,stroke:#ef5350,stroke-width:2px,color:#ffebee
style Deploy fill:#004d40,stroke:#26a69a,stroke-width:2px,color:#e0f2f1
style Verify fill:#1565c0,stroke:#42a5f5,stroke-width:2px,color:#e3f2fd
style Test fill:#4a148c,stroke:#ab47bc,stroke-width:2px,color:#f3e5f5
%% Deployment resources subgraph
style Deployment fill:#1a1a1a,stroke:#424242,stroke-width:2px,color:#e0e0e0
style ConfigMap fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
style K8sDeployment fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
style Service fill:#263238,stroke:#78909c,stroke-width:1px,color:#cfd8dc
Overview
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.
Important: 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+: Download Link
- Kubernetes must be enabled in settings.
- kubectl CLI: Command-line tool for interacting with K8s.
brew install kubectl
- kind CLI: Required to load images into the cluster if using Kind backend explicitely.
brew install kind
- pnpm 8+: Project package manager.
npm install -g pnpm
Knowledge
- 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.
2. Environment Preparation
2.1 Enable Kubernetes in Docker Desktop
- Open Docker Desktop.
- Click the Settings () icon.
- Select the Kubernetes tab.
- Check Enable Kubernetes.
- Select Show system containers (advanced) for easier debugging (optional).
- Click Apply & Restart.
- Wait 2-3 minutes until the Kubernetes icon in the bottom corner turns green.
2.2 Verify Kubernetes Connection
Check if kubectl is connected to the correct context:
# Check current context
kubectl config current-context
# Expected Output: docker-desktop
# List all nodes in the cluster
kubectl get nodes
# Expected Output:
# NAME STATUS ROLES AGE VERSION
# docker-desktop Ready control-plane 10m v1.29.1
3. Build Docker Image
We need to build the service image before deploying. Taking iam-service as an example.
# Navigate to the kubernetes deployment directory
cd deployments/local/kubernetes
# Build the Docker image from the root context
# Note: -f points to service Dockerfile, context is root (../../..)
docker build -t iam-service:local -f ../../../services/iam-service/Dockerfile ../../..
# Verify the image was built successfully
docker images | grep iam-service
# Expected Output:
# iam-service local [IMAGE_ID] [SIZE] [CREATED]
4. Load Image into 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:
# Load image into kind cluster (if using kind explicitly)
kind load docker-image iam-service:local --name desktop
# Validating image presence (optional, hard with Docker Desktop K8s directly)
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.
5. Configure Secrets & ConfigMap
Kubernetes environments need sensitive environment variables (Secrets) and general configuration (ConfigMap).
5.1 Create Secrets (Manually)
You can run a script or the following commands to create secrets securely.
# Create a dedicated namespace for local testing
kubectl create namespace iam-local
# Generate random secrets and store in Kubernetes
kubectl create secret generic iam-service-secrets \
--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=ENCRYPTION_KEY="$(openssl rand -base64 32)" \
-n iam-local
# Verify secrets creation
kubectl get secrets -n iam-local
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.2 ConfigMap
The iam-service-configmap.yaml file typically contains non-sensitive variables like NODE_ENV, LOG_LEVEL.
# Apply ConfigMap
kubectl apply -f iam-service-configmap.yaml -n iam-local
6. Deploy Service
Now we will deploy the main resources.
# Apply Deployment manifest
kubectl apply -f iam-service-deployment.yaml -n iam-local
# Apply Service manifest (LoadBalancer/NodePort)
kubectl apply -f iam-service-service.yaml -n iam-local
7. Verify & Debug
After deployment, ensure the Pod is stable (Running).
7.1 Check Pods
# Get all pods in the namespace
kubectl get pods -n iam-local
# Expected Output:
# NAME READY STATUS RESTARTS AGE
# iam-service-68994fdc79-gh2mj 1/1 Running 0 30s
7.2 View Detailed Logs
If Status is not Running (e.g., CrashLoopBackOff or ImagePullBackOff), check logs:
# Stream logs from the pod
kubectl logs -f -n iam-local -l app=iam-service
# Describe pod to see events (pull error, mounts, scheduling)
kubectl describe pod -n iam-local -l app=iam-service
7.3 Common Errors
- ImagePullBackOff:
- Reason: K8s cannot find
iam-service:localimage. - Fix: Ensure
imagePullPolicy: IfNotPresentorNeverin local deployment yaml. If using Kind, remember to runkind load.
- CrashLoopBackOff:
- Reason: Runtime error, usually unable to connect to Database.
- Fix: Check
DATABASE_URLin Secret. Ensure Postgres is running and accessible from K8s (usehost.docker.internal).
- Pending Service:
- Reason:
LoadBalancertype on local sometimes hangs pending IP. - Fix: Not a problem, we can use
port-forwardor access vialocalhost.
8. Test Service Access
To access the service from your local machine, the safest way is port-forward.
# Port forward from local port 5002 to service port 80
kubectl port-forward svc/iam-service 5002:80 -n iam-local
# Terminal will hang and show: Forwarding from 127.0.0.1:5002 -> 8000
Open another terminal and test:
# Test Health Check
curl http://localhost:5002/health/live
# Response: {"status":"ok", ...}
# View Swagger/OpenAPI docs (if enabled)
open http://localhost:5002/api-docs
9. Cleanup
When done, delete resources to free up capacity.
# Delete the namespace (removes all resources within)
kubectl delete namespace iam-local
Quick Tips
Common Issues & Solutions
| Issue | Symptoms | Solution |
|---|---|---|
| ImagePullBackOff | Pod stuck in ImagePullBackOff |
Set imagePullPolicy: Never in deployment YAMLRun kind load docker-image if using Kind |
| CrashLoopBackOff | Pod keeps restarting | Check logs with kubectl logsVerify DATABASE_URL in secretsEnsure DB is accessible via host.docker.internal |
| Pending LoadBalancer | Service External-IP shows <pending> |
Normal on local—use kubectl port-forward instead |
| Connection Refused | Can't connect after port-forward | Check pod is Running (not CrashLoopBackOff)Verify correct port mapping |
Essential Commands Reference
# Debugging
kubectl get pods -n iam-local -w # Watch pods in real-time
kubectl describe pod <POD_NAME> -n iam-local # Detailed pod info + events
kubectl logs -f <POD_NAME> -n iam-local # Stream logs
kubectl exec -it <POD_NAME> -n iam-local -- /bin/sh # Shell into container
# Image Management
docker build -t service:local -f Dockerfile . # Build image
kind load docker-image service:local --name desktop # Load to Kind cluster
docker images | grep service # List local images
# Quick Deployment
kubectl apply -f deployment.yaml -n iam-local # Deploy single manifest
kubectl apply -f . -n iam-local # Deploy all files in directory
kubectl rollout restart deployment/iam-service -n iam-local # Force pod restart
# Cleanup
kubectl delete pod <POD_NAME> -n iam-local --force # Force delete stuck pod
kubectl delete namespace iam-local --force --grace-period=0 # Force delete namespace
Visual Status Indicators
- Running - Service is healthy
- Pending - Waiting for resources
- CrashLoopBackOff - Service keeps failing (check logs!)
- ContainerCreating - Pod starting up
- Terminating - Pod shutting down
Pro Tips
- ** Fast Rebuild**: For quick iteration, use
kubectl rollout restart deployment/iam-service -n iam-localafter rebuilding image - ** Watch Mode**: Use
-wflag to watch resources update in real-time - ** YAML Validation**: Run
kubectl apply --dry-run=client -f file.yamlto validate before applying - ** Label Filtering**: Use
-l app=iam-serviceto filter resources by label instead of typing pod names