Introduction to Istio, Part 6

·

8 min read

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.comtest.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.comtest.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(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 deploymentservice 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 DeploymentService:

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:

  1. Lưu tệp trên vào file hello-world.yaml.

  2. 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:

  1. Envoy sidecar proxy.

  2. Ứ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:

  1. Lưu tệp trên vào file vs-hello-world.yaml.

  2. 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.