主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错误
// ...
}
当主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)
}
}
当主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)
}
当主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)
// ...
}
当主Ingress副本为0,syncIngress可能生成空的配置,导致请求无法正确路由。
解决方案建议 #
确保主Ingress副本总是大于0:使用滚动更新策略,确保新版本部署成功后再缩减旧版本
kubectl rollout update ingress-deployment --replicas=2
配置专用的默认后端:确保有一个稳定的默认后端处理异常路由
# 在ConfigMap中设置 apiVersion: v1 kind: ConfigMap metadata: name: ingress-nginx-controller data: default-backend-service: "namespace/default-backend"
避免灰度发布时主Ingress副本为0:灰度发布时先部署Canary,确认无误后再更新主Ingress,而不是删除主Ingress
监控Ingress状态:增加对Ingress副本数和Endpoints可用性的监控告警
以上分析基于源码中的实现逻辑,主要指向当主Ingress副本为0时,请求会因为路由不当而返回503状态码。