You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nginx Ingress Controller请求头路由配置问题排查

Let's break down your problem and walk through the solutions step by step:

First: Fixing the initial syntax error

The unknown directive error you encountered was definitely due to missing spacing in the variable assignment. The correct syntax for setting the variable is:

set $service_name "backend-data";

Once you fixed that, the config generated without errors—but routing still failed. That's because modifying the built-in $service_name variable from Nginx Ingress Controller isn't a reliable approach.

Why redefining $service_name doesn't work

The $service_name variable is managed internally by the Ingress Controller. It sets this variable early in the location block (as you saw in the generated config), and while your configuration-snippet can overwrite it, the controller's pre-generated proxy logic might not actually use the updated value. Even if it does, relying on modifying built-in variables can lead to unexpected issues with health checks, metrics, or future controller updates.

Better approaches to implement header-based routing

Here are three robust, supported ways to achieve your goal:

Approach 1: Custom proxy logic with server-snippet and configuration-snippet

You can define your own target service variable and override the proxy pass behavior directly:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: api-multi-back
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |
      # Define a custom variable to hold our target service
      set $target_service "backend-default";
      # Update the variable if the Content-Type matches
      if ($http_content_type ~* "multipart/form-data.*") {
        set $target_service "backend-data";
      }
    nginx.ingress.kubernetes.io/configuration-snippet: |
      # Override the default proxy pass to use our custom variable
      proxy_pass http://$target_service.my-namespace.svc.cluster.local:80;
      # Replace `my-namespace` with your actual Kubernetes namespace
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: backend-default # Required placeholder (won't be used)
          servicePort: 80
        path: /api

Notes:

  • You must provide a valid backend entry as a placeholder—otherwise the controller will reject the ingress config.
  • Manually construct the full service DNS name using $target_service.$namespace.svc.cluster.local to ensure proper service discovery.

Approach 2: Two separate Ingress resources with header filtering

Split your routing into two ingresses, each handling a specific header condition. This is more aligned with Kubernetes' declarative style:

# Default backend for requests without multipart/form-data
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: api-default-back
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: backend-default
          servicePort: 80
        path: /api
---
# Backend for requests with multipart/form-data
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: api-data-back
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      # Block requests that don't match the header
      if ($http_content_type !~* "multipart/form-data.*") {
        return 404;
      }
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: backend-data
          servicePort: 80
        path: /api

Pros: Clear, modular configuration—each ingress maps to one backend, making it easier to manage and monitor.

Approach 3: Use Canary Ingress for header-based traffic splitting

If you're looking for a native, managed solution (great for gray-scale testing or traffic shifting), use the Ingress Controller's canary features:

# Main ingress: handles all default traffic
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: api-main-back
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: backend-default
          servicePort: 80
        path: /api
---
# Canary ingress: catches requests with the target header
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: api-canary-data
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "Content-Type"
    # Match exact value or use regex for partial matches
    nginx.ingress.kubernetes.io/canary-by-header-pattern: "multipart/form-data.*"
spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: backend-data
          servicePort: 80
        path: /api

Pros: No custom Nginx snippets needed—this is fully supported by the Ingress Controller, and it's easy to adjust or disable the canary traffic later.

Final Takeaway

Avoid modifying built-in controller variables like $service_name—it's unstable and can break controller features. Instead, use one of the approaches above: custom proxy logic for full control, split ingresses for clarity, or canary ingress for native traffic splitting.

内容的提问来源于stack exchange,提问作者Kelindil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 11:43:15