Front end Pod and Back end Pod Communication

Phai Panda
Tech INNO
Published in
4 min readSep 7, 2020

มีโอกาสได้สอนน้องได้รู้จักกับ Kubernetes สอนพื้นฐานเขาไปแล้วเรื่อง Pod, ReplicaSet, Deployment และ Service คำถามจากน้องคือเราจะ implement เรื่องนี้ให้พอจะเห็นเป็นรูปธรรมกว่านี้ได้อย่างไร บทความนี้นำมาเสนอครับ

intro

เห็นภาพเปิดตัวอย่าเพิ่งเข้าใจว่าเรื่องนี้ต้องใช้ต้นทุนของ Microservice แต่อย่างใด มันเริ่มต้นจากความคิดง่ายดายที่ว่า เมื่อเขียนโปรแกรมเสร็จหนึ่งโปรเจกต์แล้วจะต้องนำไป deploy ตรงนั้นแหละจะดูแลต่ออย่างไร ลองคิดตามเล่นๆอย่างนี้นะ

  1. ก็ปล่อยมันอยู่บนเครื่อง server ทำงานไปเรื่อยๆของมัน
  2. ถ้า server ล่มก็แค่ reboot ใหม่
  3. หาใครสักคนมาดูแลมันแทนเราดีกว่า เราจะได้ใช้เวลากับอย่างอื่นต่อ
  4. ถ้าปริมาณการใช้งาน (คำขอ requests) เพิ่มมากขึ้นสุดท้ายมันก็ต้องล่มแน่ๆ จะแก้ไขอย่างไรได้บ้าง

ถ้าคิดถึงข้อ 3 และ 4 นั่นแสดงว่าเราต้องการโปรแกรมประเภทที่มาดูแลโปรเจกต์อีกที เช่น Kubernetes ไม่อย่างนั้นคนคนนั้นก็ต้องเป็นเราเอง

ที่มา: น้องรู้จัก Docker

เข้าเรื่องเลยนะครับ น้องถามว่า ถ้าเขาเขียนโปรแกรมเสร็จแล้ว เขาจะแน่ใจได้อย่างไรว่ามันจะทำงานได้ดีประหนึ่งเสมือนมันทำงานอยู่บนเครื่องคอมฯของเขา?

คำตอบ ก็ต้องการโปรแกรมจำลอง OS แล้วติดตั้งทุกอย่างที่เหมือนกับเครื่องคอมฯของเขาลงไปใน OS นั่น

ทำไมล่ะ?

คำตอบ หากเครื่อง server สามารถเลือกติดตั้ง OS และโปรแกรมที่ใช้รันโปรเจกต์อย่างเดียวกันได้ก็จะลดความผิดพลาดที่เกิดขึ้นได้มหาศาล (แทบเป็นศูนย์) ถูกต้องไหม

นั่นทำให้น้องรู้จักกับโปรแกรมจำลองสภาพแวดล้อมในการพัฒนาและ deploy โปรเจกต์ชื่อ Docker

Docker จะบอกให้สร้างไฟล์ชื่อ Dockerfile จากนั้นให้เรานิยามความต้องการลงไป

  • เริ่มจากเลือก OS
  • เลือกโปรแกรมที่จำเป็นต่อการทำงานของโปรเจกต์
  • กำหนด port
  • คำสั่งสั่งโปรเจกต์ทำงาน

Docker จะ build Dockerfile เป็น Docker Image เก็บไว้ที่ Docker Registry รอให้นำไปสร้างเป็น Docker Container ซึ่งเมื่อ container นี้ทำงานก็คือโปรเจกต์ของเราทำงาน

รูปภาพต่อไปนี้แสดงให้เห็นว่าใน container มี OS และใน OS ติดตั้ง web server โดยที่โปรแกรมของเรา (web) ถูก deploy อยู่บน web server

a container contains a project

ที่มา: น้องรู้จัก Pod

ในขณะที่เครื่อง server ได้ติดตั้งโปรแกรม Docker เช่นเดียวกับเครื่องคอมฯของน้อง เมื่อเขาพัฒนาและทดสอบโปรแกรมบนเครื่องคอมฯของตนเสร็จเขาก็มั่นใจว่ามันต้องทำงานได้เป็นอย่างดีบนเครื่อง server ไม่ต่างกัน — นั่นทำให้เขาสบายใจ

เขาตั้งคำถามต่อไปว่า มันรู้สึกขี้เกียจนะเวลาแก้ bug หรือเพิ่มอะไรเข้าไปในโปรแกรมแล้วต้องมาสร้าง Docker Image ใหม่ แถมยังไม่อาจทราบได้เลยว่าสุขภาพของโปรแกรมนั่นยังดีอยู่ไหมหรือตายไปแล้ว ล่มไปแล้วหรือยังไง คงดีกว่านี้ถ้ามีใครสักคนคอยติดตามเรื่องนี้แทนเขา มีใครแบบนั้นไหม?

คำตอบ มีครับ ถ้าอยากได้คนที่คอยดูแลโปรเจกต์ที่อยู่ใน Docker ให้อีกทีคนคนนั้นต้องเก่งเรื่อง orchestration โดยพยายามรักษา state ของโปรแกรมให้เป็นไปตามความต้องการและเป็นปกติอยู่เสมอ ให้เลือกระหว่าง Docker Swarm ไม่ก็ Kubernetes

Docker Swarm ยังไม่รู้จักงั้นแนะนำ Kubernetes ให้ก่อนเลยแล้วกัน ที่นี่

ออบเจ็กต์ที่เล็กที่สุดใน Kubernetes เรียกว่า Pod ในหนึ่ง Pod มีได้หลาย container

1 Pod : 1 container
ตามคำแนะนำอัตราส่วนที่ 1 ต่อ 1 นั้นดีที่สุดทั้งในด้านการพัฒนาและการ scale

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

label ประกอบด้วย key กับ value คู่กัน แต่ละ Pod สามารถมีได้หลาย label

รูปภาพต่อไปนี้แสดงให้เห็นว่าใน Pod มี container และตัวมันถูกกำกับด้วย label คู่หนึ่ง

a pod contains a container

ที่มา: น้องรู้จัก ReplicaSet

Kubernetes กล่าวว่าเมื่อ Pod ตาย มันจะตายไปเลย ไม่ถูกสร้างขึ้นใหม่ น้องบอกได้ไง ไหนบอกว่ามันสามารถรักษา state ของโปรแกรมของเขาให้เป็นปกติได้?

คำตอบ ได้แต่ต้องหาพี่เลี้ยงให้กับ Pod พี่เลี้ยงคนนี้มีชื่อว่า ReplicaSet

ReplicaSet จะพยายามรักษา state ของ Pod ในแง่ของจำนวนให้เป็นไปตามความต้องการผ่านค่าของ replicas การลดลงหรือเพิ่มขึ้นของค่านี้คือการ scale Pods

ReplicaSet มี selector ไว้จับคู่ label ที่ต้องการให้มันใส่ใจผ่านค่าของ matchLabels

เมื่อใดก็ตามที่ Pod มีเหตุให้ถูกทำลายหรือใช้งานไม่ได้ ReplicaSet จะพยายามสร้าง Pod นั้นขึ้นมาใหม่

ที่มา: น้องรู้จัก Deployment

ความจริงแล้ว ReplicaSet จะถูกสร้างให้เป็นส่วนหนึ่งของออบเจ็กต์ Deployment โดยอัตโนมัติอยู่แล้ว นั่นเท่ากับว่า Deployment สามารถสร้างและทำลาย ReplicaSet ได้

เนื่องจากการพยายามรักษา state ของ Pod เมื่อไหร่ก็ตามที่เกิดการเปลี่ยนแปลงค่าของ replicas จะมีผลให้ Deployment สร้าง ReplicaSet ขึ้นใหม่แล้วย้าย Pod ไปยังสถานที่ใหม่ จากนั้นค่อยทำลาย ReplicaSet เดิมทิ้ง

บอกตามตรงน้องยังไม่สามารถเข้าใจพฤติกรรมของออบเจ็กต์ ReplicaSet และ Deployment ทว่า Pod กลับเป็นของที่เข้าใจได้ง่ายกว่า ดังนั้นขอสัญญาว่าโอกาสถัดไปจะนำเสนอการเขียน script ไฟล์ .yml ของ Kubernetes จาก Pod แล้วจึงเปลี่ยนเป็น ReplicaSet และ Deployment เพื่อให้เกิดความเข้าใจร่วมกันครับ

ความตั้งใจ

น้องได้เขียนโปรเจกต์ด้วย Vue.js เสร็จแล้ว ให้เป็นฝั่ง front end Pod ส่วนผมได้เขียนโปรเจกต์ด้วย Express.js เป็น REST API เสร็จแล้ว ให้เป็นฝั่ง back end Pod

คำถามของน้องก็คือ เราจะ implement เรื่องนี้ให้พอจะเห็นเป็นรูปธรรมกว่านี้ได้ไหม อยากให้ Pod ของฝั่ง front end คุยกับ Pod ฝั่ง back end จะทำอย่างไร

คำตอบ สามารถให้ Pod ทั้งสองคุยกันได้ผ่าน Service เช่นนั้นประดา Service จะเป็นเสมือนสะพานเชื่อมระหว่างตัวมันเองกับ Pod ในอัตราส่วน 1 Service: 1 Pod เสียก่อน

  • todo-front-sit Service รับผิดชอบ todo-front-sit Pod
  • todo-api-sit Service รับผิดชอบ todo-api-sit Pod

Service จะใช้ label เลือกไปยัง Pod ที่มันต้องรับผิดชอบ

  • app: todo-front-sit label ถูกเลือกโดย todo-front-sit Service
  • app: todo-api-sit label ก็ถูกเลือกโดย todo-api-sit Service

รูปภาพต่อไปนี้แสดงให้เห็นว่า Service ใช้ selector จับคู่ไปยัง label ของ Pod

the service select pod label

และหลังจากนั้นเมื่อใดที่โปรแกรมฝั่ง front end Pod ต้องการเรียกใช้ api (ในที่นี้คือ REST API) ก็ให้เรียกไปที่ชื่อของ Service ฝั่ง back end แทน

เท่ากับว่าโปรแกรมฝั่ง front end Pod ต้องมีสิ่งที่เรียกกว่า proxy คอยเปลี่ยน path ที่ใช้ระบุไปยัง domain name หรือ IP address ของฝั่ง back end

ตัวอย่างนี้เราได้เลือก Nginx เป็น web server กำหนดให้ไฟล์ nginx.conf ทำหน้าที่นี้ (ตัดมาแค่บางส่วน)

...location /api/ {  proxy_pass http://todo-api-sit:3000/;}...

เมื่อให้ path ดังกล่าวคือ /api/ คราวใดที่ถูกเรียกก็จะเปลี่ยนเป็น http://todo-api-sit:3000/ โดยที่ todo-api-sit และ 3000 คือชื่อและ port ที่ได้กำหนดไว้กับ Service ฝั่ง back end ตามลำดับ

ภาพต่อไปนี้แสดงให้เห็นว่า back end มี Service ชื่อ todo-api-sit อนุญาตให้ใช้ได้ภายใน cluster เท่านั้น (จึงมี type เป็น ClusterIP) และถูกเรียกโดย Nginx proxy

nginx proxy pass to back end service by service name

ภาพรวมทั้งหมด

front end Pod จะคุยกับ back end Pod ในฝั่ง server ด้วย Nginx proxy ขณะที่ todo-front-sit Service ถูกเปิดไว้เป็นทางเข้าแก่ client ให้เรียกมายัง server ได้

front end pod and back end pod communication

อธิบายได้ว่า Service ฝั่ง front end ชื่อ todo-front-sit อนุญาตให้ถูกเรียกใช้ได้จากภายนอก cluster (จึงมี type เป็น NodePort) ด้วย port ที่เรากำหนดให้หมายเลข 30091

ก็หวังว่าทั้งหมดที่บอกเล่าไปจากความคำถามและความสงสัยของน้องจะช่วยให้เพื่อนๆมือใหม่เกิดจินตนาการสามารถประยุกต์ใช้ Pod และ Service ตลอดจนเข้าใจการ implement Kubernetes กับโปรเจกต์ของเพื่อนๆนะครับ

แล้วเจอกันบทความหน้า สวัสดีจ้า

--

--