2025-5-21 主Ingress副本变为0后报503问题分析

主Ingress副本变为0后报503问题分析 #

当主Ingress副本数变为0时出现503错误,从Ingress-NGINX控制器源码分析,主要有以下几个关键原因:

1. 默认后端机制 #

// getDefaultUpstream 返回与默认后端关联的上游 578行
// 配置上游在错误情况下返回 HTTP 代码 503
func (n *NGINXController) getDefaultUpstream() *ingress.Backend {
    upstream := &ingress.Backend{
        Name: defUpstreamName,
    }
    svcKey := n.cfg.DefaultService

    if svcKey == "" {
        upstream.Endpoints = append(upstream.Endpoints, n.DefaultEndpoint())
        return upstream
    }
    
    // 找不到服务或服务没有有效端点时返回DefaultEndpoint
    // DefaultEndpoint通常返回503错误
    // ...
}

image-20250521170206699

当主Ingress副本为0时,控制器找不到匹配的路由规则,会路由到默认后端,默认后端如果未配置或无可用端点时会返回503。

2. Canary灰度发布依赖主Ingress #

// nonCanaryIngressExists 只有在存在一个或多个可能合并到的ingress时才允许合并canary ingress 1544行行
func nonCanaryIngressExists(ingresses, canaryIngresses []*ingress.Ingress) bool {
    return len(ingresses)-len(canaryIngresses) > 0
}

// mergeAlternativeBackends处理 903行
if nonCanaryIngressExists(ingresses, canaryIngresses) {
    for _, canaryIng := range canaryIngresses {
        mergeAlternativeBackends(canaryIng, upstreams, servers)
    }
}

image-20250521165735776

image-20250521165914469

当主Ingress为0,而只有Canary Ingress存在时,由于nonCanaryIngressExists返回false,Canary配置不会被合并,导致无路由可用。

3. 空Endpoints处理机制 #

func (n *NGINXController) serviceEndpoints(svcKey, backendPort string) ([]ingress.Endpoint, error) {
    // ...
    if len(endps) == 0 {
        klog.Warningf("Service %q does not have any active Endpoint.", svcKey)
    }
    // ...
}
// getBackendServers方法内 1120行
if len(upstreams[name].Endpoints) == 0 {
    n.metricCollector.IncOrphanIngress(ing.Namespace, ing.Name, orphanMetricLabelNoEndpoint)
}

image-20250521170023931

当主Ingress副本为0时,相关Service可能没有活跃的Endpoints,NGINX会将请求路由到没有后端的upstream,导致503错误。

4. 服务器创建逻辑依赖主Ingress #

// createServers方法
for _, ing := range data {
    // ...
    if anns.Canary.Enabled {
        klog.V(2).Infof("Ingress %v is marked as Canary, ignoring", ingKey)
        continue
    }
    // ...
}

服务器(server)配置创建过程中,标记为Canary的Ingress会被忽略。当只有Canary Ingress存在时,不会创建对应的服务器配置。

5. 同步逻辑中的空检查 175行 #

func (n *NGINXController) syncIngress(interface{}) error {
    // ...
    ings := n.store.ListIngresses()
    hosts, servers, pcfg := n.getConfiguration(ings)
    // ...
}

image-20250521170608913

当主Ingress副本为0,syncIngress可能生成空的配置,导致请求无法正确路由。

解决方案建议 #

  1. 确保主Ingress副本总是大于0:使用滚动更新策略,确保新版本部署成功后再缩减旧版本

    kubectl rollout update ingress-deployment --replicas=2
    
  2. 配置专用的默认后端:确保有一个稳定的默认后端处理异常路由

    # 在ConfigMap中设置
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ingress-nginx-controller
    data:
      default-backend-service: "namespace/default-backend"
    
  3. 避免灰度发布时主Ingress副本为0:灰度发布时先部署Canary,确认无误后再更新主Ingress,而不是删除主Ingress

  4. 监控Ingress状态:增加对Ingress副本数和Endpoints可用性的监控告警

以上分析基于源码中的实现逻辑,主要指向当主Ingress副本为0时,请求会因为路由不当而返回503状态码。