Introduction to Istio, Part 6
Traffic Management
Tóm Tắt Chương
Chương này sẽ giải thích cách cấu hình định tuyến lưu lượng để đưa lưu lượng vào mesh cũng như cách phân chia lưu lượng giữa các dịch vụ chạy trong mesh. Chúng ta cũng sẽ tìm hiểu cách Istio giúp tăng cường độ bền của dịch vụ và cách tiêm lỗi vào các yêu cầu.
Mục Tiêu Học Tập
Sau khi kết thúc chương này, bạn sẽ có thể:
Hiểu cách để lộ dịch vụ ra từ cụm (cluster).
Hiểu cách Istio biết được nơi cần định tuyến lưu lượng và lưu lượng được định tuyến như thế nào.
Hiểu cách phân chia lưu lượng dựa trên trọng số và các thuộc tính yêu cầu khác.
Hiểu cách các tính năng độ bền dịch vụ, tiêm lỗi và ngắt mạch hoạt động.
Hiểu cách đưa các dịch vụ bên ngoài vào mesh bằng cách sử dụng tài nguyên ServiceEntry.
Gateway
Trong bài lab cài đặt trước đó, khi chúng ta cài đặt Istio bằng profile demo, nó đã bao gồm các cổng ingress và egress.
Cả hai cổng này là các deployment Kubernetes chạy một instance của Envoy proxy và hoạt động như các bộ cân bằng tải ở rìa của mesh. Cổng ingress nhận các kết nối đến, trong khi cổng egress nhận các kết nối đi ra khỏi cụm.
Bằng cách sử dụng cổng ingress, chúng ta có thể áp dụng các quy tắc định tuyến cho lưu lượng inbound vào cụm. Một phần của cổng ingress, một dịch vụ Kubernetes kiểu LoadBalancer sẽ được triển khai, cung cấp cho chúng ta một địa chỉ IP công khai.
Chúng ta có thể cấu hình cả hai cổng này bằng cách sử dụng tài nguyên Gateway. Tài nguyên Gateway mô tả các cổng được mở, các giao thức, cấu hình SNI (Server Name Indication) cho bộ cân bằng tải, v.v.
Cấu hình của tài nguyên Gateway điều khiển cách mà Envoy proxy lắng nghe trên giao diện mạng và chứng chỉ mà nó trình bày.
Dưới đây là một ví dụ về tài nguyên Gateway:
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: my-gateway
namespace: default
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- dev.example.com
- test.example.com
Tài nguyên Gateway trên cấu hình proxy Envoy như một bộ cân bằng tải, mở cổng 80 cho lưu lượng inbound. Cấu hình gateway sẽ được áp dụng cho proxy ingress của Istio, mà chúng ta đã triển khai vào namespace istio-system và gắn nhãn istio: ingressgateway. Trường hosts đóng vai trò như một bộ lọc và sẽ chỉ cho phép lưu lượng đi đến dev.example.com và test.example.com.
Để kiểm soát và chuyển tiếp lưu lượng đến một dịch vụ Kubernetes thực tế đang chạy trong cụm, chúng ta cần cấu hình một VirtualService với các tên máy chủ (hostname) khớp (ví dụ: dev.example.com và test.example.com) và sau đó gắn tài nguyên Gateway vào đó.
Cổng Ingress mà chúng ta triển khai như một phần của cài đặt Istio demo đã tạo một dịch vụ Kubernetes với loại LoadBalancer, và dịch vụ này sẽ nhận được một địa chỉ IP công khai, ví dụ:
kubectl get svc -n istio-system
Kết quả trả về sẽ tương tự như sau:
scssCopy codeNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-egressgateway ClusterIP 10.0.146.214 <none> 80/TCP,443/TCP,15443/TCP 7m56s
istio-ingressgateway LoadBalancer 10.0.98.7 XX.XXX.XXX.XXX 15021:31395/TCP,80:32542/TCP,443:31347/TCP,31400:32663/TCP,15443:31525/TCP. 7m56s
istiod ClusterIP 10.0.66.251 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP,853/TCP 8m6s
Lưu ý: Cách thức hoạt động của loại dịch vụ Kubernetes LoadBalancer phụ thuộc vào nơi và cách chúng ta chạy cụm Kubernetes. Đối với cụm Kubernetes quản lý trên đám mây (GCP, AWS, Azure, v.v.), tài nguyên load balancer sẽ được cấp phát trong tài khoản đám mây của bạn, và dịch vụ LoadBalancer của Kubernetes sẽ nhận được một địa chỉ IP công khai. Nếu bạn đang sử dụng Minikube hoặc Docker Desktop, địa chỉ IP công khai sẽ được thiết lập là localhost (Docker Desktop) hoặc, nếu sử dụng Minikube, nó sẽ ở trạng thái chờ (pending), và bạn sẽ phải sử dụng lệnh minikube tunnel để có được địa chỉ IP.
Ngoài cổng Ingress, chúng ta có thể triển khai cổng Egress để kiểm soát và lọc lưu lượng rời khỏi mesh của chúng ta.
Chúng ta có thể sử dụng cùng một tài nguyên Gateway để cấu hình cổng egress như chúng ta đã cấu hình cổng ingress. Cổng egress giúp tập trung hóa tất cả lưu lượng outgoing, ghi log và xác thực.
Trong bài lab này, chúng ta sẽ triển khai một ứng dụng Hello World lên cụm Kubernetes. Sau đó, chúng ta sẽ triển khai tài nguyên Gateway và một VirtualService liên kết với Gateway để tiếp xúc ứng dụng thông qua một địa chỉ IP công khai.
Trước khi tiếp tục, hãy đảm bảo rằng bạn đã có một cụm Kubernetes với Istio đã được cài đặt, và namespace mặc định đã được gắn nhãn để Istio có thể tự động tiêm sidecar vào các pod.
Chúng ta sẽ bắt đầu bằng cách triển khai tài nguyên Gateway. Trong tài nguyên này, chúng ta sẽ đặt trường hosts
là (dấu là bộ lọc đại diện cho tất cả các tên miền), để có thể truy cập vào cổng vào (ingress gateway) trực tiếp từ địa chỉ IP công khai mà không cần tên miền.
Nếu chúng ta muốn truy cập cổng vào qua tên miền, có thể đặt giá trị hosts
là tên miền (ví dụ: example.com
) và thêm địa chỉ IP công khai như một bản ghi A trong cài đặt DNS của tên miền.
Tài nguyên YAML của Gateway sẽ có cấu trúc như sau:
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- '*'
Lưu ý: Bạn có thể tải xuống các tệp YAML hỗ trợ và các tệp khác từ kho GitHub này.
Lưu tệp YAML trên thành gateway.yaml và triển khai Gateway bằng cách sử dụng lệnh sau:
kubectl apply -f gateway.yaml
Sau khi triển khai Gateway, nếu chúng ta thử truy cập vào địa chỉ IP công khai của ingress gateway, chúng ta sẽ nhận được lỗi HTTP 404, vì hiện tại không có VirtualServices nào liên kết với Gateway. Proxy cổng vào chưa biết cách chuyển tiếp lưu lượng vì chúng ta chưa định nghĩa bất kỳ tuyến đường nào.
Để lấy địa chỉ IP công khai của ingress gateway, chạy lệnh sau và kiểm tra giá trị trong cột EXTERNAL-IP:
kubectl get svc -l=istio=ingressgateway -n istio-system
Kết quả trả về sẽ giống như sau:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.0.98.7 [GATEWAY_IP] 15021:31395/TCP,80:32542/TCP,443:31347/TCP,31400:32663/TCP,15443:31525/TCP 9h
Trong suốt khóa học và các bài lab tiếp theo, chúng ta sẽ sử dụng GATEWAY_IP trong các ví dụ và văn bản khi nói về địa chỉ IP công khai của ingress gateway. Bạn có thể đặt biến môi trường với địa chỉ GATEWAY_IP như sau:
export GATEWAY_IP=$(kubectl get svc -n istio-system istio-ingressgateway -ojsonpath='{.status.loadBalancer.ingress[0].ip}')
Tiếp theo, chúng ta sẽ tạo một deployment và service cho ứng dụng Hello World. Đây là một ứng dụng web đơn giản hiển thị dòng chữ "Hello world".
Dưới đây là YAML cho Deployment và Service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
labels:
app: hello-world
spec:
replicas: 1
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- image: gcr.io/tetratelabs/hello-world:1.0.0
imagePullPolicy: Always
name: svc
ports:
- containerPort: 3000
---
kind: Service
apiVersion: v1
metadata:
name: hello-world
labels:
app: hello-world
spec:
selector:
app: hello-world
ports:
- port: 80
name: http
targetPort: 3000
Các bước thực hiện:
Lưu tệp trên vào file hello-world.yaml.
Triển khai ứng dụng và service bằng lệnh:
kubectl apply -f hello-world.yaml
Sau khi triển khai, kiểm tra các Pods và Service đã được tạo:
kubectl get po,svc -l=app=hello-world
Kết quả sẽ hiển thị thông tin của Pods và Service như sau:
NAME READY STATUS RESTARTS AGE
pod/hello-world-6bf9d9bdb6-r8bb4 2/2 Running 0 78s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello-world ClusterIP 10.0.155.147 <none> 80/TCP 78s
Lúc này, bạn sẽ thấy hai container chạy trên mỗi pod:
Envoy sidecar proxy.
Ứng dụng Hello World.
Chú ý: Dịch vụ hello-world
đã được tạo với kiểu ClusterIP
và đang lắng nghe trên cổng 80. Tuy nhiên, vì chưa có VirtualService, lưu lượng vẫn chưa được chuyển hướng qua Gateway để tiếp cận từ bên ngoài.
Bước tiếp theo là tạo một VirtualService cho service hello-world và liên kết nó với Gateway đã tạo.
Dưới đây là YAML cho VirtualService:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: hello-world
spec:
hosts:
- "*"
gateways:
- gateway
http:
- route:
- destination:
host: hello-world.default.svc.cluster.local
port:
number: 80
Giải thích:
hosts: Chúng ta sử dụng dấu
*
(wildcard matcher), giống như trong Gateway, để cho phép tất cả các tên miền. Nếu muốn, bạn có thể thay thế dấu*
bằng tên miền cụ thể.gateways: Liên kết VirtualService với Gateway mà chúng ta đã triển khai trước đó.
http.route.destination: Xác định dịch vụ đích là
hello-world.default.svc.cluster.local
, sử dụng tên dịch vụ đầy đủ để đảm bảo tính chính xác.
Các bước thực hiện:
Lưu tệp trên vào file vs-hello-world.yaml.
Tạo VirtualService bằng lệnh:
kubectl apply -f vs-hello-world.yaml
Kiểm tra VirtualService đã triển khai:
Sau khi triển khai, kiểm tra VirtualService:
kubectl get vs
Kết quả sẽ hiển thị thông tin về VirtualService như sau:
NAME GATEWAYS HOSTS AGE
hello-world [gateway] [*] 3m31s
Kiểm tra kết nối:
Để kiểm tra xem có thể truy cập ứng dụng hello-world qua Gateway hay không, bạn có thể sử dụng lệnh cURL hoặc trình duyệt.
Chạy lệnh cURL:
curl -v http://$GATEWAY_IP/
Hoặc mở địa chỉ http://$GATEWAY_IP/
trong trình duyệt.
Kết quả sẽ hiển thị phản hồi:
Hello World
Lưu ý: Header server: istio-envoy
cho thấy rằng yêu cầu đã được xử lý qua sidecar proxy của Envoy.