Chào các bạn tới với series về kubernetes. Đây là bài thứ 4 trong series của mình, ở các bài trước chúng ta đã nói về Pod (resource run application), ReplicaSet (resource hỗ trợ cho high availability application). Ở bài này chúng ta sẽ nói về Kubernetes Services, một resource cho phép chúng ta ra expose traffic cho Pod, để Pod có thể giao tiếp và xử lý request từ client.
Là một resouce sẽ tạo ra một single, constant point của một nhóm Pod phía sau nó. Mỗi service sẽ có một địa chỉ IP và port không đổi, trừ khi ta xóa nó đi và tạo lại. Client sẽ mở connection tới service, và connection đó sẽ được dẫn tới một trong những Pod ở phía sau.
Vậy service giúp ta những vấn đề gì? Mỗi thằng Pod nó cũng có địa chỉ IP riêng của nó, sao ta không gọi thẳng nó luôn mà thông qua service chi cho mất công? Để trả lời những câu hỏi này thì ta sẽ nói qua một vài vấn đề.
Có nghĩa Pod là một resource rất phù du, nó sẽ được tạo ra, bị xóa, và thay thế bằng một thằng khác bất cứ lúc nào, có thể là lúc ta muốn đổi một template khác cho Pod, Pod cũ sẽ bị xóa đi và Pod mới sẽ được tạo ra. Hoặc là trường hợp một woker node die, Pod trên worker node đó cũng sẽ die theo, và một Pod mới sẽ được tạo ra trên woker node khác.
Khi tạo thằng pod mới tạo ra, nó sẽ có một IP khác với thằng cũ. Nếu ta dùng IP của Pod để tạo connection tới client thì lúc Pod được thay thế với IP khác thì ta phải update lại code.
Có nghĩa là ta sẽ có nhiều pod đang chạy một ứng dụng của chúng ta để tăng performance. Ví dụ khi ta dùng ReplicaSet với replicas = 3, nó sẽ tạo ra 3 Pod. Vậy làm sao ta biết được nên gửi request tới Pod nào?
Thì để giải quyết những vấn để trên thì Kubernetes cung cấp cho chúng ta Services resource, Service sẽ tạo ra một endpoint không đổi cho các Pod phía sau, client chỉ cần tương tác với endpoint này.
Làm sao Service biết được nó sẽ chọn Pod nào để quản lý connection tới những Pod đó, nếu bạn còn nhớ label selectors ở những bài trước và cách ReplicaSet sử dụng label để quản lý Pod. Thì Services cũng sẽ sử dụng label selectors để chọn Pod mà nó quản lý connection.
Sample config
apiVersion: v1
kind: Service
metadata:
name: hello
spec:
selector:
app: hello-kube # label selectors Pod
ports:
- port: 80 # port of the serivce
targetPort: 3000 # port of the container that service will forward to
Service sẽ có 4 loại cơ bản là:
Đây là loại service sẽ tạo một IP và local DNS mà sẽ có thể truy cập ở bên trong cluster, không thể truy cập từ bên ngoài, được dùng chủ yếu cho các Pod ở bên trong cluster dễ dàng giao tiếp với nhau.
Ví dụ như sau, ta có một application cần xài redis, ta sẽ deploy một Pod redis và application của ta cần kết nối với Pod redis đó. Với redis thì connection string của nó sẽ có dạng như sau redis://<host-name>:<port>
, vậy ứng dụng ta sẽ kết nối với redis thế nào? Sau đây ta sẽ làm ví dụ tạo Pod redis và Service cho nó.
Tạo một file tên là hello-service.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- image: redis # redis image
name: redis
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
selector:
app: redis # label selectors Pod redis
ports:
- port: 6379 # port of the serivce
targetPort: 6379 # port of the container that service will forward to
kubectl apply -f hello-service.yaml
Bây redis của chúng ta sẽ có địa chỉ truy cập như sau redis://10.100.255.140:6379. Ta có thể thấy hostname của service của chúng ta ở đây là 10.100.255.140, ta có thể dùng địa chỉ này để các ứng ta deploy về sau truy cập được tới redis host.
Vậy nếu ta có các ứng dụng đã chạy sẵn, thì làm sao ta kết nối tới host này được, không lẻ chúng ta phải update lại code? Thì để giải quyết vấn đề này, thay vì truy cập redis host thằng IP, ta có thể truy cập thông qua DNS, kubernes có cung cấp cho chúng ta một local DNS bên trong cluster, giúp chúng ta có thể connect được tới host ta muốn thông qua DNS. Ta có thể connect redis với địa chỉ sau redis://redis:6379, với host name là tên của Service chúng ta đặt trong trường metadata.
Test thử service. Các bạn có thể tạo Pod để test bằng file config
apiVersion: v1
kind: Pod
metadata:
name: application
spec:
containers:
- image: 080196/hello-redis
name: application
Hoặc tạo bằng cli cho nhanh
kubectl run hello-redis --image=080196/hello-redis
Đây là code của application trong 080196/hello-redis image
const redis = require("redis");
const client = redis.createClient("redis://redis:6379")
client.on("connect", () => {
console.log("Connect redis success");
})
Kiểm tra log của pod, nếu in ra Connect redis success thì chúng ta đã kết nối được với redis host bằng dns
kubectl logs hello-redis
Clear resource
kubectl delete pod hello-redis
kubectl delete -f hello-service.yaml
ClusterIP giúp các ứng dụng deploy trong cluster của ta giao tiếp với nhau dễ dàng hơn nhiều. Còn nếu chúng ta muốn client từ bên ngoài có thể truy cập vào ứng dụng của chúng ta thì sao? Có 3 cách đó là dùng NodePort, LoadBalancer (hỗ trợ clound), Ingress.
Đây là cách đầu tiên để expose Pod cho client bên ngoài có thể truy cập vào được Pod bên trong cluster. Giống như ClusterIP, NodePort cũng sẽ tạo endpoint có thể truy cập được bên trong cluster bằng IP và DNS, đồng thời nó sẽ sử dụng một port của toàn bộ worker node để client bên ngoài có thể giao tiếp được với Pod của chúng ta thông qua port đó. NodePort sẽ có range mặc định từ 30000 - 32767. Ví dụ:
apiVersion: v1
kind: Service
metadata:
name: hello
spec:
selector:
app: hello-kube
type: NodePort # type NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30123 # port of the worker node
Client có thể gửi request tới Pod bằng địa chỉ 130.211.97.55:30123 hoặc 130.211.99.206:30123. Và application bên trong cluster có thể gửi request tới Pod với địa chỉ http://hello-kube
Giờ ta tạo thử NodePort service. Tạo một file tên là hello-nodeport.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: hello-rs
spec:
replicas: 2
selector:
matchLabels:
app: hello-kube
template:
metadata:
labels:
app: hello-kube
spec:
containers:
- image: 080196/hello-kube
name: hello-kube
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: hello
spec:
selector:
app: hello-kube
type: NodePort
ports:
- port: 3000
targetPort: 3000
nodePort: 31000
kubectl apply -f hello-nodeport.yaml
Test gửi request tới Pod với địa chỉ http://<your_worker_node_ip>:<node_port>
Khi bạn chạy kubernetes trên cloud, nó sẽ hỗ trợ LoadBalancer Service, nếu bạn chạy trên môi trường không có hỗ trợ LoadBalancer thì bạn không thể tạo được loại Service này. Khi bạn tạo LoadBalancer Service, nó sẽ tạo ra cho chúng ta một public IP, mà client có thể truy cập Pod bên trong Cluster bằng địa chỉ public IP này. Ví dụ
apiVersion: v1
kind: Service
metadata:
name: kubia-loadbalancer
spec:
selector:
app: kubia
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
Ingress là một resource cho phép chúng ta expose HTTP and HTTPS routes từ bên ngoài cluster tới service bên trong cluster của chúng ta. Ingress sẽ giúp chúng ta gán một domain thực tế với service bên trong cluster. Ví dụ:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubia
spec:
rules:
- host: kubia.example.com # domain name
http:
paths:
- path: /
backend:
serviceName: kubia-nodeport # name of the service inside cluster
servicePort: 80
Ta cũng có thể mapping nhiều service với cùng một domain. Ví dụ:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubia
spec:
rules:
- host: kubia.example.com
http:
paths:
- path: /bar
backend:
serviceName: kubia-bar
servicePort: 80
- path: /foo
backend:
serviceName: kubia-foo
servicePort: 80
Ingress là resource hữu dụng nhất để expose HTTP và HTTPS của Pod ra ngoài. Bạn có thể đọc nhiều hơn về Ingress ở đây.
Vậy là chúng ta đã tìm hiểu xong về Kubernetes Servies. Sử dụng nó khi bạn muốn expose traffic của Pod và mở connection cho client bên ngoài truy cập vào Pod của chúng ta. Cảm ơn các bạn đã đọc bài của mình. Nếu có thắc mắc hoặc cần giải thích rõ thêm chỗ nào thì các bạn có thể hỏi dưới phần comment. Hẹn gặp lại các bạn ở bài tiếp theo mình sẽ nói về Kubernetes Deployment, đây là resource được sử dụng nhiều trong thực tế hay thì ReplicaSet, nó sẽ giúp chúng ta trong quá trình deploy một version mới của dự án mà không bị downtime.
Nguồn: viblo.asia