Category Archives: Kubernetes

K8S Sizing and Key Consideration

แนวทางเบื้องต้นเพื่อใช้ในการ Sizing ขนาดของ Kubernetes Cluster สำหรับ Application ใช้งานใน Kubernetes Environment สามารถใช้แนวทางดังนี้ในการพิจารณา

ต้องพิจารณาปัจจัยหลักๆ ประกอบด้วย 4 ปัจจัยคือ

Pods per node density

คือจำนวนของ Pod ซึ่งเป็น deployable unit (containers) ที่สามารถทำงานได้ต่อหนึ่งเครื่อง (Node) โดยเราต้องมีข้อมูล

  • vCPU ที่ pod ใช้งาน อาจจะใช้ cpu limit (ปกติจะต้องทำ cpu limit ไว้ เพื่อไม่ให้ pod ใช้ cpu ของเครื่องหมดจนส่งผลกระทบทั้ง cluster)
  • vCPU ของเครื่อง (Node) สำหรับใช้ในการ run pod
  • vCPU ทั้งหมดของเครื่อง (Node)
  • เปอร์เซ็นต์ของ cpu ที่จะ reserve ไว้สำหรับงานอื่นๆ เช่น system process

จากนั้นก็จะสามารถหาค่า pod per node density ได้จากการหาว่ามี vCPU สำหรับใช้ได้จริงเท่าไหร่ แล้ว หารด้วยค่าเฉลี่ยของ vCPU ที่ pod ใช้งาน เช่น

Node VM มี 8 vCPU และต้องการ reserve vCPU ไว้ 15% สำหรับ system process โดยค่าเฉลี่ยที่ pod ใช้งาน cpu core คือ 0.2 vCPU ต่อ Pod ก็จะหา pod per node density ได้ดังนี้

vCPU ที่ใช้งานได้ = 8 – (8*15/100) = 6.8 vCPU

Pod per node density = 6.8/0.2 = 34

** การกำหนดค่าเฉลี่ย vCPU ที่ pod ใช้งาน ต้องพิจารณา pods per CPU core จากคำแนะนำของ Kubernetes ที่ 1 CPU core จะสามารถรองรับได้ที่มากที่สุด 10 pods และจำนวน pod ต่อ Node ไม่ควรเกิน 110 pods – https://kubernetes.io/docs/setup/best-practices/cluster-large/

Master Node’s hardware config

ใช้ข้อมูลจาก kubernetes.io สำหรับเลือกขนาดของ Master Node

และต้องพิจารณา size ของเครื่องเพื่อรองรับ etcd คือ

ซึ่งถ้าต้องการ high availability จะต้องมีจำนวน node เป็นเลขคี่ตั้งแต่ 3 ขึ้นไป (Quorum)

ตัวอย่างเช่น ถ้าเรามี Worker node อยู่ 11 Node และต้อง support client จำนวน 500 client เราต้องใช้ Master node ด้วย spec 4vCPU memory 15 GBs

Number of Master Node in Cluster

เพื่อให้ระบบทำงานได้แม้จะมี Master node บางตัวไม่สามารถทำงานได้ ต้องพิจารณาจำนวนของ Master node ดังนี้

ตัวอย่างเช่น ถ้าต้องการให้ระบบยังคงทำงานได้ กรณีที่มี Master Node 2 ตัวเกิดปัญหา เราต้องเลือกจำนวน Master Node เป็น 5

High Availability and Fault Tolerance

ปัจจัยที่ต้องใช้ในการพิจารณามีดังนี้

  • จำนวน Node ที่มีปัญหา ณ​ เวลาใดเวลาหนึ่งพร้อมกัน
  • Node ที่ต้อง reserve ไว้ในกรณีที่มีการ update ระบบ
  • Pod per node density
  • จำนวน Node ที่เหลืออยู่หลังจาก Failure
  • จำนวน Capacity ที่เหลือสำหรับให้ Pod ทำงานได้หลังจาก Failure
  • จำนวน CPU core ที่เหลืออยู่หลังจาก Pod ทำงานเรียบร้อย หลังจาก Failure (rescheduling)

การหาจำนวน Node เช่น ถ้าเรามี 100 pods และต้องการให้ run 34 pods ต่อ node โดยสามารถ fail ได้ 2 Node ต่อเนื่อง และรองรับกรณี upgrade ระบบ ก็จะคำนวณ sizing ของ Node ได้คือ

100/34 + 2 + 1 = 6 worker node

การหา capacity ที่เหลือ และ pod per node density หลังจาก failure

เช่น มี pod จำนวน 100 pods ทำงานกระจายใน 6 node เมื่อมี 2 nodes ไม่สามารถให้บริการได้

จำนวน pod per node density เบื้องต้น = 100/6 = 16.6

จำนวน node ที่เหลืออยู่หลังจาก failure = 4 Node ซึ่งก็คือ resource หายไป 33% ของทั้งหมด

ทำให้ pod per node density เพิ่มขึ้นเป็น = 100/4 = 25

หลังจากได้ pods per node density แล้วต้องคำนวณด้วย cpu core ที่ pod ใช้งานถึงจะ sizing ขนาดของ node ได้ว่าจะต้องเผื่อ cpu และ memory ไว้ที่เท่าไหร่ถึงจะเหมาะสม

** Kubernetes support cluster auto scaling ได้ในกรณีที่ pod ไม่สามารถ scheduling ได้เนื่องจาก resource มีไม่เพียงพอ https://kubernetes.io/docs/concepts/cluster-administration/cluster-autoscaling/ แต่ก็จะมีช่วงเวลาที่ pod ไม่สามารถทำงานได้ในระหว่างที่มีการสร้าง node ใหม่เพื่อ join เข้ามาใน cluster

Workload Characteristic

เพื่อที่จะได้ค่า cpu และ memory ที่ pod ต้องการใช้จะต้องมีข้อมูลการทำงานจริงของ pod แล้วนำมาหาค่าเฉลี่ยเพราะแต่ละ pod ประกอบด้วย container ที่ application ถูกสร้างด้วย technology, architecture, algorithm ที่มี load หรือ usage แตกต่างกันในแต่ละช่วงเวลาการใช้งาน ตัวอย่าง memory ต่อ container ของแต่ละภาษา เช่น

  • Legacy JEE. 2Gb+ mem per container
  • SpringBoot 1Gb+ mem per container
  • NodeJS. 256Mb+ mem per container
  • Go 256Mb+ mem per container

Case Study

หา Sizing ของ Kubernetes Cluster เพื่อรองรับ 100 Springboot containers โดยมีข้อมูลดังนี้

  • Pod ทำงานโดยใช้ 0.2 vCPU และ Memory 0.4 GB
  • จำนวน pod per node density เท่ากับ 34
  • สามารถ fail ติดต่อกันได้ 2 ครั้ง
  • มี node ไว้ reserve สำหรับการ upgrade
  • ต้องมีการสำรอง resource ไว้ 15% สำหรับระบบ

KIND – Kubernetes in Docker

kind เป็น tool ตัวหนึ่งที่น่าสนใจสำหรับ run Kubernetes อยู่ที่เครื่องเราเองโดยใช้ Docker container เป็น nodes ของ Kubernetes ข้อดีคือจัดการง่ายและทำงานได้เร็ว ถ้าต้องใช้ script เพื่อสร้าง cluster เพื่อทำ integration test แล้ว tool ตัวนี้ตอบโจทย์ได้ดีทีเดียว ติดตั้งเพื่อใช้งานทำได้ตาม quick start

ตัวอย่าง command ต่าง ๆ สำหรับใช้งาน kind

สร้าง cluster ที่มี Master และ Worker จำนวน 1 node

kind create cluster --name test1

สร้าง cluster ที่มี Master และ Work อย่างละ Node จาก configuration file

kind create cluster --name=test2 --config kind-2node.yaml

# ข้อมูลใน File kind-2node.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker

สร้าง cluster ที่มี Master จำนวน 3 nodes และ Worker จำนวน 2 nodes

kind create cluster --name=test3 --config kind-5node.yaml

# ข้อมูลของ file kind-5node.yaml
kind: Cluster 
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: control-plane
- role: control-plane
- role: worker
- role: worker

ในกรณีที่ใช้ docker-machine เพื่อสร้าง docker engine จำเป็นต้องระบุ ip ของ docker engine ใน file config ด้วย กรณีต้องการ config ค่าอื่นๆ ดูได้จาก kind document

# หา ip ของ docker engine ด้วย
❯ docker-machine ip
192.168.99.102

# จากนั้นสร้าง config file ดังนี้
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  apiServerAddress: "192.168.99.102"
  apiServerPort: 6443
nodes:
- role: control-plane
- role: worker

การ access เข้าไปที่ node

docker ps

# test1-control-plane เป็นชื่อ Master node จากผลลัพธ์ docker ps
docker exec -it test1-control-plane bash

การ access container ที่ run ที่เครื่อง test1-control-plan ซึ้ง container runtime ใน node จะเป็น containerd นะครับ

root@test-control-plane:/# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                      ATTEMPT             POD ID
fd7b628af2359       296a6d5035e2d       20 minutes ago      Running             coredns                   0                   f068e76bb133e
67db85b7b5293       296a6d5035e2d       20 minutes ago      Running             coredns                   0                   1d773ed216c4e
1e94aff11ee8e       e422121c9c5f9       20 minutes ago      Running             local-path-provisioner    0                   6c9467c5cdb84
9599b04fdad77       6de166512aa22       20 minutes ago      Running             kindnet-cni               0                   1a9a398e62418
f55a566a3f556       0e124fb3c695b       20 minutes ago      Running             kube-proxy                0                   c075e7b86e928
6927ff1f38141       0369cf4303ffd       20 minutes ago      Running             etcd                      0                   92b0750af4e4c
6eaab86c31d42       94ffe308aeff9       20 minutes ago      Running             kube-apiserver            0                   34bbfc2183651
5a861837a686e       96a295389d472       20 minutes ago      Running             kube-controller-manager   0                   571c1b03041e7
7f5d355589866       1248d2d503d37       20 minutes ago      Running             kube-scheduler            0                   9d92fc037f002

สร้าง Kubernetes pod

kubectl run nginx --image=nginx

สร้าง Kubernetes service

❯ kubectl expose pod nginx --port=80 --target-port=80 --name=nginx-http --type=NodePort


# ทดสอบเรียก service
root@test-control-plane:~# kubectl get nodes -o wide
NAME                 STATUS   ROLES                  AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE       KERNEL-VERSION         CONTAINER-RUNTIME
test-control-plane   Ready    control-plane,master   18m   v1.21.1   172.18.0.3    <none>        Ubuntu 21.04   4.19.130-boot2docker   containerd://1.5.2
test-worker          Ready    <none>                 18m   v1.21.1   172.18.0.2    <none>        Ubuntu 21.04   4.19.130-boot2docker   containerd://1.5.2

root@test-control-plane:~# curl http://172.18.0.2:30108
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@test-control-plane:~# exit

สร้าง kube config ที่ master

cp /etc/kubernetes/admin.conf ~/.kube/config

แสดง log ของ cluster จาก kind cli

kind export logs --name=test2

ลบ cluster

kind delete cluster --name test1

Restart docker, ในกรณีที่ restart เครื่อง ต้อง start docker image ของ Master และ Worker nodes

docker start <name>-control-plane
docker start <name>-worker
export KUBECONFIG="$(kind get kubeconfig-path --name="<name>")"