Files
pos-system/docs/en/guides/kubernetes-local.md

8.7 KiB

Local Kubernetes Deployment Guide

Last Updated: 2026-01-04
Difficulty: Intermediate
Duration: 30-45 minutes

Overview

This guide describes how to deploy the IAM Service to a local Kubernetes cluster using Docker Desktop on macOS.

Prerequisites

Software

  • Docker Desktop 4.0+ with Kubernetes enabled
  • kubectl CLI
  • kind CLI (for loading images into cluster)
  • pnpm 8+

Knowledge

  • Basic understanding of Kubernetes (Pods, Deployments, Services)
  • Familiarity with Docker and containerization
  • Command line proficiency

Step 1: Environment Preparation

1.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.2 Verify Kubernetes

# Check kubectl context
kubectl config current-context
# Output: docker-desktop

# Check nodes
kubectl get nodes
# Output: docker-desktop   Ready    control-plane   ...

# Check kind cluster name (if using kind)
kind get clusters
# Output: desktop

1.3 Install kind CLI

# Install kind
brew install kind

# Verify installation
kind version

Step 2: Build Docker Image

# Navigate to deployments directory
cd deployments/local/kubernetes

# Build image (script auto-builds)
docker build -t iam-service:local -f ../../../services/iam-service/Dockerfile ../../..

# Verify image
docker images | grep iam-service
# Output: iam-service:local   ...   1.67GB

Step 3: Load Image into Kubernetes Cluster

⚠️ Important: Docker Desktop Kubernetes with kind backend does not automatically share images with Docker Desktop. You must load the image into the cluster:

# Load image into kind cluster
kind load docker-image iam-service:local --name desktop

# Wait for completion (may take 1-2 minutes)

Note: If using kubeadm instead of kind, you can skip this step as kubeadm shares images better.

Step 4: Configure Secrets

4.1 Prepare Environment Variables

Create .env.k8s file with the following variables:

# 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:

# Create namespace
kubectl create namespace iam-local

# Create secrets
kubectl create secret generic iam-service-secrets \
  --from-literal=DATABASE_URL="postgresql://..." \
  --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
kubectl get secrets -n iam-local

Step 5: Deploy Service

5.1 Using Automated Script

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

5.2 Manual Deployment

# Apply ConfigMap
kubectl apply -f iam-service-configmap.yaml

# Apply Deployment
kubectl apply -f iam-service-deployment.yaml

# Apply Service
kubectl apply -f iam-service-service.yaml

Step 6: Verify Deployment

6.1 Check Pod Status

# View pods
kubectl get pods -n iam-local

# Expected output:
# NAME                           READY   STATUS    RESTARTS   AGE
# iam-service-68994fdc79-gh2mj   1/1     Running   0          2m

6.2 Check Logs

# View logs
kubectl logs -f -n iam-local -l app=iam-service

# Successful logs:
# [iam-service] Database connected successfully
# [iam-service] Service started on port 5001

6.3 Check Service

# 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

# Forward port to access service
kubectl port-forward svc/iam-service 5002:80 -n iam-local

# Service will be available at http://localhost:5002

7.2 Test Health Endpoints

# Test liveness probe
curl http://localhost:5002/health/live

# 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
open http://localhost:5002/api-docs

Troubleshooting

Issue 1: ImagePullBackOff

Symptoms:

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:

# 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:

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:

# 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:

# 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):

# 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

# 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

# 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)
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