จัดการกับ External Service อย่างไรบน Kubernetes

Apipol Sukgler
golfapipol.me
Published in
2 min readJun 11, 2019

ในการพัฒนาซอฟต์แวร์นั้น นอกเหนือจาก Service ที่เราเขียนแล้ว Deploy ใช้งานกันเอง ยังมี Service อื่นๆ ที่จะต้องไปเชื่อมต่อ ซึ่งเมื่อเราคิดถึง Principle ในการออกแบบ Application เพื่อให้เหมาะสำหรับ Cloud Native ที่ได้ยินกันคุ้นหู นั่นก็คือ 12 Factors

ในข้อที่ 7 ของ 12 Factors คือ Port Binding

VII. Port binding
Export services via port binding
The web app exports HTTP as a service by binding to a port, and listening to requests coming in on that port

หมายถึง เวลาที่ Application คุยกับ Service อื่นๆ สิ่งที่คุยกันให้ binding ผ่าน port ไม่ใช่ IP เพราะ หากเราใช้ IP ในการ binding service ลองจินตนาการว่า server ที่เรามีเป็นร้อยตัว ถ้าจะต้องมานั่งแก้ Config IP ทุกครั้งที่ Scale Service ก็คงจะไม่ Productive เท่าไหร่

แล้วทำอย่างไรล่ะ

ใน Docker และ Kubernetes มีสิ่งหนึ่งที่ถูก Build-in อยู่ภายในอยู่แล้ว ที่เราไม่รู้นั่นก็คือ Service Discovery หากเราสังเกตุใน Docker เราจะสามารถเรียกใช้ container แต่ละตัวได้ด้วยชื่อของ Container name ไม่ใช่วง IP ของแต่ละ Container ภายใน ใน docker compose ที่เราสามารถ scale service ขึ้นหลายๆ ตัวแต่เรียกใช้ผ่านชื่อ service เหมือนเดิม โดยการ route request จะเข้าไปใน service แบบ Round robin

การ Mapping External Service ใน Kubernetes

ในการ Mapping External Service จะมีอยู่ 2 อย่างที่ต้องใช้ คือ Service และ Endpoint ซึ่งทำได้ 3 แบบดังนี้

1. Service ที่อยู่ภายนอก Cluster ที่เป็น IP Address

ยกตัวอย่างเช่น Database โดยส่วนมากเราจะสร้าง database instance แยกออกมาจาก kubernetes cluster

mongoDB server ที่เราสร้างแยกไว้จะมี IP อยู่

อันดับแรก เพิ่ม service เพื่อทำให้ส่ง request มายัง service ได้

//Service
kind: Service
apiVersion: v1
metadata:
name: mongo
Spec:
type: ClusterIP
ports:
- port: 27017
targetPort: 27017

จากนั้นสร้าง Endpoint Object เพื่อรับ traffic ที่เข้ามาจาก Service

kind: Endpoints
apiVersion: v1
metadata:
name: mongo
subsets:
- addresses:
- ip: 10.240.0.4
ports:
- port: 27017

เราสามารถเรียกใช้ผ่าน ชื่อ service ได้เลยดังนี้

mongodb://mongo

2. Service จากภายนอกที่เป็นลักษณะ URL

กรณีใช้ third party service อย่างเช่น mlab ที่เป็น Database-as-a-service for Mongo

mongodb://<dbuser>:<dbpassword>@ds149763.mlab.com:49763/dev

เราสามารถกำหนดชื่อใหม่โดยเปลี่ยนจาก ds149763.mlab.com เป็น mongo ได้ดังนี้

kind: Service
apiVersion: v1
metadata:
name: mongo
spec:
type: ExternalName
externalName: ds149763.mlab.com

ก็จะสามารถเข้าถึงได้โดยใช้ชื่อ mongo

mongodb://<dbuser>:<dbpassword>@mongo:<port>/dev

3. Service จากภายนอกที่มีลักษณะของ Dynamic Port

ในกรณีที่ third party service ไม่ได้เป็น fixed port อย่างใน mlab.com ที่ instance ที่เราสร้างจะ random port มาให้

เราสามารถ nslookup เพื่อเช็คก่อนว่า IP อะไร

nslookup ds149763.mlab.com

จากนั้นสร้าง service, endpoint เพื่อใช้ map จาก port ที่ไม่ได้เป็น specific ให้ application ในแต่ละ environment ไม่ต้องแก้ config แต่ละ environment ให้มาแก้ที่ endpoint กับ service แทน

kind: Service
apiVersion: v1
metadata:
name: mongo
spec:
ports:
- port: 27017
targetPort: 49763
---
kind: Endpoints
apiVersion: v1
metadata:
name: mongo
subsets:
- addresses:
- ip: 35.188.8.12
ports:
- port: 49763

ก็จะสามารถ access จากภายใน cluster ผ่านทาง mongo ได้

mongodb://<dbuser>:<dbpassword>@mongo/dev

การ Mapping External service ทำให้เราไม่ต้องเปลี่ยนแปลง config ของ Application ทุกครั้งที่มีการเปลี่ยนแปลงกับ external service

Reference:

https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-mapping-external-services

https://12factor.net/

--

--

Apipol Sukgler
golfapipol.me

Full-Stacked Developer. Let’s share to the world :)