Deploy Node.js Application บน Kubernetes พร้อม Auto-Scaling

บทนำ

Kubernetes (K8s) ได้กลายมาเป็นมาตรฐานในการจัดการ Container Orchestration สำหรับการ Deploy Application ขนาดใหญ่ การ Auto-Scaling หรือการปรับจำนวน Pod โดยอัตโนมัติตามปริมาณคำขอเป็นหนึ่งในคุณสมบัติที่ทำให้ Kubernetes เป็นตัวเลือกที่น่าสนใจสำหรับองค์กร

บทความนี้จะอธิบายวิธีการ Deploy Node.js Application บน Kubernetes พร้อมการตั้งค่า Horizontal Pod Autoscaler (HPA) เพื่อให้ Application สามารถปรับจำนวน Pod ได้โดยอัตโนมัติตามความต้องการ

สถาปัตยกรรม Deploy Node.js บน Kubernetes

การ Deploy Node.js บน Kubernetes ประกอบด้วยขั้นตอนหลักดังนี้:

  • Dockerize Application – สร้าง Docker Image จาก Node.js Application
  • Push Image – อัปโหลด Image ไป Docker Registry
  • สร้าง Deployment – นิยาม Deployment Configuration บน Kubernetes
  • สร้าง Service – เพิ่ม Load Balancing ระหว่าง Pod
  • ตั้งค่า Ingress – ให้ Application เข้าถึงได้จากภายนอก Cluster
  • ตั้งค่า Resource Limits – กำหนด CPU/Memory ที่ Pod ต้องการ
  • ตั้งค่า HPA – ปรับจำนวน Pod โดยอัตโนมัติตามปริมาณคำขอ

สร้าง Node.js Application ตัวอย่าง

สำหรับ Demo นี้ เราจะสร้าง Node.js Application ที่เรียบง่าย:

// server.js
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.json({ 
    message: 'Hello from Node.js on Kubernetes!',
    timestamp: new Date().toISOString(),
    hostname: process.env.HOSTNAME
  });
});

app.get('/health', (req, res) => {
  res.json({ status: 'ok' });
});

app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

และ package.json:

{
  "name": "nodejs-k8s-app",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.18.2"
  }
}

สร้าง Docker Image (Dockerize)

สร้างไฟล์ Dockerfile สำหรับ Node.js Application:

# Dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install --production

COPY . .

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/health', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"

CMD ["npm", "start"]

สร้าง .dockerignore เพื่อลดขนาด Image:

node_modules
npm-debug.log
.git
.gitignore
.env
.env.local

Build และ Push Docker Image

Build Docker Image:

docker build -t your-registry/nodejs-k8s-app:1.0.0 .

Push ไป Docker Registry:

docker push your-registry/nodejs-k8s-app:1.0.0

สร้าง Kubernetes Deployment

สร้างไฟล์ deployment.yaml เพื่อ Deploy Node.js Application:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodejs-app
  labels:
    app: nodejs-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nodejs-app
  template:
    metadata:
      labels:
        app: nodejs-app
    spec:
      containers:
      - name: nodejs-app
        image: your-registry/nodejs-k8s-app:1.0.0
        imagePullPolicy: Always
        ports:
        - containerPort: 3000
          name: http
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 15
          periodSeconds: 20
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 10
          timeoutSeconds: 3
          failureThreshold: 2
        env:
        - name: NODE_ENV
          value: "production"
        - name: PORT
          value: "3000"

Apply Deployment:

kubectl apply -f deployment.yaml

สร้าง Service สำหรับ Load Balancing

สร้างไฟล์ service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: nodejs-app-service
  labels:
    app: nodejs-app
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 3000
    protocol: TCP
    name: http
  selector:
    app: nodejs-app

Apply Service:

kubectl apply -f service.yaml

ตั้งค่า Ingress Controller

สร้างไฟล์ ingress.yaml เพื่อให้ Application เข้าถึงได้จากภายนอก Cluster:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nodejs-app-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - app.yourdomain.com
    secretName: nodejs-app-tls
  rules:
  - host: app.yourdomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nodejs-app-service
            port:
              number: 80

Apply Ingress:

kubectl apply -f ingress.yaml

ตั้งค่า Resource Requests และ Limits

Resource Requests และ Limits เป็นสิ่งสำคัญสำหรับการทำ Auto-Scaling:

  • Requests – ปริมาณ CPU/Memory ที่ Pod ต้องการขั้นต่ำ
  • Limits – ปริมาณสูงสุดที่ Pod สามารถใช้ได้

ในตัวอย่างข้างต้น:

resources:
  requests:
    cpu: 100m        # 0.1 CPU cores
    memory: 128Mi    # 128 Megabytes
  limits:
    cpu: 500m        # 0.5 CPU cores
    memory: 512Mi    # 512 Megabytes

ตั้งค่า Horizontal Pod Autoscaler (HPA)

HPA จะปรับจำนวน Pod โดยอัตโนมัติตามการใช้งาน CPU สร้างไฟล์ hpa.yaml:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nodejs-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nodejs-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
      - type: Percent
        value: 100
        periodSeconds: 30
      - type: Pods
        value: 2
        periodSeconds: 30
      selectPolicy: Max

Apply HPA Configuration:

kubectl apply -f hpa.yaml

ตรวจสอบ HPA Status

ตรวจสอบสถานะ HPA:

# ดูสถานะ HPA
kubectl get hpa nodejs-app-hpa -w

# ดูรายละเอียด HPA
kubectl describe hpa nodejs-app-hpa

# ดูจำนวน Pod ปัจจุบัน
kubectl get pods -l app=nodejs-app

# ตรวจสอบ CPU Usage
kubectl top pods -l app=nodejs-app

ทดสอบ Auto-Scaling ด้วย Load Test

ใช้ Apache Bench หรือ ApacheBench สำหรับ Load Testing:

# ติดตั้ง Apache Bench
apt-get install apache2-utils  # Ubuntu/Debian
brew install httpd              # macOS

# สร้างความกดดันให้กับ Application
ab -n 10000 -c 100 http://app.yourdomain.com/

# ติดตามการเปลี่ยนแปลงจำนวน Pod
watch kubectl get hpa,deployment

# ดู Metrics ในรีอลไทม์
kubectl get hpa -w

ในระหว่างการ Load Test คุณจะเห็น:

  1. CPU Usage เพิ่มขึ้น
  2. HPA ตรวจสอบปริมาณคำขอ
  3. Kubernetes เพิ่มจำนวน Pod โดยอัตโนมัติ
  4. เมื่อคำขอลดลง Pod จะถูกลด

วิธีการเพิ่มประสิทธิภาพ

1. ใช้ Multi-Stage Dockerfile

# Stage 1: Build
FROM node:18 as builder
WORKDIR /app
COPY package*.json ./
RUN npm install

# Stage 2: Runtime
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

2. ใช้ Pod Disruption Budgets (PDB)

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: nodejs-app-pdb
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: nodejs-app

3. ใช้ Network Policies

จำกัดการเข้าถึง Pod ระหว่างกันเพื่อความปลอดภัย:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: nodejs-app-netpol
spec:
  podSelector:
    matchLabels:
      app: nodejs-app
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx
    ports:
    - protocol: TCP
      port: 3000

การติดตั้ง Metrics Server (สำหรับ HPA)

ตรวจสอบว่า Metrics Server ติดตั้งอยู่แล้ว:

kubectl get deployment metrics-server -n kube-system

ถ้ายังไม่มี ติดตั้งตามคำสั่งนี้:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

ความท้าทายและข้อพิจารณา

Startup Time

Node.js Application อาจใช้เวลาในการเริ่มต้น ตั้งค่า initialDelaySeconds อย่างเหมาะสม:

initialDelaySeconds: 30  # รอ 30 วินาที ก่อนเริ่มตรวจสอบ

Database Connection Pooling

ใช้ Connection Pooling เพื่อไม่ให้ Database Overwhelm:

const pool = mysql.createPool({
  connectionLimit: 5,
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME
});

Memory Leaks

ตรวจสอบ Memory Leaks โดยใช้ Tools เช่น Clinic.js:

npm install -g clinic
clinic doctor -- node server.js

ผลประโยชน์จากการใช้ Kubernetes บน Cloud VPS

บริการ Cloud VPS จาก Dot Enterprise ให้คุณสามารถ Deploy Kubernetes Cluster ด้วยความยืดหยุ่นสูง:

  • สามารถปรับแต่งทรัพยากร CPU/Memory ได้ตามความต้องการ
  • ราคาที่สมเหตุสมผล สำหรับการทดสอบและ Production
  • Uptime Guarantee ถึง 99.9% สำหรับความน่าเชื่อถือของ Application
  • Full Control บน Infrastructure ด้วย Root Access
  • Support Team ที่พร้อมช่วยเหลือ 24/7

สรุป

การ Deploy Node.js Application บน Kubernetes พร้อม Auto-Scaling ช่วยให้:

  • Application สามารถจัดการปริมาณคำขอได้อย่างมีประสิทธิภาพ
  • ลดการใช้ทรัพยากรที่ไม่จำเป็น ช่วยประหยัดค่าใช้งาน
  • มี Resilience สูงขึ้น ถ้า Pod ล้มเหลว Pod ใหม่จะถูกสร้างขึ้นโดยอัตโนมัติ
  • ให้ความเป็นระเบียบในการจัดการ Deployment

สำหรับการ Deploy Application ที่มีความเสถียรและปลอดภัย ลองใช้บริการ Cloud VPS จาก Dot Enterprise ที่ให้คุณสมบัติการจัดการ Kubernetes ที่มืออาชีพ