👤
Novice Handbook
  • Novice Handbook
  • Guide
  • Internet และ Web
    • HTML
  • Computer Language
    • Basic Computer Language (LV.1)
    • C Language (LV.1)
    • Python3 (LV.1)
  • Operating System
    • Linux
      • Basic Linux (LV.1)
  • TOOLS
    • Text Editor
      • Vim Editor
    • Source Control
      • GitLab
        • GitLab for small site (LV.1)
    • Container
      • Docker
        • Docker (LV.1)
        • Docker (LV.2)
      • Kubernetes
        • Kubernetes Intro (LV.0)
        • Kubernetes Basic (LV.1)
        • Kubernetes Intermediate (LV.2)
        • Helm (LV.2)
        • RKE2 (LV.3)
        • K3S (LV.3)
        • K3D (LV.3)
    • Repository
      • Harbor
        • Harbor for small site (LV.1)
        • Harbor for enterprise (LV.2)
    • Database
      • Redis
        • Redis on Docker Compose (LV.1)
        • Redis on Kubernetes (LV.2)
      • Elastic Stack
        • Elasticsearch & Kibana for small site (LV.1)
    • Observability
      • Prometheus
        • Prometheus for small site (LV.1)
        • Prometheus Operator (LV.2)
    • Security
      • Certbot (LV.1)
      • Falco
      • Hashicorp Vault
    • Collaboration
      • Nextcloud
Powered by GitBook
On this page
  • Kubernetes Object Management
  • Imperative command
  • Imperative object configuration
  • Declarative object configuration
  • Kubernetes Workloads
  • Pods
  • ReplicaSets
  • Deployments
  • StatefulSets
  • DaemonSets
  • Jobs และ CronJobs
  • Workshop Kubernetes Workloads
  • Deployment
  • Update Deployment
  • ReplicaSets
  • Cleanup Deployment
  • StatefulSets
  • Cleanup StatefulSet
  • DaemonSets
  • Cleanup DaemonSet
  • Jobs
  • Cleanup Job
  • CronJobs
  • Cleanup CronJob
  • Environment variable
  • ตัวอย่างการใช้งาน env
  • cleanup env
  • ตัวอย่างการใช้งาน envFrom
  • cleanup envFrom
  • Kubernetes Services and Networking
  • ClusterIP
  • NodePort
  • LoadBalancer
  • ExternalName
  • Ingress
  • Kubernetes Storage
  • Ephemeral Volumes
  • Persistent Volumes (PV) และ Persistent Volume Claims (PVC)
  • Storage Classes และ Dynamic Provisioning

Was this helpful?

  1. TOOLS
  2. Container
  3. Kubernetes

Kubernetes Basic (LV.1)

Kubernetes Object Management

kubectl เป็น CLI ที่รองรับการจัดการ Kubernetes objects ในหลายๆแบบ

Imperative command

user กระทำกับ object โดยตรง เป็นวิธีที่ใช้ learning curve น้อยที่สุด

kubectl create deployment nginx --image nginx

Imperative object configuration

user สร้าง file ที่ define object ในรูปแบบ YAML หรือ JSON และคำสั่งในการดำเนินการเช่น create, replace, delete เป็นวิธีที่ใช้ learning curve ปานกลาง

kubectl create -f nginx.yaml
kubectl delete -f nginx.yaml

Declarative object configuration

user สร้าง file YAML หรือ JSON ทั้งหมด แล้วเก็บไว้ใน directory และใช้เพียงคำสั่ง kubectl apply เป็นวิธีที่ใช้ learning curve มากที่สุด

kubectl diff -f configs/
kubectl apply -f configs/

Kubernetes Workloads

Pods

Pod คือหน่วยที่เล็กที่สุดที่สามารถ deploy ได้ใน Kubernetes โดย Pod ประกอบด้วยคอนเทนเนอร์อย่างน้อย 1 container โดย container ที่อยู่ใน Pod เดียวกันจะแชร์ IP Address และ Network เดียวกัน และสามารถสื่อสารกันได้โดยใช้ localhost container ที่รันคู่กับ container หลัก เรามักจะเรียกว่า sidecar

ReplicaSets

ReplicaSet เป็นตัวควบคุมจำนวนของ Pods ที่ทำงานอยู่ในช่วงเวลาเดียวกัน โดย ReplicaSet จะทำให้แน่ใจว่า Pod ที่มีจำนวนกำหนดจะถูกสร้างและทำงานอยู่เสมอ หาก Pod ใดถูกลบหรือเกิดการขัดข้อง ระบบจะทำการสร้าง Pod ใหม่ขึ้นมาแทนที่โดยอัตโนมัติ

Deployments

เป็น Workload ที่ใช้กับ Stateless application ไม่สนใจว่า Pod ใดที่ถูก control ภายใต้ Deployment นั้นจะ start ก่อนหรือหลังอีก Pod หนึ่ง มักจะใช้กับ application ส่วนมาก

StatefulSets

เป็น Workload ที่สนใจ State ของแต่ละ Pod มีการ control ให้ Pod ถูกสร้างและลบ ตามลำดับที่กำหนด มักจะใช้กับงานประเภท database หรือ cluster application

DaemonSets

เป็น Workload ที่จะ control ให้มีการ Deploy Pod ลงบนทุก Node ใน cluster โดย deploy 1 Pod ต่อ node เสมอ ดังนั้นหากมีการเพิ่ม node ใหม่เข้ามาใน cluster ก็จะมีการ deploy Pod บน node นั้นโดยอัตโนมัติ มักจะถูกใช้กับงานประเภท เก็บ log หรือ monitor node resource

Jobs และ CronJobs

Job เป็น Workload ใช้กับงานที่รันครั้งเดียวจบ จะมีการสร้าง Pod ขึ้นมารัน และหยุดไปเมื่อทำงานเสร็จ หรือหมดเวลา

Cronjob เป็น Workload ที่จะสร้าง Job ตาม Schedule ที่กำหนด


Workshop Kubernetes Workloads

Deployment

สร้าง YAML file จากคำสั่งดังนี้

kubectl create deployment nginx --image nginx --dry-run=client -o yaml > nginx.yaml

deploy ด้วยคำสั่งดังนี้

kubectl apply -f nginx.yaml

ตรวจสอบ deployment และ pod

kubectl get deployment
kubectl get pods

ลองอ่านไฟล์ nginx.yaml ดู

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}

replicas เป็นตัวกำหนดจำนวน Pod ที่จะถูกสร้างใน cluster selector เป็นวิธีที่ Pod ใช้ในการหาว่า Pod ใดบ้างที่จะถูก manage โดย Deployment นี้ ในตัวอย่างจะเป็น Pod ที่ถูก label app=nginx template เป็นตัวระบุ config เพื่อสร้าง Pod ในตัวอย่างจะสร้าง Pod โดยมี label app=nginx และใช้ image nginx จาก Dockerhub และเนื่องจากไม่มีการระบุ tag จึงจะใช้ image tag latest

Update Deployment

ลองทำการแก้ไขไฟล์ เปลี่ยนไปใช้ image nginx:1.27 ดังนี้

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.27
        name: nginx
        resources: {}
status: {}

apply change

kubectl apply -f nginx.yaml

ReplicaSets

ดู ReplicaSet ด้วยคำสั่งดังนี้

kubectl get rs

จะพบว่ามี 2 ReplicaSet

เราสามารถดูรายละเอียดของ ReplicaSet ได้จากคำสั่งดังนี้

kubectl describe rs nginx-xxx

โดย nginx-xxx คือ ชื่อ ReplicaSet ที่ได้มาจากก่อนหน้านี้

Name:           nginx-647f8c94fb
Namespace:      default
Selector:       app=nginx,pod-template-hash=647f8c94fb
Labels:         app=nginx
                pod-template-hash=647f8c94fb
Annotations:    deployment.kubernetes.io/desired-replicas: 1
                deployment.kubernetes.io/max-replicas: 2
                deployment.kubernetes.io/revision: 2
Controlled By:  Deployment/nginx
Replicas:       1 current / 1 desired
Pods Status:    1 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  app=nginx
           pod-template-hash=647f8c94fb
  Containers:
   nginx:
    Image:         nginx:1.27
    Port:          <none>
    Host Port:     <none>
    Environment:   <none>
    Mounts:        <none>
  Volumes:         <none>
  Node-Selectors:  <none>
  Tolerations:     <none>
Events:
  Type    Reason            Age   From                   Message
  ----    ------            ----  ----                   -------
  Normal  SuccessfulCreate  24s   replicaset-controller  Created pod: nginx-647f8c94fb-sjv8x

แต่ละ ReplicaSet คือ template ในการสร้าง Pod ReplicaSet จะคอยดูแลจำนวนของ Pod ให้แน่ใจว่าตรงตามจำนวนที่กำหนด การเปลี่ยนแปลง Deployment เช่น image version จะทำให้เกิดการสร้าง ReplicaSet ตัวใหม่, scale up ReplicaSet อันใหม่ และ scale down ReplicaSet เก่า

Cleanup Deployment

kubectl delete -f nginx.yaml

StatefulSets

StatefulSets ใช้ในการ manage stateful application มีการการันตีลำดับของการสร้าง Pod Pod จะถูกสร้างตาม spec ที่กำหนดไว้ และไม่สามารถเปลี่ยนแปลงได้หลังสร้างไปแล้ว

สร้าง StatefulSet YAML ในชื่อ sts.yaml ดังนี้

apiVersion: apps/v1
kind: StatefulSet
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  serviceName: nginx
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.27
        name: nginx
        resources: {}
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi
kubectl apply -f sts.yaml

config ส่วนใหญ่จะคล้าย Deployment แต่ต่างกันตรง - kind เป็น StatefulSet - เพิ่ม field serviceName - ตัด field strategy ทิ้ง

ใน StatefulSet เราอาจจะใส่ volumeClaimTemplates เพิ่มขึ้นมา เพื่อทำ dynamic allocate volume ให้กับ Pod ได้เช่นกัน

ลอง list StatefulSet

kubectl get sts
kubectl get pods

จะพบว่า Pod ถูกสร้างทีละ Pod ตามลำดับ

พฤติกรรมเช่นนี้จึงเหมาะกับการทำ cluster database มาก โดยมี Pod แรก bootstrap cluster ขึ้นมา แล้วค่อยมี Pod อื่นๆมาขอ join cluster

NAME                     READY   STATUS    RESTARTS   AGE
nginx-0                  1/1     Running   0          7s
nginx-1                  0/1     Pending   0          3s

Cleanup StatefulSet

kubectl delete -f sts.yaml
kubectl delete pvc -l app=nginx

DaemonSets

DaemonSet เป็น Workload ที่ทำให้เรามั่นใจได้ว่าทุก node จะมี Pod ตามที่กำหนดทำงานอยู่ ถ้ามี node ใหม่เพิ่มเข้ามา ก็จะมี Pod deploy ไปยัง node ที่เพิ่มเข้ามาโดยอัตโนมัติ

สร้าง DaemonSet YAML ในชื่อ ds.yaml ดังนี้

apiVersion: apps/v1
kind: DaemonSet
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.27
        name: nginx
        resources: {}
status: {}
kubectl apply -f sts.yaml

config ส่วนใหญ่จะคล้าย Deployment แต่ต่างกันตรง - kind เป็น DaemonSet - ตัด field strategy ทิ้ง

ลองตรวจข้อมูล DaemonSet และ Pod ดังนี้

kubectl get ds
kubectl get pods -o wide

จะได้ผลลัพธ์ดังนี้

NAME          READY   STATUS    RESTARTS   AGE   IP           NODE                       NOMINATED NODE   READINESS GATES
nginx-5k7qm   1/1     Running   0          72s   10.42.2.15   k3d-k3s-default-server-0   <none>           <none>
nginx-k8bld   1/1     Running   0          72s   10.42.0.20   k3d-k3s-default-agent-0    <none>           <none>
nginx-vwv68   1/1     Running   0          72s   10.42.1.12   k3d-k3s-default-agent-1    <none>           <none>

แสดงให้เห็นว่า Pod ของ DaemonSet จะทำงานอยู่คนละ node เสมอ

Cleanup DaemonSet

kubectl delete -f ds.yaml

Jobs

สร้าง 1 Pod หรือมากกว่านั้น เมื่อทำงานจนเสร็จ จะ down ไป ถ้า process มี exit code เป็น 0 จะถือว่า Job success ถ้า process มี exit code เป็น non-zero จะถือว่า failed และอาจจะมีการ re-run อีกครั้ง (หากกำหนด restartPolicy ไว้)

สร้าง Job YAML ในชื่อ job.yaml ดังนี้

apiVersion: batch/v1
kind: Job
metadata:
  name: myjob
spec:
  template:
    spec:
      containers:
      - name: myjob
        image: curlimages/curl
        command:
        - curl
        - -L
        - -v
        - https://google.com
      restartPolicy: Never
kubectl apply -f job.yaml

ลองดูข้อมูลของ Job และ Pod ดังนี้

kubectl get jobs
kubectl get pods

จะได้ผลลัพธ์ดังนี้

NAME          READY   STATUS      RESTARTS   AGE
myjob-hv88b   0/1     Completed   0          3m20s

ตรง STATUS แสดงเป็น Completed หมายถึง Job ทำงานเสร็จแล้ว และ Success ส่วน READY 0/1 หมายถึง Job ทำงานเสร็จ และหยุดไปแล้ว ซึ่งจะทำให้ไม่ consume compute resource แล้ว

Cleanup Job

kubectl delete -f job.yaml

การลบ Job จะทำการลบ Pod ทิ้งไปด้วย


CronJobs

Cronjob จะสร้าง Job ตาม Schedule ที่กำหนด

โดย default Cronjob จะทำงานตามเวลา timezone ของ kube-controller-manager แต่ใน Kubernetes version 1.27 เป็นต้นไป สามารถระบุ timezone ที่ต้องการได้ใน spec เลย

สร้าง Cronjob ในชื่อ cronjob.yaml ดังนี้

apiVersion: batch/v1
kind: CronJob
metadata:
  name: mycron
spec:
  schedule: '*/2 * * * *'
  timeZone: 'Asia/Bangkok'
  jobTemplate:
    metadata:
      name: mycron
    spec:
      template:
        spec:
          containers:
          - name: myjob
            image: curlimages/curl
            command:
            - curl
            - -L
            - -v
            - https://google.com
          restartPolicy: Never
kubectl apply -f cronjob.yaml

จากตัวอย่าง schedule มี pattern ดังนี้

# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday)
# │ │ │ │ │                                   OR sun, mon, tue, wed, thu, fri, sat
# │ │ │ │ │ 
# │ │ │ │ │
# * * * * *

หมายความว่า cron ตามตัวอย่าง จะสร้าง jobs ขึ้นมาทุกเวลาที่หาร 2 ลงตัว

หากลองดูข้อมูลของ CronJob, Job และ Pod

kubectl get cronjob
kubectl get job
kubectl get pod

จะได้ผลลัพธ์ดังนี้

NAME     SCHEDULE      TIMEZONE       SUSPEND   ACTIVE   LAST SCHEDULE   AGE
mycron   */2 * * * *   Asia/Bangkok   False     0        70s             3m25s

NAME              STATUS     COMPLETIONS   DURATION   AGE
mycron-28807746   Complete   1/1           5s         3m15s
mycron-28807748   Complete   1/1           5s         75s

NAME                    READY   STATUS      RESTARTS   AGE
mycron-28807746-tjtfv   0/1     Completed   0          3m36s
mycron-28807748-f9q9l   0/1     Completed   0          96s

Cleanup CronJob

kubectl delete -f cronjob.yaml

การลบ CronJob จะลบ Job ไปด้วย ซึ่งจะ chain ไปลบ Pod ด้วยเช่นกัน


Environment variable

Environment Variables ใน Kubernetes เป็นวิธีการส่งค่าคอนฟิกหรือข้อมูลเข้าสู่ Container ภายใน Pod เพื่อให้แอปพลิเคชันที่รันอยู่ใน Container สามารถใช้งานค่าที่กำหนดได้ โดย Environment Variables เหมาะสำหรับการส่งค่าที่เป็นข้อมูลการตั้งค่า เช่น ชื่อแอปพลิเคชัน, URL ของฐานข้อมูล, หรือค่าอื่น ๆ ที่แอปพลิเคชันต้องการ

env เป็นการกำหนดค่า variable ลงไปตรงๆ

envFrom เป็นการ refer ค่าจาก configMap หรือ secret โดยค่าต้องเก็บอยู่ในรูป key-value pair เท่านั้น

ตัวอย่างการใช้งาน env

สร้างไฟล์ชื่อ static-env.yaml ดังนี้

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        env:
        - name: FOO
          value: BAR
        - name: HELLO
          value: WORLD

สร้าง resource ด้วยคำสั่ง

kubectl apply -f static-env.yaml

ทดสอบ exec เข้าไปใน pods

kubectl exec -it deploy/nginx -- bash

ลองอ่านค่า environment variable

 echo $FOO
 echo $HELLO

จะได้ผลลัพธ์ตาม value ที่ set ไป

cleanup env

kubectl delete -f static-env.yaml

ตัวอย่างการใช้งาน envFrom

สร้างไฟล์ชื่อ cm-env.yaml ดังนี้

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        envFrom:
        - configMapRef:
            name: cm-env
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-env
data:
  FOO: BAR
  HELLO: WORLD

ทดสอบ exec เข้าไปใน pods

kubectl exec -it deploy/nginx -- bash

ลองอ่านค่า environment variable

 echo $FOO
 echo $HELLO

จะได้ผลลัพธ์ตาม value ที่ set ไป

cleanup envFrom

kubectl delete -f cm-env.yaml

Kubernetes Services and Networking

Service เป็นวิธีการที่ Kubernetes ใช้ในการเปิดให้เข้าถึง application ที่รันอยู่ภายใน cluster ได้ มีด้วยกันหลายชนิด ดังนี้

ClusterIP

ClusterIP เป็น Service ที่เปิดให้ application อื่นๆ เข้าถึง application ที่กำหนด ได้จากภายใน cluster เองเท่านั้น เป็น default ของ Kubernetes หากมีการสร้าง Service ขึ้นโดยไม่ระบุ type

ตัวอย่าง YAML

apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx

NodePort

NodePort เป็น Service ที่เปิดให้ traffic จากภายนอก cluster สามารถเข้ามาสู่ application ภายใน cluster ได้ผ่านทาง node ip & port โดยจะ forward traffic นั้นมายัง service ตามที่กำหนด

Port บน node จะเป็น high port ตั้งแต่ 30000 จนถึง 32767 และทุก node ใน cluster จะเปิด port หมายเลขนั้น โดยไม่สนใจว่า Pod อยู่บน node นั้นหรือไม่ ภายนอกจึงสามารถส่ง traffic มาที่ node ใดก็ได้ใน cluster แล้ว cluster จะ forward traffic ไปยัง Pod ที่รันอยู่เอง

ตัวอย่าง YAML

apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort

LoadBalancer

LoadBalancer เป็น Service ที่จะติดต่อกับ cloud provider เพื่อให้สร้าง loadbalancer ขึ้นมา และเปิดให้เข้าถึง application ผ่านทาง endpoint ของ loadbalancer แทน มีข้อดีกว่า NodePort ตรงที่ endpoint มีความแน่นอน เป็น dns name หรือ ip ของ load balancer เอง ซึ่งจะตายตัวกว่าการเรียกผ่าน node ip ที่เครื่องอาจจะมีการเปลี่ยนแปลง ip ได้ตลอดเมื่อ cloud มีการ scale node เพิ่มลด และยังสามารถ expose port เป็น low port number ได้อีกด้วย เช่น http-80 และ https-443

ดังนั้น loadbalancer จึงเทียบได้กับ superset ของ NodePort เอง

ตัวอย่าง YAML

apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer

ExternalName

เป็น Service ที่จะ map service name เข้ากับ DNS หนึ่ง เมื่อมีการเรียกใช้ service จะมีพฤติกรรมเหมือนกับ DNS resolve มากกว่าการทำ proxy หรือการ forward traffic มีประโยชน์ในการ refer resource นอก cluster ซึ่งใช้ร่วมกันในหลายๆ application หรือในการเตรียมทำ migration เข้ามาอยู่เป็น service หนึ่งใน cluster

ตัวอย่าง YAML

apiVersion: v1
kind: Service
metadata:
  name: ext-name
spec:
  type: ExternalName
  externalName: google.com

Ingress

Ingress เป็นวิธีในการ expose HTTP และ HTTPS route จากภายนอก cluster เข้าสู่ application ที่กำหนด Traffic routing ถูกควบคุมโดย rule ที่ประกาศไว้ใน Kubernetes resource ที่ชื่อ Ingress Ingress ยังสามารถกำหนด config ในแง่ของ URL, path, และการ terminate SSL/TLS ได้อีกด้วย

การที่ Ingress จะสามารถทำงานได้ จำเป็นต้องอาศัย Ingress Controller ซึ่งต้องติดตั้งเพิ่ม Ingress Controller ที่ได้รับความนิยม คือ Nginx, Traefik และ Kong เลือกติดตั้ง Ingress Controller เพียงชนิดเดียว หรือติดตั้งหลายๆ Ingress Controller ก็ได้ แต่ default IngressClass ต้องมีเพียงตัวเดียว

การติดตั้ง Nginx Ingress Controller

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx -n ingress-nginx --create-namespace

Nginx Ingress Controller มี 2 ค่าย คือ ของ Kubernetes community และของ F5 Nginx วิธีในตัวอย่างนี้เป็นของ Kubernetes Community

สิ่งที่ต้องระวังคึอ ทั้ง 2 ค่ายรองรับ feature และ annotation ไม่เหมือนกัน และใช้คนละ document ของ Kubernetes Community จะใช้ document ดังนี้

ทดสอบ Ingress Controller

สร้างไฟล์ ingress-example.yaml ดังนี้

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.27
        name: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: apache
  name: apache
spec:
  replicas: 1
  selector:
    matchLabels:
      app: apache
  template:
    metadata:
      labels:
        app: apache
    spec:
      containers:
      - image: httpd
        name: httpd
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: apache
  name: apache
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: apache
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /nginx
        pathType: Prefix
        backend:
          service:
            name: nginx
            port:
              number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: apache
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /apache
        pathType: Prefix
        backend:
          service:
            name: apache
            port:
              number: 80

apply ด้วยคำสั่งดังนี้

kubectl apply -f ingress-example.yaml

จากตัวอย่าง จะสร้าง deployment และ service ของ nginx และ apache และมีการสร้าง rule nginx ให้ เวลาเรียก path /nginx มีการส่ง traffic ไปยัง pod ของ nginx ส่วน rule apache เมื่อเรียก path /apache มีการส่ง traffic ไปยัง pod ของ apache โดยทั้งสอง rule จะมีการทำ rewrite url path ที่ขึ้นต้นจาก /apache และ /nginx ให้เหลือเพียง / เท่านั้น

ทดสอบเปิด browser เข้า path /apache และ /nginx ดู

ลบทิ้งด้วยคำสั่งดังนี้

kubectl delete -f ingress-example.yaml

แท้จริงแล้ว Ingress Controller คือ Application & Kubernetes Service ประเภท LoadBalancer อย่างหนึ่งที่สามารถอ่าน Kind Ingress ได้ และทำการ re-config logic ภายใน application เพื่อ route traffic ไปยัง service อื่นๆ

ข้อดีหนึ่งของการใช้ Ingress แทนการใช้ หลายๆ service LoadBalancer คือช่วยให้เราสามารถประหยัด cost ของ LoadBalancer ได้ เพราะเราสามารถใช้เพียง 1 LoadBalancer แทนการสร้าง LoadBalancer จำนวนมากในการรับ http/https request ของทุกๆ service

ในการใช้งานบน public cloud เราควรแยก LoadBalancer เป็น 2 ชุด ตัวหนึ่งเป็น public LoadBalancer และอีกอันเป็น private LoadBalancer เพื่อแยกเฉพาะ service ที่ไม่จำเป็นต้อง expose ให้ public รู้จัก สามารถเข้าถึงได้จาก private ในองค์กรเท่านั้น


Kubernetes Storage

Kubernetes มีการรองรับพื้นที่ Storage แบบต่างๆทั้ง Long-term Storage และ พื้นที่ Storage ชั่วคราว (Ephemeral Storage) หลายๆแบบ ดังนี้

Ephemeral Volumes

Ephemeral Volumes คือ Volumes ที่มีอายุการใช้งานชั่วคราวและเชื่อมโยงกับ lifecycle ของ Pod เมื่อ Pod ถูกสร้างขึ้น Volumes เหล่านี้จะถูกสร้างตามไปด้วย และเมื่อ Pod ถูกลบหรือยุติการทำงาน Volumes เหล่านี้ก็จะถูกลบไปด้วย

Ephemeral Volumes ที่ใช้งานบ่อยใน Kubernetes ได้แก่

  • emptyDir: allocate พื้นที่เปล่าเมื่อ Pod ถูกสร้าง โดยอาศัยพื้นที่จาก kubelet base directory (ปกติเป็น root disk) หรือจาก RAM

  • configMap & secret: inject ข้อมูลคอนฟิกหรือข้อมูลที่มีความลับ เข้ามาใน Pod

ตัวอย่าง emptyDir

สร้าง YAML ชื่อ redis.yaml โดยมี content ดังนี้

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: redis
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - image: bitnami/redis:7.4
        name: redis
        env:
        - name: ALLOW_EMPTY_PASSWORD
          value: "yes"
        volumeMounts:
        - mountPath: /bitnami/redis/data
          name: redis-data
      volumes:
      - name: redis-data
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: redis
  name: redis
spec:
  ports:
  - port: 6379
    protocol: TCP
    targetPort: 6379
  selector:
    app: redis

สั่ง apply เพื่อสร้าง

kubectl apply -f redis.yaml

หลังจากนั้นทำการสร้าง pod busybox เพื่อทดสอบใช้งาน redis ในเคสนี้เลือก busybox image เพราะมีติดตั้ง command telnet ไว้อยู่แล้ว

kubectl run -it --rm busybox --image busybox -- sh

หลังจากนั้น access เข้า redis

telnet redis 6379
KEYS *
SET FOO BAR
KEYS *
GET FOO

จะพบว่าสามารถ set และ get ข้อมูลออกมาได้

หลังจากนั้นใช้อีก terminal terminate redis pod ด้วยคำสั่งดังนี้

kubectl delete pods -l app=redis

ใน busybox จะถูกตัดการเชื่อมต่อ ให้รอสักพัก แล้ว connect ไปใหม่

telnet redis 6379
KEYS *
GET FOO

จะพบว่าไม่มี KEY แล้ว และไม่สามารถ get ข้อมูลออกมาได้ เนื่องจาก emptyDir เป็นพื้นที่ซึ่งผูกกับ lifecycle ของ Pod ดังนั้นเมื่อ Pod ถูก terminate ก็จะถูกลบทิ้งไปด้วย

cleanup

kubectl delete -f redis.yaml

ตัวอย่าง configMap

ตัวอย่างการ mount เป็น config file

สร้างไฟล์ mock.yaml ดังนี้

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: mock-server
  name: mock-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mock-server
  template:
    metadata:
      labels:
        app: mock-server
    spec:
      containers:
      - image: mockserver/mockserver
        name: mock-server
        env:
        - name: MOCKSERVER_INITIALIZATION_JSON_PATH
          value: /config/mock.json
        volumeMounts:
        - mountPath: /config
          name: mock-config
      volumes:
      - name: mock-config
        configMap:
          name: cm-mock
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-mock
data:
  mock.json: |
    [
      {
        "httpRequest": {
          "path": "/hello"
        },
        "httpResponse": {
          "body": "hello world"
        }
      },
      {
        "httpRequest": {
          "path": "/qwerty"
        },
        "httpResponse": {
          "body": "qwerty"
        }
      }
    ]
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: mock-server
  name: mock-server
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 1080
  selector:
    app: mock-server

จากตัวอย่างจะเป็นการสร้าง deployment mock-server และใช้ configmap ในการจัดเก็บ config ของ mock-server ซึ่งจะถูก mount เป็นไฟล์ภายใน pod เมื่อ pod ถูกสร้างขึ้นมา

การเก็บเป็น configmap นี้จะไม่มีการ encrypt หรือ decode และการส่งข้อมูลระหว่าง control-plane ไปยัง worker node ก็จะไม่มีการ encrypt เช่นกัน ดังนั้นจึงไม่ควรใส่ sensitive data ไว้ในรูป configmap

ทำการสร้าง resource ด้วยคำสั่งดังนี้

kubectl apply -f mock.yaml

ทดสอบการทำงานด้วย pod alpine

kubectl run -it --rm alpine --image alpine -- sh

ติดตั้ง curl ใน alpine และทดสอบเรียก mock

apk add curl
curl http://mock-server/hello
curl http://mock-server/qwerty

จะพบว่า mock-server สามารถทำงานได้ตาม config จาก configmap

cleanup ด้วยคำสั่งดังนี้

kubectl delete -f mock.yaml

ตัวอย่าง secret

สร้างไฟล์ชื่อ redis-secret.yaml ดังนี้

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: redis
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - image: bitnami/redis:7.4
        name: redis
        env:
        - name: REDIS_PASSWORD_FILE
          value: /secret/password
        volumeMounts:
        - mountPath: /bitnami/redis/data
          name: redis-data
        - mountPath: /secret
          name: redis-password
      volumes:
      - name: redis-data
        emptyDir: {}
      - name: redis-password
        secret:
          secretName: redis
---
apiVersion: v1
kind: Secret
metadata:
  labels:
    app: redis
  name: redis
data:
  password: bXlzZWNyZXQ=
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: redis
  name: redis
spec:
  ports:
  - port: 6379
    protocol: TCP
    targetPort: 6379
  selector:
    app: redis

จากตัวอย่างจะเป็นการสร้าง deployment redis และให้อ่าน password จากไฟล์ /secret/password โดย /secret มาจากการ mount Kubernetes secret ชื่อ key ใดๆก็ตามใน secret จะกลายเป็นชื่อไฟล์ และ value ซึ่งอยู้ในรูป base64 encode จะถูก decode เป็น content ของไฟล์นั้นๆ

ในตัวอย่าง bXlzZWNyZXQ= จะเทียบเท่าคำว่า mysecret เมื่อผ่าน base64 decode

ค่าที่อยู่ใน secret เป็นเพียงการ encode base64 ไม่ได้มีการ encrypt ดังนั้นใครก็ตามที่มี permission อ่าน secret ได้ จะสามารถเข้าถึง sesitive data ได้ ควรมีการ limit permission แต่ละ user ให้เหมาะสม

แม้ว่า secret จะเป็นเพียงการ encode แต่ในด้านการเก็บข้อมูลใน disk ของ etcd นั้น control plane จะสามารถกำหนดให้ encrypt secret ที่บันทึกลง disk ได้ และการส่งข้อมูลไปยัง worker node ก็ผ่าน TLS จึงมีความ secure กว่า configmap และสามารถใช้ในการเก็บ sensitive data ได้

Access เข้า redis

kubectl exec -it deployment/redis -- redis-cli

ทดสอบเรียกคำสั่งดังนี้

KEYS *

จะพบว่า redis แจ้งว่าต้อง Authen

(error) NOAUTH Authentication required.

ทำการ Authen

AUTH mysecret
KEYS *

จะพบว่าสามารถเรียกใช้งานได้ปกติ

หลังจากนั้น disconnect และทำการ cleanup

kubectl delete -f redis-secret.yaml

Persistent Volumes (PV) และ Persistent Volume Claims (PVC)

Storage Classes และ Dynamic Provisioning

PreviousKubernetes Intro (LV.0)NextKubernetes Intermediate (LV.2)

Last updated 5 months ago

Was this helpful?

https://kubernetes.github.io/ingress-nginx/
ClusterIP
NodePort
LoadBalancer
ExternalName
Ingress