[Kubernetes] อยากใช้ Load Balancer แต่รัน Cluster บน Bare Metal ทำยังไงดี ?
หลายคนเคยเจอปัญหา
NAME TYPE CLUSTER-IP EXTERNAL-IP
hello-kubernetes LoadBalancer 10.100.179.79 <pending>
EXTERNAL-IP ทำไมถึง pending อยู่ตลอดเวลานะ มันต้องมีอะไรผิดพลาดแน่ๆ
เพราะว่า cluster ของเราไม่ support Layer 4 Load Balancer ยังไงล่ะ
ทำยังไงดี ในเมื่อใช้ LoadBalancer ไม่ได้ก็อย่าหวังว่าจะใช้ Ingress ได้เลย
วันนี้เลยอยากจะนำเสนอโปรเจคที่มีชื่อว่า MetalLB (ย่อมาจาก Metal Load Balance) ซึ่งตอนนี้อยู่ในช่วง Beta และเป็นโปรเจค Unofficial ของ Google https://github.com/google/metallb ถ้าจะใช้บน Production ก็ระวังกันหน่อยครับ
MetalLB เป็น “Pure Software Solution” ที่จะจัดการเรื่อง network load-balancer ที่ implement บน Kubernetes โดยใช้ Standard Routing Protocols
หากสังเกตดีๆ จะมีคราบคล้ายเลือดติดอยู่บน Logo ฮ่าๆ (สงสัย dev กันจนแทบกระอักเลือด)
หากเรารัน Kubernetes บน Cloud ก็จะมี Network Topology หน้าตาประมาณนี้ (คร่าวๆ)
แต่ถ้าเป็น Bare-metal หรือ On-premises ล่ะ?
ตรงสีแดง เราจะเอาอะไรมากั้นให้ client เรียกผ่านตัวนั้น
คิดแบบบ้านๆ เลย
“ งั้นเราก็สร้างอีก 1 VM ขึ้นมารัน Nginx เลยสิ ความรู้ Nginx พอไปวัดไปวา น่าจะทำได้หน่า”
จะทำแบบนั้นก็ได้ แต่จะทำไปทำไม เดี๋ยวมันก็จะกลายเป็น Single point of failure (SPOF) อีก
“แล้วจะทำยังไงล่ะ”
ก็ติดตั้ง MetalLB ไง
Requirements:
- Kubernetes cluster เวอร์ชัน 1.9.0 หรือมากกว่า (ตรวจสอบได้จากคำสั่ง
kubectl verion
ในส่วนของ Server Version) - Network addon ที่ติดตั้งต้องรองรับ (ดูจากตารางด้านล่าง)
- IPv4 สำหรับ assign ให้ MetalLB
ในที่นี้ ผมใช้ addon ที่ชื่อว่า Flannel ซึ่งวิธีติดตั้งก็แค่ใช้คำสั่ง
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
อย่าลืมตั้งค่าใน /etc/sysctl.conf ตามนี้ด้วยนะ
net.bridge.bridge-nf-call-ip6tables = 1net.bridge.bridge-nf-call-iptables = 1net.ipv4.ip_forward = 1
เมื่อติดตั้งเสร็จแล้ว เราจะต่อด้วย MetalLB กัน
วิธีติดตั้ง MetalLB
รันคำสั่ง
kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.7.3/manifests/metallb.yaml
รอจน pull image จนเสร็จ จะได้ Pod “controller-xxxx-xxxx” โดยมี namespace เป็น metallb-system หากเข้าไปใน Pod แล้วไม่มี error ใดๆ แสดงว่าผ่าน
MetalLB รองรับ protocols ดังต่อไปนี้
ซึ่งบทความนี้ผมจะกล่าวเพียง Layer 2 เท่านั้น
การ config MetalLB
apiVersion: v1kind: ConfigMapmetadata:namespace: metallb-systemname: configdata:config: |address-pools:- name: defaultprotocol: layer2addresses:- 111.201.40.100-111.201.40.125
โปรดสังเกตตรง protocol ว่าผมใช้เป็น layer2 และ addresses ที่ใช้จะอยู่ใน range ระหว่าง 111.201.40.100–111.201.40.125 IP นี้ผมใช้เป็นตัวเลข Public IP (ผมสมมติขึ้นมา)
ข้อควรระวัง
- ต้องตั้งค่าไม่ให้ DHCP แจก IP เหล่านี้ เพราะจะเกิด IP conflict
ลองทดสอบกับ application เบาๆ อย่าง hello-app โดยใช้ docker image ของ Google
สร้าง Deployment ชื่อว่า hello-app มีจำนวน replica เท่ากับ 3 ใช้ image gcr.io/google-samples/hello-app:1.0 และระบุ port ใน container เป็น 8080
kubectl run hello-app --replicas=3 --image=gcr.io/google-samples/hello-app:1.0 --port=8080
จะได้
เมื่อเข้าไปดูใน Replica sets
ของผม Age แสดงเป็น 19 ชั่วโมง แต่ของท่านน่าจะเป็นหลักวินาที
ต่อไปใช้คำสั่งนี้เพื่อสร้าง Service แบบ LoadBalancerโดยใช้ Deployment ชื่อว่า hello-app และ expose port หมายเลข 80
kubectl expose deployment hello-app --type=LoadBalancer --port=80 --target-port=8080 --name=hello-app
เมื่อเข้าไปดูข้างใน
ขั้นตอนสุดท้าย คือการทดสอบเรียก Service จาก Client โดยใช้ curl จาก Terminal ของเครื่องผมเอง
จะเห็นว่าชื่อของ hostname ได้เปลี่ยนไปเมื่อ request ซ้ำๆ ซึ่งเป็นผลมาจาก Service กระจาย request ให้
ขอจบเพียงเท่านี้ หากมีตรงไหนผิดพลาดหรือข้อติชมประการใดรบกวนช่วยคอมเมนต์ด้านล่างจะเป็นพระคุณยิ่งครับ
References