วิธีย้ายจาก Docker Compose เป็น Kubernetes เบื้องต้น
กรณีเรามีการคุ้นเคยหรือใช้งาน Docker เป็นหลักอยู่แล้ว อาจจะรู้จัก docker compose เป็นอย่างดี ซึ่งในการ
ทำไมถึงต้องย้าย?
เรามาดูเหตุผลและความจำเป็นในการการย้ายจาก Docker Compose มายัง Kubernetes โดยมักเกิดขึ้นเมื่อแอปพลิเคชันมีการเติบโตและต้องการความสามารถที่ Docker Compose ไม่สามารถให้ได้ ได้แก่
- ความทนทาน (Fault Tolerance): ถ้าคอนเทนเนอร์ตัวใดตัวหนึ่งล่ม Kubernetes สามารถสร้างตัวใหม่ (Pod) ขึ้นมาในทันทีจะทำให้ระบบพร้อมใช้งานตลอดเวลา
- การขยายขนาด (Scalability): เมื่อมีคนใช้งานเยอะขึ้น Kubernetes สามารถเพิ่มจำนวนคอนเทนเนอร์ของแอปพลิเคชันให้โดยอัตโนมัติ เพื่อรองรับปริมาณงานที่เพิ่มขึ้น
- การจัดการที่ซับซ้อน (Complex Management): Docker Compose เหมาะกับแอปพลิเคชันขนาดเล็กและไม่ต้องจัดการเยอะ แต่เมื่อแอปของคุณมีหลายส่วนที่ต้องทำงานร่วมกัน หรือต้องการความสามารถด้านความปลอดภัย การจัดการปริมาณงาน หรือการอัปเดตแบบไม่มี downtime Kubernetes จะตอบโจทย์ได้ดีกว่า
ทำความเข้าใจ YAML ของ Kubernetes
ไฟล์ docker-compose.yml
จะถูกแปลงเป็นไฟล์ YAML ของ Kubernetes ซึ่งมีหลายประเภท เช่น Deployment
, Service
, ConfigMap
, Secret
, Certificate
และ Ingress
ที่เป็นไฟล์ตั้งค่าสำหรับแอปของคุณ
- Deployment: ใช้ในการสร้างข้อมูลแอปพลิเคชันหรือบริการที่ใช้งาน
- Service: สำหรับเปิดพอร์ตให้แอปพลิเคชันเข้าถึงได้จากภายนอก
- ConfigMap / Secret: ใช้สำหรับจัดการค่าตัวแปร (Configuration) และข้อมูลสำคัญ (Secret) ที่สำหรับใช้ในแอปพลิเคชัน
- PV / PVC: ใช้สำหรับจัดเก็บข้อมูลสำหรับแอปพลิเคชัน
- Ingress: ใช้สำหรับกำหนดเส้นทางไปยังแอปฯ
ตัวอย่างการนำไปใช้งาน
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: demo-prod-demo-web
name: demo-web
namespace: demo-prod
spec:
replicas: 1
selector:
matchLabels:
app: demo-prod-demo-web
template:
metadata:
labels:
app: demo-prod-demo-web
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: demo-web
ports:
- containerPort: 80
name: 80tcp
protocol: TCP
resources:
requests:
memory: 50Mi
cpu: 50m
limits:
memory: 250Mi
cpu: 250m
dnsPolicy: ClusterFirst
restartPolicy: Always
web.yaml
Service
apiVersion: v1
kind: Service
metadata:
name: demo-web
namespace: demo-prod
spec:
ports:
- name: 80tcp
port: 80
protocol: TCP
targetPort: 80
selector:
app: demo-prod-demo-web
type: ClusterIP
web-service.yaml
Certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: demo-web-tls
namespace: demo-prod
spec:
secretName: demo-web-tls
commonName: "demo-web.example.app"
dnsNames:
- "demo-web.example.app"
issuerRef:
name: cloudflare-issuer
kind: ClusterIssuer
demo-web-tls.yaml
Self Certificate
# Certificate: 2024-2025
apiVersion: v1
data:
tls.crt: LS0tLS1CRUdJTi... # Base64
tls.key: LS0tLS1CRUdJTi... # Base64
kind: Secret
metadata:
name: demo-prod-demo-web
namespace: demo-prod
type: kubernetes.io/tls
Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-prod-demo-web
namespace: demo-prod
annotations:
kubernetes.io/tls-acme: "true"
spec:
ingressClassName: nginx
rules:
- host: demo-web.example.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-web
port:
number: 80
tls:
- hosts:
- demo-web.example.app
secretName: demo-web-tls
demo-web-ingress.yaml
PersistentVolume
apiVersion: v1
kind: PersistentVolume
metadata:
name: demo-web-pv
namesplace: demo-prod
spec:
storageClassName: longhorn
capacity:
storage: 10Gi
volumeMode: Filesystem
# accessModes
# - ReadWriteOnce
# - ReadWriteMany
accessModes:
- ReadWriteOnce
# persistentVolumeReclaimPolicy
# กำหนดสถานะข้อมูลหลังลบ PVC
# - Retain จะเก็บข้อมูลเอาไว้
# - Delete จะลบข้อมูลทันทีหลัง PVC ถูกลบ
persistentVolumeReclaimPolicy: Delete
PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: demo-web-pvc
namespace: demo-prod
spec:
storageClassName: longhorn
volumeName: "demo-web-pv"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Secret
apiVersion: v1
kind: Secret
metadata:
name: demo-web-secret
namespace: demo-prod
type: Opaque
data:
ROOT_PASSWORD: VHBrOEhlbnIhUmQ=
ConfigMaps
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-web-config
namespace: demo-prod
data:
APP_ENV: "Test"
APP_PROD: "Test"