Hiểu và thực hành Networking trong Kubernetes với ví dụ BE + FE

0 0 0

Người đăng: Nguyen Duy Hieu

Theo Viblo Asia

1. Giới thiệu

Sau bài Triển khai ứng dụng full-stack với k8s cho người mới. Trong đó, mình đã giới thiệu và thực hành với các resource của k8s như Deployment, Service, StatefulSet,..., giúp mọi người có thể thực hành và dựng được 1 app cơ bản, hoàn chỉnh chạy trong cluster từ minikube. Tuy nhiên ở bài viết đó thì chưa có giải thích, đào sâu vào các câu hỏi như là các thành phần giao tiếp với nhau như nào, tại sao chỗ này phải dùng service, tại sao trong service, chỗ dùng NodePort, chỗ dùng ClusterIP,... rất nhiều câu hỏi về kiến trúc, về network,.. mà trong bài trên chưa đào sâu vào để hiểu. Do vậy, trong bài này sẽ tập trung vào các ví dụ đơn giản để làm rõ và hiểu hơn về Networking trong k8s, từ khái niệm đến các thực hành, để bạn có một hình dung trực quan về cách các resource giao tiếp với nhau trong cluster.

2. Pod IP & vì sao phải cần Service

Khi chạy app trong Kubernetes, mỗi Pod được gán một IP riêng. Nhưng IP này không cố định: khi Pod chết/rollback/scale là IP của Pod đổi ngay. Vì thế, nếu FE hoặc Pod khác gọi trực tiếp vào IP cũ Pod → rất dễ “toang” sau một lần redeploy/restart.

Dưới đây là 1 ví dụ, mà bạn có thể làm theo để thấy được vấn đề và cách giải quyết vấn đề bằng Service

2.1. Thử gọi trực tiếp Pod IP (và lý do thất bại)

  • Bước 1: Tạo một Pod backend đơn giản (chưa có Service)

Ở đây mình dùng image nginxdemos/hello:plain-text là một demo image do team NGINX cung cấp, dùng để test nhanh NGINX và môi trường container/k8s. Nó đơn giản là nhận 1 request và trả về response dạng text.

Các bạn nhớ bật minikube để có thể thực hành ở local nhé. Bật terminal lên chạy kubectl apply -f be-pod.yaml Đợi 1 lúc cho pod khởi chạy xong thì chạy lệnh kubectl get pod be-pod -o wide để thấy được IP của Pod be-pod. (ví dụ: 10.244.0.209)

  • Bước 2: Tạo tạm một Pod “client” để test call pod be-pod bằng curl

kubectl run curl --image=curlimages/curl -it --rm --restart=Never -- sh

Lệnh này dùng image curlimages/curl chưa duy nhất curl để test HTTP request từ trong cluster và mở shell sau khi pod được tạo thành công

Khi vào shell của pod curl này thì gõ lệnh curl -s http://10.244.0.209

Bạn sẽ thấy 1 response trên terminal:

Vậy là từ Pod curl đã call thành công sang be-pod khi biết được IP của pod be-pod

  • Bước 3: Mô phỏng Pod restart => IP đổi

Tuy nhiên chúng ta sẽ mô phỏng tình huống pod bị kill, restart, redeploy,... Chúng ta chạy các lệnh sau:

kubectl delete pod be-pod
kubectl apply -f be-pod.yaml
kubectl get pod be-pod -o wide

Sau khi chạy lại pod và check ip pod, chúng ta thấy ip của pod đã thay đổi. Khi này, thực hiện lại bước 2 với ip pod cũ thì sẽ bị lỗi. Đây là lý do không bao giờ nên setup FE gọi trực tiếp Pod IP trong K8s

2.2. Dùng Service (ClusterIP) để có định danh ổn định + load balancing

Trong bài viết trên, chúng ta thấy có sự xuất hiện của service. Service sẽ cũng cấp 1 định danh ổn định đại diện cho các Pod trong 1 nhóm nào đó (chọn qua selector)

  • Bước 4: Tạo Service cho backend

Ở đây, selector.app phải trỏ đúng vào metadata.labels.app trong be-pod.yaml để service biết rằng nó cần quản lý các pod có nhãn là be

Trong terminal, chúng ta chạy: kubectl apply -f be-svc.yaml

Sau khi apply thành công thì chạy kubectl get svc backend để xem thông tin service của be-pod

Cách setup service (dùng ClusterIP) sẽ cung cấp 1 IP cho service này, và chúng ta có thể thấy None ở ExternalIP, tức là không thể gọi đến service này từ ngoài cluster.

  • Bước 5: Gọi qua DNS Service (ổn định, không sợ Pod đổi IP)

Chúng ta sẽ lại dùng pod curl để call thử đến be-pod thông qua service

Lúc này chúng ta hoàn toàn ko cần quan tâm đến Pod IP, ngay cả khi restart lại be-pod thì nhờ service, chúng ta vẫn có thể thực hiện các request call đến be-pod

2.3. Thêm Deployment + scale để thấy Service load balance

Trong thực tế, có thể sẽ có nhiều tình huống crash pod, (ở local thì thường chạy với 1 pod để phù hợp với sự hạn chế tài nguyên của máy tính). Do vậy thay vì Pod đơn lẻ, ta demo với Deployment (2 replicas) để scale và test với load balancing ( 1 cơ chế cân bằng tải của service )

File deployment.yaml

kubectl apply -f be-deploy.yaml
kubectl get pods -l app=be -o wide

Tiếp tục dùng pod curl để chạy thử lệnh: for i in 1 2 3 4 5; do curl -s http://backend | grep 'Server name'; done

Bạn sẽ thấy “Server name” thay đổi qua lại giữa 2 Pod khác nhau → chứng tỏ Service đang cân bằng tải cho bạn. Còn về các cách, hay là các thuật toán cân bằng tải sẽ được trình bày trong 1 bài viết trong tương lai gần. Đến đây, chúng ta đã có thể hiểu phần nào tại sao không dùng pod IP trong thực tế, cách giao tiếp trong cluster, cách từ 1 FE sẽ call đến BE trong môi trường k8s (bằng cách set biến env trong FE, ví dụ API_BASE_URL=http://backend:80)

3. Các loại Service trong Kubernetes

Trong phần trước, bạn đã thấy ClusterIP giải quyết bài toán Pod IP “ngắn hạn”. Tuy nhiên, đôi khi chúng ta cần mở Service cho người dùng bên ngoài cluster truy cập (ví dụ: frontend app, public API). Đây là lúc cần tìm hiểu kỹ hơn các loại Service khác

3.1. ClusterIP (mặc định)

  • Là gì?
    • Đây là Service mặc định trong Kubernetes.
    • Chỉ cho phép truy cập bên trong cluster.
    • DNS: <service-name>.<namespace>.svc.cluster.local
  • Use case:
    • BE ↔ DB (nội bộ)
    • FE ↔ BE (nếu cả hai đều nằm trong cluster)

3.2. NodePort

  • Là gì?
    • Mở một port cố định (30000–32767) trên mỗi Node
    • Bạn có thể truy cập Service từ ngoài cluster thông qua: http://<NodeIP>:<NodePort> (NodeIP lấy bằng minikube ip)
  • Use case:
    • Demo local với Minikube/K3s
    • Khi chưa có Ingress/LoadBalancer
  • Yaml mẫu:

3.3. LoadBalancer

  • Là gì?
    • Khi bạn dùng Kubernetes trên cloud (AWS/GCP/Azure), Service type LoadBalancer sẽ nhờ cloud cấp IP public/Load Balancer thật
    • Người dùng chỉ cần truy cập IP public đó
  • Use case:
    • Production trên cloud.
    • Khi cần expose trực tiếp service ra Internet.
  • Yaml mẫu:

Truy cập thông qua: http://<cloud-public-ip>. Và chỉ hoạt động nếu cluster chạy trên cloud provider có hỗ trợ (EKS, GKE, AKS…)

4. Kinh nghiệm & Best Practice khi làm việc với Networking trong Kubernetes

Sau khi thực hành qua ClusterIP, NodePort, LoadBalancer, mình rút ra được một số kinh nghiệm nho nhỏ. Nếu bạn cũng mới bắt đầu, hy vọng sẽ giúp tiết kiệm kha khá thời gian.

  • Luôn dùng Service name thay vì Pod IP
  • Chọn đúng loại Service cho đúng mục đích
  • NodePort – đừng hardcode nếu không cần

Tài liệu tham khảo

  1. https://kubernetes.io/docs/concepts/cluster-administration/networking/
  2. https://www.vmware.com/topics/kubernetes-networking

Bình luận

Bài viết tương tự

- vừa được xem lúc

Đề thi interview DevOps ở Châu Âu

Well. Chào mọi người, mình là Rice - một DevOps Engineers ở đâu đó tại Châu Âu.

0 0 118

- vừa được xem lúc

In calculus, love also means zero.

Mình nhớ hồi năm 2 đại học, thầy giáo môn calculus, trong một giây phút ngẫu hứng, đã đưa ra cái definition này. Lúc đấy mình cũng không nghĩ gì nhiều.

0 0 89

- vừa được xem lúc

Chuyện thay đổi

Thay đổi là một thứ gì đó luôn luôn đáng sợ. Cách đây vài tháng mình có duyên đi làm cho một banking solution tên là X.

0 0 71

- vừa được xem lúc

Pet vs Cattle - Thú cưng và gia súc

Khái niệm. Pets vs Cattle là một khái niệm cơ bản của DevOps. Bài viết này sẽ nói về sự phát triển của các mô hình dịch vụ từ cốt lõi Pets and Cattle. 1.

0 0 58

- vừa được xem lúc

Git workflow được Google và Facebook sử dụng có gì hay ho

Với developer thì Git hẳn là công cụ rất quen thuộc và không thể thiếu rồi. Thế nhưng có mấy ai thực sự hiểu được Git.

0 0 113

- vừa được xem lúc

Kubernetes - Học cách sử dụng Kubernetes Namespace cơ bản

Namespace trong Kubernetes là gì. Tại sao nên sử dụng namespace.

0 0 142