Skip to content

Service Mesh Networking: Envoy Data Plane and mTLS

Tại sao Service Mesh Troubleshooting Khác biệt

Service Mesh (Anthos Service Mesh hoặc Istio) bổ sung thêm một tầng phức tạp mới (additional layer of complexity):

  • Luồng traffic đi qua các Envoy sidecar proxy, không truyền trực tiếp (direct).
  • Bắt buộc áp dụng mTLS (mutual TLS) giữa các service.
  • Các chính sách traffic policy kiểm soát định tuyến (routing), thử lại (retries), và ngắt mạch (circuit breaking).
  • Khả năng quan sát (Observability) thông qua access logs, traces, và metrics.

Sự cố mạng có thể xuất phát từ hạ tầng bên dưới (firewall, routes) hoặc cấu hình của service mesh. Để phân tách nguyên nhân, bạn cần hiểu rõ kiến trúc của service mesh.

Cơ chế bên trong: Luồng đi của Traffic trong Service Mesh

Luồng tổng quát (High-Level Flow)

Pod A (có Envoy sidecar)

Envoy bắt traffic (qua các rules iptables)

Envoy áp dụng các chính sách (retry, timeout, v.v.)

Envoy thiết lập kết nối mTLS tới Envoy của Pod B

Envoy của Pod B giải mã và forward tới ứng dụng

Chi tiết các bước

Bước 1: Đánh chặn Traffic (iptables)

Service Mesh đưa các iptables rules vào để đánh chặn traffic:

bash
# Xem các rules iptables (yêu cầu quyền admin)
sudo iptables -t mangle -L -n

# Kết quả hiển thị các rule chuyển traffic tới Envoy (localhost:15000)

Cơ chế hoạt động:

Pod khởi tạo kết nối: pod-a.ns.svc.cluster.local:8080

iptables redirect: 127.0.0.1:15001 (Envoy listener)

Envoy xử lý traffic

Bước 2: Cấu hình Envoy

Service Mesh control plane (istiod) đẩy cấu hình (push configuration) tới các Envoy sidecar:

istiod (control plane)

Cấu hình Envoy sidecar
  ├─ Listeners (các port Envoy lắng nghe)
  ├─ Routes (cách thức định tuyến traffic)
  ├─ Clusters (các destination ở backend)
  └─ Endpoints (các instance backend thực tế)

Cấu hình được cập nhật theo thời gian thực qua giao thức xDS (gRPC). Envoy sẽ áp dụng cấu hình này ngay lập tức.

Bước 3: Đưa ra Quyết định Định tuyến (Traffic Decision)

Khi packet truyền đến Envoy listener, Envoy sẽ thực hiện:

1. Khớp listener (port, protocol)
2. Áp dụng route khớp (host, path, headers)
3. Áp dụng các chính sách (retry, timeout, circuit breaker)
4. Chọn cluster (backend service)
5. Chọn endpoint (instance pod cụ thể)
6. Mở kết nối upstream tới endpoint
7. Forward traffic của ứng dụng

Bước 4: Thiết lập Kết nối mTLS

Envoy thiết lập kết nối mutual TLS tới Envoy của endpoint:

Envoy A: Bắt tay TLS tới port 15003 của Envoy B (mutual)
  ├─ Xuất trình client certificate (Workload Identity)
  ├─ Xác thực server certificate (Workload Identity)
  └─ Thiết lập encrypted tunnel (đường truyền mã hóa)

Traffic ứng dụng được mã hóa qua tunnel

Quản lý Certificate:

  • Istio Certificate Authority (CA) cấp phát các certificate.
  • Certificate được tự động xoay vòng (mặc định sau mỗi 24 giờ).
  • mTLS được bắt buộc áp dụng dựa trên các chính sách PeerAuthentication.

Bước 5: Đường truyền Phản hồi (Response Path)

Traffic phản hồi được truyền ngược lại:

Backend Pod → Backend Envoy

Giải mã mTLS

Forward phản hồi tới upstream Envoy

Upstream Envoy giải mã, forward tới ứng dụng

Các lỗi Service Mesh thường gặp khi Debug

Trường hợp 1: Lỗi từ chối kết nối (Connection Refused)

Triệu chứng:

Pod A curl pod-b:8080
curl: (7) Failed to connect to pod-b port 8080: Connection refused

Nguyên nhân gốc rễ:

  1. Chưa inject các rule iptables của service mesh

    bash
    # Kiểm tra status sidecar injection
    kubectl get pods pod-a -o yaml | grep sidecar
    # Phải có annotation: sidecar.istio.io/inject=true
    
    # Nếu chưa được inject, hãy kích hoạt cho namespace
    kubectl label namespace default istio-injection=enabled --overwrite
    
    # Tạo lại pod
    kubectl delete pods pod-a
    kubectl apply -f pod-a.yaml
  2. Backend service chưa được đăng ký trong mesh

    bash
    # Kiểm tra Service definition
    kubectl get svc pod-b -o yaml
    # Kiểm tra xem port có được định nghĩa rõ ràng không
    
    # Kiểm tra VirtualService / DestinationRule (nếu có)
    kubectl get vs,dr
  3. Chính sách traffic policy chặn kết nối

    bash
    # Kiểm tra DestinationRule traffic policies
    kubectl get dr pod-b -o yaml
    # Xem kỹ: trafficPolicy (load balancer, connection pool)
    
    # Kiểm tra chính sách PeerAuthentication
    kubectl get peerauth -o yaml
    # Nếu ở chế độ STRICT, kết nối bắt buộc phải dùng mTLS

Trường hợp 2: Lỗi bắt tay mTLS (mTLS Handshake Failures)

Triệu chứng:

Envoy logs hiển thị:
  TLS error: certificate verify failed
  TLS error: bad certificate
  upstream connect error or disconnect/reset before headers

Nguyên nhân gốc rễ:

  1. Certificate chưa được cấp phát

    bash
    # Kiểm tra log của deployment/istiod
    kubectl logs -n istio-system deployment/istiod | grep certificate
    
    # Pod mới có thể phải chờ cấp certificate
    # Chờ khoảng 30s rồi thử lại
  2. Workload Identity bị sai lệch (mismatch)

    bash
    # Kiểm tra service account
    kubectl get sa pod-b
    
    # Certificate được cấp phát cho service account
    # Xác minh pod đang chạy đúng service account
    kubectl get pods pod-b -o yaml | grep serviceAccountName
  3. Sai lệch chính sách PeerAuthentication

    bash
    # Nếu PeerAuthentication bắt buộc STRICT mTLS,
    # cả hai pod đều phải hỗ trợ mTLS
    
    kubectl get peerauth -o yaml
    
    # Nếu một pod không có sidecar proxy, kết nối sẽ lỗi
    # Hãy inject sidecar proxy cho pod

Trường hợp 3: Traffic không đến được Backend (Cấu hình sai Routing)

Triệu chứng:

Lúc đầu gọi curl thành công, sau đó bắt đầu gặp lỗi
hoặc traffic đi sai backend mong muốn

Nguyên nhân gốc rễ:

  1. Cấu hình sai rule trong VirtualService

    bash
    # Kiểm tra VirtualService
    kubectl get vs -o yaml
    # Xem kỹ: hosts, http routes, match conditions
    
    # Ví dụ mẫu:
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: pod-b
    spec:
      hosts:
      - pod-b.default.svc.cluster.local
      http:
      - route:
        - destination:
            host: pod-b.default.svc.cluster.local
            port:
              number: 8080
  2. Thiếu Destination Rule

    bash
    # VirtualService có thể tham chiếu tới destination không tồn tại
    kubectl describe vs pod-b
    # Kiểm tra xem host có phân giải được không
    
    # Tạo DestinationRule nếu cần thiết
    kubectl apply -f - << EOF
    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: pod-b
    spec:
      host: pod-b.default.svc.cluster.local
      trafficPolicy:
        connectionPool:
          tcp:
            maxConnections: 100
          http:
            http1MaxPendingRequests: 100
    EOF

Trường hợp 4: Latency qua Mesh tăng cao

Triệu chứng:

Kết nối trực tiếp giữa hai pod (qua IP): latency 1ms
Kết nối qua mesh (qua service): latency 50ms

Nguyên nhân gốc rễ:

  1. Phát sinh thêm hop qua Envoy

    Envoy làm tăng thêm độ trễ xử lý (thường khoảng ~10-20ms). Đây là hiện tượng bình thường.

  2. Circuit breaker giới hạn số lượng request đồng thời

    bash
    # Kiểm tra DestinationRule traffic policy
    kubectl get dr -o yaml | grep -A 10 trafficPolicy
    
    # Nếu http1MaxPendingRequests quá thấp, các request sẽ bị xếp hàng
    # Hãy tăng giới hạn này lên
  3. Retry policy làm phát sinh thêm latency

    bash
    # Kiểm tra retry policy
    kubectl get vs -o yaml | grep -A 5 retries
    
    # Nếu cấu hình 3 lần retry với timeout 1s mỗi lần, độ trễ tối đa sẽ là 3s
    # Hãy điều chỉnh lại nếu quá khắt khe

Kiểm tra Logs của Envoy

Access Logs

Bật Envoy access logs để theo dõi traffic:

bash
# Qua CLI
kubectl set env -n default deployment/pod-a \
  PROXY_LOG_LEVEL=debug

# Hoặc cấu hình qua Telemetry resource
kubectl apply -f - << EOF
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: default
spec:
  accessLogging:
  - providers:
    - name: envoy
    state: ON
EOF

Xem logs:

bash
# Log của container proxy
kubectl logs pod-a -c istio-proxy

# Định dạng output mẫu:
[2026-06-26T15:30:45.123Z] "[2026-06-26T15:30:45.123Z] ...
SOURCE_IP - - [26/Jun/2026:15:30:45 +0000] "GET /api HTTP/1.1" 200 1234 "-" "-" 0 42 "-" "-" "10.0.1.2" "10.1.1.3:8080" "pod-b.default.svc.cluster.local" outbound|8080||pod-b.default.svc.cluster.local 10.0.1.2:54321 10.1.1.3:8080 10.0.1.2:54321 -

Đọc hiểu log:

- Method: GET
- Path: /api
- Status: 200
- Thời gian phản hồi (Response time): 42ms
- Upstream: pod-b.default.svc.cluster.local

Cấu hình Debug Log Level

Tăng độ chi tiết của log:

bash
# Kiểm tra tên container proxy của pod
kubectl get pods pod-a -o jsonpath='{.spec.containers[].name}'

# Bật debug logging qua API
kubectl exec pod-a -c istio-proxy -- \
  curl -X POST http://localhost:15000/logging?level=debug

# Theo dõi logs trực tiếp
kubectl logs pod-a -c istio-proxy -f

Xuất thông tin Cấu hình (Configuration Dump)

Kiểm tra cấu hình thực tế của Envoy:

bash
# Xuất toàn bộ config
kubectl exec pod-a -c istio-proxy -- \
  curl localhost:15000/config_dump > config_dump.json

# Kiểm tra các cluster
kubectl exec pod-a -c istio-proxy -- \
  curl localhost:15000/clusters

# Kiểm tra các listener
kubectl exec pod-a -c istio-proxy -- \
  curl localhost:15000/listeners

Sử dụng Distributed Tracing

Tracing hiển thị luồng đi của request đầu-cuối qua mesh:

bash
# Xác thực Tracing đã được bật chưa
kubectl get telemetry -o yaml | grep tracingProviders

# Triển khai tracing backend (như Jaeger/Zipkin)
# Thường được tích hợp sẵn kèm theo Anthos Service Mesh

# Gửi request để tạo trace
kubectl exec pod-a -- curl pod-b:8080

# Xem thông tin trace trên Jaeger UI

Sơ đồ luồng đi (Trace):

Request A → Envoy A (10ms)

Bắt tay mTLS (5ms)

Request B → Envoy B (8ms)

Xử lý ở App B (20ms)

Phản hồi B ← Envoy B (3ms)

Phản hồi A ← Envoy A (2ms)

Tổng cộng: ~48ms

Mỗi phân đoạn (span) hiển thị latency chi tiết ở từng layer, giúp xác định điểm nghẽn.

Best Practices cho Service Mesh Debugging

1. Đảm bảo Kích hoạt Sidecar Injection đồng nhất

bash
# Label namespace
kubectl label namespace default istio-injection=enabled

# Kiểm tra pod đã được auto-inject sidecar chưa
kubectl get pods pod-a -o yaml | grep "- name: istio-proxy"
# Phải xuất hiện container istio-proxy

2. Giám sát thời gian hết hạn Certificate

bash
# Kiểm tra các secret cert
kubectl get secret -n default | grep cert

# Xem thông tin chi tiết certificate
kubectl get secret pod-a-certs -o jsonpath='{.data.cert}' | \
  base64 --decode | openssl x509 -text -noout

3. Áp dụng mTLS theo lộ trình

bash
# Bắt đầu với chế độ PERMISSIVE (cho phép cả traffic không dùng mTLS)
kubectl apply -f - << EOF
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
spec:
  mtls:
    mode: PERMISSIVE  # Ban đầu cho phép cả kết nối thường
EOF

# Sau khi xác thực hoạt động ổn định, chuyển sang STRICT
kubectl patch peerauth default -p '{"spec":{"mtls":{"mode":"STRICT"}}}'

4. Thiết lập rõ các Traffic Policies

bash
# Áp dụng DestinationRule đi kèm giới hạn và cấu hình log
kubectl apply -f - << EOF
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: pod-b
spec:
  host: pod-b
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 1000
      http:
        http1MaxPendingRequests: 1000
        maxRequestsPerConnection: 2
  outlierDetection:
    consecutive5xxErrors: 5
    interval: 30s
    baseEjectionTime: 30s
EOF

5. Xác thực cấu hình trước khi deploy

bash
# Sử dụng công cụ analyze của istioctl để xác thực
istioctl analyze

# Đảm bảo không hiển thị lỗi hoặc cảnh báo nào trước khi deploy

Quy trình xử lý sự cố trên Production

Khi xảy ra lỗi kết nối giữa các service (service-to-service communication failing):

1. Xác thực sidecar đã được inject vào pod chưa
   kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].name}{"\n"}{end}' | grep istio-proxy
   
2. Kiểm tra cấu hình mTLS
   kubectl get peerauth -o yaml
   → Nếu là STRICT, bắt buộc cả hai service kết nối đều phải có sidecar proxy.

3. Kiểm tra các chính sách traffic policy
   kubectl get vs,dr -o yaml
   → Xem kỹ các routing rules và traffic policies.

4. Bật access logs để theo dõi traffic
   kubectl apply -f telemetry.yaml

5. Tạo traffic giả lập để kiểm tra trace
   kubectl exec pod-a -- curl pod-b:8080
   
6. Kiểm tra logs của proxy
   kubectl logs pod-a -c istio-proxy | grep "pod-b"
   
7. Kiểm tra certificate của workload
   kubectl get secret -n default | grep cert
   
8. Xác thực phân giải tên miền nội bộ
   kubectl exec pod-a -- nslookup pod-b.default.svc.cluster.local
   
9. Nếu vẫn gặp lỗi:
   kubectl describe vs pod-b
   kubectl describe dr pod-b
   kubectl describe peerauth

References