Introduction to Istio, Part 12

·

9 min read

Extending the Mesh

Mở rộng tính năng của Istio Service Mesh

Chương này giải thích một số cách để mở rộng tính năng của Istio Service Mesh. Chúng ta sẽ tìm hiểu về các khái niệm cơ bản của proxy Envoy, cách sử dụng tài nguyên EnvoyFilter để tùy chỉnh cấu hình của Envoy, và cách sử dụng các plugin Wasm để mở rộng tính năng của Envoy proxy.

Mục tiêu học tập

Đến cuối chương này, bạn sẽ có thể:

  1. Hiểu các thành phần cơ bản của Envoy proxy.

  2. Hiểu cách tùy chỉnh cấu hình của Envoy proxy bằng tài nguyên EnvoyFilter.

  3. Hiểu cách xây dựng một plugin Wasm cơ bản bằng GoProxy-Wasm SDK.

  4. Hiểu cách sử dụng tài nguyên WasmPlugin để triển khai plugin Wasm vào Istio Service Mesh.

Tổng quan về Envoy Proxy

Trước khi giải thích tài nguyên EnvoyFilter, chúng ta cần tìm hiểu tổng quan về cấu hình của Envoy và các thành phần cơ bản của nó.

Cấu hình Envoy là một file JSON được chia thành nhiều phần. Các thành phần cơ bản và các khái niệm cần hiểu được minh họa trong sơ đồ dưới đây:

Các thành phần chính của Envoy

  1. Listeners:

    • Đây là nơi Envoy lắng nghe các kết nối đến (inbound traffic).

    • Mỗi listener định nghĩa các địa chỉ IP, cổng, và giao thức (HTTP, TCP, v.v.) mà Envoy sẽ sử dụng.

  2. Filters:

    • Các bộ lọc được áp dụng trên traffic, giúp thực hiện các nhiệm vụ như giải mã HTTP, nén dữ liệu, hay thực hiện kiểm tra bảo mật.
  3. Clusters:

    • Một cluster đại diện cho một nhóm các dịch vụ backend mà Envoy có thể gửi traffic đến.

    • Envoy sử dụng các cluster để quản lý kết nối và cân bằng tải giữa các endpoint.

  4. Routes:

    • Định nghĩa cách Envoy định tuyến các request.

    • Một route chỉ định URL nào nên được chuyển đến cluster nào.

  5. Endpoints:

    • Mỗi cluster chứa một danh sách endpoint — các địa chỉ IP và cổng thực tế nơi các dịch vụ backend chạy.
  6. Virtual Hosts:

    • Các host ảo cho phép Envoy xử lý nhiều tên miền trên cùng một listener.

    • Chúng chứa các định nghĩa routes.

Những thành phần trên giúp Envoy thực hiện nhiệm vụ của một proxy hiện đại với khả năng cân bằng tải, mã hóa mTLS, và quản lý lưu lượng.

Listeners trong Envoy

Listeners là các vị trí mạng (network locations) được định danh, thường bao gồm địa chỉ IP và cổng (port). Envoy lắng nghe tại các vị trí này để nhận kết nối và xử lý các yêu cầu. Trong Istio, nhiều listener được tự động tạo cho mỗi sidecar proxy.

Ví dụ, có một listener được gắn với địa chỉ 0.0.0.0:15006, nơi tất cả lưu lượng đi vào (incoming traffic) pod được định tuyến. Một ví dụ khác là listener 0.0.0.0:15001, nơi lưu lượng đi ra (outgoing traffic) từ pod được định tuyến.

Giữa các listenerroute, các yêu cầu trong Envoy đi qua một chuỗi các filter (bộ lọc). Các filter này có thể:

  • Xử lý và bổ sung thông tin vào yêu cầu,

  • Sinh ra số liệu thống kê,

  • Chuyển đổi giao thức,

  • Hoặc thay đổi nội dung của các yêu cầu.

Nhờ đó, Envoy không chỉ đóng vai trò như một proxy thông thường mà còn cung cấp các khả năng nâng cao như theo dõi hiệu suất, quản lý giao thức, và cải thiện bảo mật.

Envoy Filters

Khi một yêu cầu được gửi tới Envoy, nó bắt đầu tại listener và được xử lý qua một danh sách các filter theo thứ tự gọi là filter chain.
Mỗi filter trong chuỗi này có thể bổ sung thông tin cho yêu cầu và quyết định:

  • Chuyển yêu cầu đến filter tiếp theo hoặc

  • Dừng xử lý yêu cầu tại đó.

Filter cuối cùng trong chuỗi chịu trách nhiệm định tuyến yêu cầu đến đích của nó.

Ở mức tổng quan, Envoy chia filter thành ba loại chính:

1. Listener Filters

Các listener filter làm việc với dữ liệu thô (raw data) và có khả năng thao tác metadata của các kết nối ở tầng 4 (L4) của mô hình OSI trong giai đoạn kết nối ban đầu.

Ví dụ phổ biến là TLS inspector filter, dùng để:

  • Xác định xem kết nối có được mã hóa TLS hay không.

  • Trích xuất thông tin TLS cần thiết nếu kết nối sử dụng TLS.

2. Network Filters

Network filter xử lý dữ liệu thô ở dạng các gói TCP (TCP packets).

Filter phổ biến nhất trong nhóm này là HTTP connection manager filter (HCM), đóng vai trò quản lý các kết nối HTTP.

Các ví dụ khác về network filter bao gồm:

  • Rate limit filter: Giới hạn tốc độ yêu cầu.

  • Redis proxy filter: Proxy cho Redis.

  • Mongo proxy filter: Proxy cho MongoDB.

  • Connection limit filter: Giới hạn số lượng kết nối.

Bạn có thể xem danh sách đầy đủ các network filter tích hợp sẵn tại đây.

3. HTTP Filters

HTTP filter hoạt động ở tầng 7 (L7), làm việc với dữ liệu HTTP.

  • HTTP connection manager filter (HCM) có khả năng tạo ra các HTTP filter tùy chọn.

  • HCM filter chuyển đổi dữ liệu thô thành dữ liệu HTTP, giúp các HTTP filter có thể thao tác với các yêu cầu và phản hồi HTTP.

Nhờ sự phân tầng và khả năng mở rộng qua các loại filter trên, Envoy trở thành một proxy mạnh mẽ, linh hoạt, phục vụ tốt cho các nhu cầu về hiệu suất và bảo mật trong hệ thống dịch vụ mesh.

Envoy Routes

Khi định tuyến lưu lượng HTTP, filter cuối cùng trong filter chain phải là router filter. Filter này chịu trách nhiệm định tuyến lưu lượng đến đích, dẫn đến khối cấu hình thứ hai - routes.

Trong cấu hình route, chúng ta:

  • Định nghĩa virtual hosts (máy chủ ảo).

  • Viết các route để khớp với các yêu cầu đến dựa trên URI, header, v.v.

  • Chỉ định nơi gửi lưu lượng dựa trên route được khớp.

Trong mỗi route, chúng ta có thể định tuyến lưu lượng đến các cluster.


Envoy Clusters và Endpoints

Trong Envoy, một cluster là tập hợp các host upstream có khả năng nhận lưu lượng. Cluster tương tự với khái niệm Kubernetes Service.

Lưu ý:

  • Upstream: Đích hoặc máy chủ nhận lưu lượng (server).

  • Downstream: Nguồn gửi yêu cầu (client).

Endpoints là các phần tử của cluster, biểu thị địa chỉ mà lưu lượng có thể được gửi tới, ví dụ: một địa chỉ IP hoặc hostname.

Ví dụ cấu hình Envoy

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: hello_world
          http_filters:
          - name: envoy.filters.http.router
          route_config:
            name: my_first_route
            virtual_hosts:
            - name: my_vhost
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: hello_world_service
clusters:
- name: hello_world_service
  connect_timeout: 5s
  load_assignment:
    cluster_name: hello_world_service
    endpoints:
    - lb_endpoints:
      - endpoint:
          address:
            socket_address:
              address: 127.0.0.1
              port_value: 8000

Phân tích cấu hình

  • Listener:

    • Tên: listener_0.

    • Lắng nghe trên port 10000.

  • Filter chain:

    • Chứa một HTTP Connection Manager (HCM) filter.
  • HTTP Filter:

    • Sử dụng router filter để định tuyến lưu lượng.
  • Route Configuration:

    • Khớp với tất cả các virtual host (* trong mảng domains).

    • Khớp các yêu cầu có prefix/.

    • Định tuyến lưu lượng đến cluster hello_world_service.

  • Cluster Configuration:

    • Tên cluster: hello_world_service.

    • Có một endpoint tại 127.0.0.1:8000.

Cấu hình trên minh họa cách Envoy proxy hoạt động từ việc nhận lưu lượng tại listener, xử lý qua filter chain, định tuyến qua router filter, và cuối cùng gửi lưu lượng đến các endpoint thuộc một cluster được định nghĩa.

Khi sử dụng EnvoyFilter, điều đầu tiên cần làm là xác định vị trí áp dụng patch. Điều này được mô tả trong trường applyTo. Ví dụ, bạn có thể áp dụng patch vào:

  • Listener (LISTENER)

  • Network filter (NETWORK_FILTER)

  • HTTP filter (HTTP_FILTER)

  • Virtual host (VIRTUAL_HOST)

Xác định vị trí chính xác với match

Ngoài việc chỉ định vị trí tổng quát với applyTo, bạn có thể cung cấp vị trí cụ thể hơn thông qua trường match. Trường này cho phép định nghĩa các điều kiện khớp mà patch phải đáp ứng trước khi được áp dụng.

Các điều kiện khớp phổ biến:

TrườngMô tả
contextXác định loại proxy cần áp dụng patch: inbound (SIDECAR_INBOUND), outbound (SIDECAR_OUTBOUND), gateway (GATEWAY), hoặc mọi proxy (ANY).
proxyKhớp với các thuộc tính của proxy, như phiên bản proxy hoặc metadata node được thiết lập.
listenerKhớp với các thuộc tính của listener trong Envoy (ví dụ: số port, tên listener, hoặc filter cụ thể trong chuỗi filter).
routeConfigurationKhớp với cấu hình route HTTP (ví dụ: tên route, số port, tên cổng, tên gateway, hoặc virtual host cụ thể).
clusterKhớp với các thuộc tính của cluster (ví dụ: tên cluster, subset, tên dịch vụ đầy đủ, hoặc số port).

Ví dụ cấu hình

configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
      listener:
        portNumber: 9000
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
            subFilter:
              name: "envoy.filters.http.router"

Phân tích ví dụ

  1. applyTo:

    • Loại patch được áp dụng là HTTP_FILTER.
  2. match.context:

    • Chỉ định áp dụng patch cho sidecar inbound traffic (SIDECAR_INBOUND).
  3. match.listener:

    • Khớp với một listener cụ thể:

      • portNumber: 9000.

      • filterChain: Chuỗi filter chứa một HTTP Connection Manager filter (envoy.filters.network.http_connection_manager).

  4. subFilter:

    • Target vào router filter (envoy.filters.http.router) bên trong HCM.

Sau khi xác định vị trí cần áp dụng, bước tiếp theo là quyết định nội dung và cách áp dụng patch. Phần cấu hình của patch được mô tả qua hai thành phần chính:

  1. operation: Xác định cách thức áp dụng patch.

  2. value: Mô tả nội dung thực tế của patch.

operation: Cách áp dụng patch

operation là trường xác định cách patch sẽ được thêm hoặc thay đổi trong cấu hình hiện tại của Envoy. Một số loại operation phổ biến:

  • ADD: Thêm mới cấu hình vào vị trí được chỉ định.

  • MERGE: Hợp nhất patch với cấu hình hiện tại.

  • REMOVE: Gỡ bỏ một phần của cấu hình.

  • INSERT_BEFORE/INSERT_AFTER: Chèn patch vào trước hoặc sau một đối tượng cụ thể.

value: Giá trị của patch

Trường value chứa nội dung cấu hình của patch, được viết dưới dạng YAML. Đây chính là phần thiết lập cụ thể mà bạn muốn áp dụng cho Envoy.

Ví dụ cấu hình patch

- applyTo: EXTENSION_CONFIG
    patch:
      operation: ADD
      value:
        name: my-wasm-extension
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
          config:
            root_id: my-wasm-root-id
            vm_config:
              vm_id: my-wasm-vm-id
              runtime: envoy.wasm.runtime.v8
              code:
                remote:
                  http_uri:
                    uri: http://my-wasm-binary-uri

Phân tích ví dụ

  1. applyTo:

    • Patch được áp dụng vào phần EXTENSION_CONFIG trong cấu hình Envoy.
  2. patch.operation:

    • Thao tác được sử dụng là ADD, nghĩa là thêm một cấu hình mới vào phần EXTENSION_CONFIG.
  3. patch.value:

    • name: Tên của extension là my-wasm-extension.

    • typed_config:

      • Sử dụng filter envoy.extensions.filters.http.wasm.v3.Wasm.

      • root_idvm_id xác định plugin Wasm.

      • runtime: Sử dụng runtime envoy.wasm.runtime.v8.

      • code.remote.http_uri: Định nghĩa URL từ xa chứa binary của Wasm plugin (http://my-wasm-binary-uri).

  4. Không có match:

    • Patch này không sử dụng điều kiện khớp (match). Thay vào đó, cấu hình được áp dụng trực tiếp vào toàn bộ phần EXTENSION_CONFIG.