Coding Gun

ติดตั้ง Kubernetes บน Ubuntu 22

ก่อนจะทำการ install kubernetes เราต้องตรวจสอบ spec ของ server ก่อนว่าเพียงพอต่อการใช้งานหรือไม่ โดยที่ spec ขั้นต่ำที่สามารถติดต้ัง kubernetes ได้คือ

หลังจากนั้นให้เชื่อม nodes ต่างๆเข้าหากันให้เรียบร้อย(ทุกๆ node ต้องอยู่ใน network เดียวกัน) หลังจากนั้นก็เช้าสู่ขั้นตอนการติดต้ัง ซึ่งมีขั้นตอนต่างๆ ดังนี้

  1. Disable swap
  2. ตั้ง hostname
  3. Mapping IP Address กับ Hostname ในทุกๆ Nodes
  4. ตั้งค่า IPV4 Bridge ในทุกๆ Nodes
  5. ติดต้ัง Container runtime(Containerd)
  6. ติดตั้ง Kubernetes components ในทุกๆ Nodes
  7. สร้าง Kubernetes Cluster
  8. ติดตั้ง Kubernetes network(Calico)
  9. นำ Worker Node join เข้ามาใน cluster

1. Disable Swap

Swap Space คือ การย้ายข้อมูลที่อยู่ใน Memory(RAM) ไปเก็บไว้ใน disk เพื่อประหยัดพื้นที่ใน RAM ดังนั้นเมื่อ enable swap ขึ้นมาระบบจะ stable มากขึ้นเพราะจะใช้พื้นที่ใน memory(RAM) น้อยลง แต่ปัญหาก็คือความไม่แน่นอนของการอ่านเขียนข้อมูล เพราะถ้าเราไปอ่านข้อมูลใน Swap Space ก็จะช้ากว่าการอ่านเขียนข้อมูลใน RAM ดังนั้นในขั้นตอนแรกของการติดตั้ง เราต้องไป disable swap เพื่อให้ kubernetes สามารถจัดการกับ performance ได้ง่ายขึ้น

Kubernetes schedule จะใช้ปริมาณของ memory ในการตัดสินใจตว่าจะ deploy pod ลงไปใน node ไหน

การ disable swap เราจะใช้คำสั่ง

$ swapoff -a

คำสั่ง swapoff จะเป็นการ disable ชั่วคราวเท่านั้นถ้า restart server ใหม่ swap จะถูก enable ขึ้นมาใช้งานใหม่ เราจึงต้องไปแก้ไฟล์ fstab โดยการ comment บรรทัดที่มี swap ออก

$ sudo sed -i '/ swap / s/^/#/' /etc/fstab

2. ตั้ง Hostname

ในขั้นตอนนี้เราจะตั้งชื่อ hostname ให้อ่านง่าย อาจดูว่าเป็นขั้นตอนที่ดูไม่ค่อยจำเป็นเท่าไหร่ เพราะเราสามารถตั้ง hostname เป็นอะไรก็ได้ kubernetes ไม่ได้สนใจ แต่หลังจากนี้ถ้าเกิดปัญหาขึ่้นมาตอน Operation การตั้งชื่อให้อ่านง่ายจะช่วยเรามากๆ ดังนั้นเราจะไม่ตั้งชื่อเป็น ubuntu-01, ubuntu-02 แบบนี้ เพราะสุดท้ายคุณเองนั่นแหละจะลืมเองว่าตัวไหนเป็น control plane หรือตัวไหนเป็น worker

เราจะใช้คำสั่งนี้ในการตั้ง hostname

$ sudo hostnamectl set-hostname "control-plane"

และเราจะใช้คำสั่ง exec bash เพื่อให้ดการเปลี่ยนชื่อ hostname นี้มีผลทันที

$ exec bash

เราจะตั้งชื่อเครื่องตามนนี้

  1. เครื่องที่ทำหน้าที่เป็น control plane หรือ master ให้ใช้ชื่อว่า control-plane
  2. เครื่องที่ทำหน้าที่เป็น worker ให้ตั้งชื่อเรียงลำดับไปเรื่อยๆ แบบนี้
    • worker-node1
    • worker-node2
    • worker-node3

ข้อแนะนำ ใน 1 cluster ควรจะมี worker nodes อย่างน้อย 3 ตัว

3. Mapping IP Address กับ Hostname ในทุกๆ Nodes

เราต้องแก้ไขไฟล์ /etc/hosts เพื่อ map ip address กับ hostname ที่เราได้ตั้งไว้เวลาอ้างถึง hostname จะได้วิ่งไปยัง IP Address ของเครื่องนั้นเลย วิธีการคือ เปิดไฟล์ /etc/hosts แล้วเพิ่มข้อความนี้เข้าไป

10.0.0.2 control-plane
10.0.0.3 worker-node1
10.0.0.4 worker-node2
10.0.0.5 worker-node3

IP Address ของเราจะไม่เหมือนกันขึ้นอยู่กับ network ที่เรากำหนดไว้

4. ตั้งค่า IPV4 Bridge ในทุกๆ Nodes

ในกรณีที่เราใช้ containerd เป็น container runtime เราต้อง set ให้ network เป็น bridge เราจึงต้อง run script นี้

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# sysctl params required by setup, params persist across reboots
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system

5. ติดตั้ง Container Runtime(Containerd)

Kubernetes นั้นไม่สามารถทำงานกับ container ได้เราจึงต้องติดตั้ง container runtime เพื่อสร้าง container ขึ้นมาทำงาน ซึ่ง container runtime ที่ได้รับความนิยมมากที่สุดตอนนี้คือ containerd โดยจะมีขั้นตอนติดตั้ง containerd ดังนี้

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  
sudo apt-get update 
sudo apt-get install -y containerd.io

หลังจากที่เรา install containerd เสร็จเรียบร้อยให้สร้าง default configuration ของ containerd ด้วยคำสั่ง

sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml

หลังจากนั้นให้แก้ config.toml ที่ได้มา โดยดารเปิดไฟล์ /etc/containerd/config.toml แล้วให้ค้นหา section ที่มีชื่อว่า [plugins.“io.containerd.grpc.v1.cri”.containerd.runtimes.runc] เปลี่ยน SystemdCgroup จาก false ไปเป็น true

หรือ run คำสั่งนี้เพื่อเปลี่ยน SystemdCgroup

sudo sed -i 's/            SystemdCgroup = false/            SystemdCgroup = true/' /etc/containerd/config.toml

ที่เราต้องแก้ไฟล์ config.toml เพราะ kubelet ต้องการไปอยู่ใน cgroup ของ systemd

สุดท้ายให้ restart containerd service ใหม่อีกรอบ

$ sudo systemctl restart containerd

สิ่งที่ต้องระวัง

ถ้าเราใช้ containerd ห้ามติดตั้่ง docker ลงไปด้วย เพราะ kubeadm จะทำการค้นหา container runtime ซึ่ง kubeadm จะเลือกใช้งาน docker ก่อน containerd

ส่วนใหญ่บน server เรานิยมใช้ containerd มากกว่า docker เพราะตอนที่เราติดตั้ง kubernetes จะไม่มี docker shim ติดตั้งมาด้วย ดังนั้นถ้าเราอยากใช้งาน docker เราต้องไปติดตั้ง docker shim เอง

6. ติดตั้ง Kubernetes Components ในทุกๆ Nodes

ขั้นตอนนี้สำคัญมากๆ เพราะต้องการเครื่องมือที่จะต้องใช้ในการติดตั้ง kubernetes ซึ่งเครื่องมือที่เราต้องใช้ประกอบไปด้วย

  1. kubeadm เป็นคำสั่งที่ใช้ในการสร้าง kubernetes cluster และนำ worker node เข้ามา join ใน cluster
  2. kubelet เป็น agent ที่จะ run อยู่ในทุกๆ Node มีไว้คุยกับ Control plane
  3. kubectl เป็น command line ที่เราต้องใช้จัดการ kubernetes cluster
$ sudo apt-get install kubelet kubeadm kubectl
$ sudo apt-mark hold kubelet kubeadm kubectl containerd

หลังจากนั้นให้ตรวจสอบว่าในแต่ละเครื่อง kubelet และ containerd ทำงานปกติหรือไม่ด้วยคำสั่ง

$ sudo systemctl enable kubelet.service
$ sudo systemctl enable containerd.service

7. สร้าง Kubernetes Cluster

ในขั้นตอนนี้ให้เข้าไปที่เตรื่อง control-plane แล้ว run คำสั่ง kubeadm init เพื่อสร้าง kubernetes cluster

$ sudo kubeadm init

ถ้าต้องการระบุ IP address ของ Pods ให้ใช้ –pod-network-cidr ต่อท้าย

sudo kubeadm init --pod-network-cidr=10.0.0.0/16

อย่าให้ IP address ของ Pods ไป overlap หรือซ้ำกับ IP address ของ physical network

ในการจัดการกับ Kubernetes Cluster โดยใช้ kubectl เราต้องกำหนด configuration ของ user ที่ต้องการใช้งาน kubernetes cluster เราจึงต้องย้าย admin.conf ที่ generate ออกมาจาก kubeadm init ไปวางไว้ใน folder /.kube/config

# สร้าง folder .kube ใน home directory ของ user ปัจจุบัน
mkdir -p $HOME/.kube
# copy  admin.conf ไปวางไว้ใน folder ที่เราได้สร้างขึ้น
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# ปรับสิทธิให้ kubectl สามารถเข้ามาอ่านได้
sudo chown $(id -u):$(id -g) $HOME/.kube/config

8. ติดตั้ง Kubernetes Network(Calico)

หลังจากที่เราได้ init cluster ขึ้นมาแล้ว หลังจากนี้ให้เข้าไปติดตั้ง kubernetes network ซึ่ง Kubernetes network นั้นมีให้เลือกหลายตัวมากๆ ซึ่ง kubernetes ที่ได้รับความนิยมมากๆคือ Calico ซึ่งขั้นตอนการติดตั้ง Calico จะมีดังนี้

  1. Download calico.yml
$ wget https://raw.githubusercontent.com/projectcalico/calico/master/manifests/calico.yaml

หลังจากนั้นติดตั้ง Calico ด้วย kubectl apply

$ kubectl apply -f calico.yaml

สามารถเลือก kubernetes network ตัวอื่นได้ตามความต้องการ โดยสามารถดูรายละเอียดต่อได้ที่นี่

9. นำ Worker Node join เข้ามาใน cluster

ตอนที่เรา run คำสั่ง kubeadm init ในขั้นตอนที่ 7 จะมี command สำหรับ join เข้ามาใน cluster ที่สร้าง ให้นำคำสั่งนั้นไป run ในเครื่อง worker ทุกตัว

1
2
3
sudo kubeadm join 172.16.94.10:6443 \
    --token 2yij0q.256jwadksuvxprp8 \
    --discovery-token-ca-cert-hash sha256:bd0763f650e65bc211c02f39d6e1e6a5ea92423728df7034b8747dc0086d6c8a

เราต้องมี token และ ค่า hash ของ CA certificate เราถึงจะสามารถ join เข้าไปใน cluster ได้ แต่ถ้าเรา copy คำสั่ง kubeadm join ไว้ไม่ทันให้กลับไปที่เครื่อง control-plane แล้ว run คำสั่ง

$ kubeadm token list

และหาค่า hash ของ CA Certificate ด้วยคำสั่ง

openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

นำ token และ hash ของ CA Certificate ไปแทนที่ในคำสั่งนี้

1
2
3
$ sudo kubeadm join 172.16.94.10:6443 \
    --token [token] \
    --discovery-token-ca-cert-hash [ค่า hash ของ CA Certificate]

หรือถ้าต้องการสร้าง token ตัวใหม่ขึ้นมาเราสามารถใช้ –print-join-command ต่อท้ายเข้าไปได้เลย

$ kubeadm token create --print-join-command

หลังจากนั้น copy คำสั่งที่ได้ไป run ใน worker node

สุดท้ายให้ทำการตรวจสอบสถานะของ Nodes ต่างๆ โดยที่ run คำสั่งนี้ใน control-plane

kubectl get nodes

ถ้าได้ผลลัพธ์ออกมามีทั้ง Control Plane และ Worker Nodes ครบตามจำนวนที่เราต้องการก็ถือว่าการติดตั้ง kubernetes ของเราเสร็จสมบูรณ์เรียบร้อย

อ่านต่อเพิ่มเติมได้ที่

Phanupong Permpimol
Follow me

Software Engineer ที่เชื่อในเรื่องของ Process เพราะเมื่อ Process ดี Product ก็จะดีตาม ปัจจุบันเป็นอาจารย์และที่ปรึกษาด้านการออกแบบและพัฒนา Software และ Web Security