All Products
Search
Document Center

Alibaba Cloud Service Mesh:Gunakan layanan pemrosesan eksternal Envoy untuk pemrosesan kustom permintaan

Last Updated:Jul 02, 2025

Envoy External Processing adalah fitur yang memungkinkan Anda menghubungkan layanan pemrosesan eksternal ke rantai filter Envoy. Fitur ini memungkinkan Anda memproses permintaan dan respons HTTP tanpa perlu menulis plug-in Wasm atau skrip post-processing tambahan untuk Envoy, sehingga meningkatkan fleksibilitas dan skalabilitas. Topik ini menjelaskan cara mengonfigurasi dan menggunakan Pemrosesan Eksternal dalam proxy Envoy.

Prasyarat

Mekanisme

Diagram berikut menggambarkan bagaimana layanan pemrosesan eksternal Envoy mengelola permintaan dari layanan downstream dan respons dari layanan upstream:

  1. Layanan downstream ① mengirim permintaan ke layanan upstream. Envoy memblokir permintaan dan ② mengirimnya ke layanan pemrosesan eksternal untuk diproses.

  2. Layanan pemrosesan eksternal memproses permintaan dan ③ mengembalikan hasilnya ke Envoy.

  3. Envoy memproses permintaan berdasarkan hasil dan ④ meneruskan permintaan ke layanan upstream.

  4. Layanan upstream memproses permintaan dan ⑤ mengembalikan respons ke layanan downstream. Envoy memblokir respons dan ⑥ meneruskannya ke server pemrosesan eksternal.

  5. Server pemrosesan eksternal ⑦ memproses respons dan ⑧ mengembalikannya ke Envoy.

  6. Envoy memproses respons berdasarkan hasil dan ⑨ meneruskan respons yang telah diproses ke layanan downstream.

Langkah 1: Tulis logika pemrosesan untuk layanan pemrosesan eksternal

Blok kode berikut adalah cuplikan dari kode logika inti. Untuk kode contoh lengkap, lihat ext-proc-demo. Untuk informasi lebih lanjut, lihat Dokumentasi Envoy.

Kembangkan untuk melihat detail

// Fungsi NewServer membuat instance baru Server
func NewServer() *Server {
	return &Server{}
}

// Server mengimplementasikan antarmuka server pemrosesan eksternal Envoy
// Lihat https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/ext_proc/v3/external_processor.proto
type Server struct{}

func (s *Server) Process(srv extProcPb.ExternalProcessor_ProcessServer) error {
	klog.Infof("Memproses")
	ctx := srv.Context()
	for {
		select {
		case <-ctx.Done():
			klog.Infof("konteks selesai")
			return ctx.Err()
		default:
		}

		req, err := srv.Recv()
		if err == io.EOF {
			// envoy telah menutup aliran. Jangan kembalikan apa pun dan tutup seluruh aliran ini
			return nil
		}
		if err != nil {
			return status.Errorf(codes.Unknown, "tidak dapat menerima permintaan aliran: %v", err)
		}

		resp := &extProcPb.ProcessingResponse{}
		switch v := req.Request.(type) {
        // Permintaan yang memerlukan pemrosesan header permintaan
		case *extProcPb.ProcessingRequest_RequestHeaders:
			klog.Infof("Mendapat RequestHeaders")
			h := req.Request.(*extProcPb.ProcessingRequest_RequestHeaders)
			resp = handleRequestHeaders(h)
        // Permintaan yang memerlukan pemrosesan header respons
        case *extProcPb.ProcessingRequest_ResponseHeaders:
			klog.Infof("Mendapat ResponseHeaders")
			h := req.Request.(*extProcPb.ProcessingRequest_ResponseHeaders)
			resp = handleResponseHeaders(h)
        // Permintaan yang memerlukan pemrosesan body permintaan, belum diimplementasikan saat ini
		case *extProcPb.ProcessingRequest_RequestBody:
			klog.Infof("Mendapat RequestBody (belum ditangani saat ini)")
        // Permintaan yang memerlukan pemrosesan trailer permintaan, belum diimplementasikan saat ini
		case *extProcPb.ProcessingRequest_RequestTrailers:
			klog.Infof("Mendapat RequestTrailers (belum ditangani saat ini)")
        // Permintaan yang memerlukan pemrosesan body respons, belum diimplementasikan saat ini
		case *extProcPb.ProcessingRequest_ResponseBody:
			klog.Infof("Mendapat ResponseBody (belum ditangani saat ini)")
        // Permintaan yang memerlukan pemrosesan trailer respons, belum diimplementasikan saat ini
		case *extProcPb.ProcessingRequest_ResponseTrailers:
			klog.Infof("Mendapat ResponseTrailers (belum ditangani saat ini)")

		default:
			klog.Infof("Tipe Permintaan tidak dikenal %v", v)
		}
        // Kembalikan pemrosesan yang diminta
		klog.Infof("Mengirim ProcessingResponse: %+v", resp)
		if err := srv.Send(resp); err != nil {
			klog.Infof("kesalahan pengiriman %v", err)
			return err
		}
	}
}

// Tambahkan x-ext-proc-header=hello-to-asm ke header permintaan
func handleRequestHeaders(req *extProcPb.ProcessingRequest_RequestHeaders) *extProcPb.ProcessingResponse {
	klog.Infof("menangani header permintaan: %+v\n", req)

	resp := &extProcPb.ProcessingResponse{
		Response: &extProcPb.ProcessingResponse_RequestHeaders{
			RequestHeaders: &extProcPb.HeadersResponse{
				Response: &extProcPb.CommonResponse{
					HeaderMutation: &extProcPb.HeaderMutation{
						SetHeaders: []*configPb.HeaderValueOption{
							{
								Header: &configPb.HeaderValue{
									Key:      "x-ext-proc-header",
									RawValue: []byte("hello-to-asm"),
								},
							},
						},
					},
				},
			},
		},
	}
    
	return resp
}

// Tambahkan x-ext-proc-header=hello-from-asm ke header respons
func handleResponseHeaders(req *extProcPb.ProcessingRequest_ResponseHeaders) *extProcPb.ProcessingResponse {
	klog.Infof("menangani header respons: %+v\n", req)

	resp := &extProcPb.ProcessingResponse{
		Response: &extProcPb.ProcessingResponse_ResponseHeaders{
			ResponseHeaders: &extProcPb.HeadersResponse{
				Response: &extProcPb.CommonResponse{
					HeaderMutation: &extProcPb.HeaderMutation{
						SetHeaders: []*configPb.HeaderValueOption{
							{
								Header: &configPb.HeaderValue{
									Key:      "x-ext-proc-header",
									RawValue: []byte("hello-from-asm"),
								},
							},
						},
					},
				},
			},
		},
	}

	return resp
}
Catatan

Anda harus menulis Dockerfile untuk mengemas kode layanan pemrosesan eksternal menjadi gambar dan unggah gambar tersebut ke repositori gambar sebelum penyebaran.

Langkah 2: Sebarkan layanan pemrosesan eksternal

Dalam contoh ini, gambar contoh layanan pemrosesan eksternal yang disediakan oleh ASM digunakan. Layanan akan menambahkan header permintaan x-ext-proc-header: hello-to-asm ke permintaan yang diterima dan menambahkan header respons x-ext-proc-header: hello-from-asm ke respons yang diterima.

  1. Buat file bernama ext.yaml dengan konten berikut.

    apiVersion: v1
    kind: Service
    metadata:
      name: ext-proc
      labels:
        app: ext-proc
        service: ext-proc
    spec:
      ports:
      # Port listener layanan pemrosesan eksternal.
      - name: grpc
        port: 9002
        targetPort: 9002
      selector:
        app: ext-proc
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ext-proc
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ext-proc
          version: v1
      template:
        metadata:
          labels:
            app: ext-proc
            version: v1
        spec:
          containers:
          - image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/ext-proc:v0.2
            imagePullPolicy: IfNotPresent
            name: ext-proc
            ports:
            - containerPort: 9002
  2. Jalankan perintah berikut untuk melihat log pod dan verifikasi apakah layanan pemrosesan eksternal beroperasi.

    kubectl logs ext-proc-64c8xxxxx-xxxxx

    Output yang diharapkan:

    I1126 06:41:25.467033       1 main.go:52] Memulai server gRPC pada port :9002

    Log seperti yang ditunjukkan di atas menunjukkan bahwa layanan pemrosesan eksternal berjalan sesuai harapan.

Langkah 3: Konfigurasikan Filter Envoy

  1. Masuk ke Konsol ASM. Di panel navigasi di sebelah kiri, pilih Service Mesh > Mesh Management.

  2. Di halaman Mesh Management, klik nama instance ASM. Di panel navigasi di sebelah kiri, pilih Plugin Extension Center > EnvoyFilter Template.

  3. Buat Envoy Filter bernama httpbin-ext-proc dengan konten berikut.

    apiVersion: networking.istio.io/v1alpha3
    kind: EnvoyFilter
    spec:
      configPatches:
        - applyTo: HTTP_FILTER
          match:
            context: SIDECAR_INBOUND
            listener:
              portNumber: 80
              filterChain:
                filter:
                  name: envoy.filters.network.http_connection_manager
            proxy:
              proxyVersion: ^MIN_VERSION-MAX_VERSION.*
          patch:
            operation: INSERT_BEFORE
            value:
              name: envoy.filters.http.ext_proc
              typed_config:
                '@type': >-
                  type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor
                grpc_service:
                  envoy_grpc:
                    cluster_name: outbound|9002||ext-proc.default.svc.cluster.local
                    authority: ext-proc.default.svc.cluster.local
                processing_mode:
                  request_header_mode: SEND
                  response_header_mode: SEND

Langkah 4: Akses aplikasi HTTPBin untuk verifikasi

Jalankan perintah berikut untuk mengakses aplikasi HTTPBin dan periksa header respons.

kubectl exec -it deploy/sleep -- curl httpbin:8000/headers -i

Output yang diharapkan:

HTTP/1.1 200 OK
server: envoy
date: Wed, 11 Dec 2024 06:47:59 GMT
content-type: application/json
content-length: 564
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 3
x-ext-proc-header: hello-from-asm

{
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin:8000",
    "User-Agent": "curl/8.1.2",
    "X-B3-Parentspanid": "5c6dd2cc9312d6bb",
    "X-B3-Sampled": "1",
    "X-B3-Spanid": "1153a2737cee4434",
    "X-B3-Traceid": "baba86b696edc75a5c6dd2cc9312d6bb",
    "X-Envoy-Attempt-Count": "1",
    "X-Ext-Proc-Header": "hello-to-asm",
    "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=69d8f267c3c00b4396a83e12d14520acc9dadb1492d660e10f77e94dcad7cb06;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/sleep"
  }
}

Output menunjukkan bahwa header permintaan x-ext-proc-header: hello-to-asm ditambahkan sebelum permintaan diteruskan, dan header respons x-ext-proc-header: hello-from-asm ditambahkan sebelum respons dikembalikan.