获取Ingress状态信息

使用kubectl get ingress命令在获取Ingress信息时

1
2
3
➜  ~ kubectl get ingress
NAME                    HOSTS               ADDRESS          PORTS   AGE
xnile                 dianduidian.com		     X.X.X.X		80    3h41m

你有没有留意ADDRESS列的含义是什么?它是如何来的?能不能修改?

这其实是靠Ingress状态的上报机制来实现的。

Ingress 状态上报原理

官方的nginx-ingress-controller默认启动参数大概是这样:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
containers:
  - name: nginx-ingress-controller
    image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1
    args:
      - /nginx-ingress-controller
      - --configmap=$(POD_NAMESPACE)/nginx-configuration
      - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
      - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
      - --publish-service=$(POD_NAMESPACE)/ingress-nginx
      - --annotations-prefix=nginx.ingress.kubernetes.io

其中--publish-service参数的作用就是用来上报状态用的。

它的完整代码在这里 ,其中主要逻辑在statusAddressFromService这个函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
func statusAddressFromService(service string, kubeClient clientset.Interface) ([]string, error) {
	ns, name, _ := k8s.ParseNameNS(service)
  	//获取--publish-service 指定的svc信息
	svc, err := kubeClient.CoreV1().Services(ns).Get(name, metav1.GetOptions{})
	if err != nil {
		return nil, err
	}
  
  	//判断Service的类型
	switch svc.Spec.Type {
  	//ExternalName
	case apiv1.ServiceTypeExternalName:
		return []string{svc.Spec.ExternalName}, nil
  	//ClusterIP
	case apiv1.ServiceTypeClusterIP:
		return []string{svc.Spec.ClusterIP}, nil
  	//TypeNodePort
	case apiv1.ServiceTypeNodePort:
		addresses := []string{}
		if svc.Spec.ExternalIPs != nil {
			addresses = append(addresses, svc.Spec.ExternalIPs...)
		} else {
			addresses = append(addresses, svc.Spec.ClusterIP)
		}
		return addresses, nil
 	 //LoadBalancer
	case apiv1.ServiceTypeLoadBalancer:
		addresses := []string{}
		for _, ip := range svc.Status.LoadBalancer.Ingress {
			if ip.IP == "" {
				addresses = append(addresses, ip.Hostname)
			} else {
				addresses = append(addresses, ip.IP)
			}
		}

		addresses = append(addresses, svc.Spec.ExternalIPs...)

		return addresses, nil
	}

	return nil, fmt.Errorf("unable to extract IP address/es from service %v", service)
}

函数逻辑也很简单,根据--publish-service指定Service的类型获取对应的IPHostname,然后把信息上报给API Server:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
func runUpdate(ing *ingress.Ingress, status []apiv1.LoadBalancerIngress,
	client clientset.Interface) pool.WorkFunc {
	return func(wu pool.WorkUnit) (interface{}, error) {
		if wu.IsCancelled() {
			return nil, nil
		}

		if k8s.IsNetworkingIngressAvailable {
			ingClient := client.NetworkingV1beta1().Ingresses(ing.Namespace)
			currIng, err := ingClient.Get(ing.Name, metav1.GetOptions{})
			if err != nil {
				return nil, errors.Wrap(err, fmt.Sprintf("unexpected error searching Ingress %v/%v", ing.Namespace, ing.Name))
			}

			klog.Infof("updating Ingress %v/%v status from %v to %v", currIng.Namespace, currIng.Name, currIng.Status.LoadBalancer.Ingress, status)
      			//设置状态
			currIng.Status.LoadBalancer.Ingress = status
      			//更新
			_, err = ingClient.UpdateStatus(currIng)
			if err != nil {
				klog.Warningf("error updating ingress rule: %v", err)
			}
		} else {
			ingClient := client.NetworkingV1beta1().Ingresses(ing.Namespace)
			currIng, err := ingClient.Get(ing.Name, metav1.GetOptions{})
			if err != nil {
				return nil, errors.Wrap(err, fmt.Sprintf("unexpected error searching Ingress %v/%v", ing.Namespace, ing.Name))
			}

			klog.Infof("updating Ingress %v/%v status from %v to %v", currIng.Namespace, currIng.Name, currIng.Status.LoadBalancer.Ingress, status)
			currIng.Status.LoadBalancer.Ingress = status
			_, err = ingClient.UpdateStatus(currIng)
			if err != nil {
				klog.Warningf("error updating ingress rule: %v", err)
			}
		}

		return true, nil
	}
}

如何自定义上报时的IP

如果想自定义Ingress上报时的IP也很容易,给nginx-ingress-controller加上--publish-status-address启动参数就行。

Argument Description
–publish-status-address string Customized address to set as the load-balancer status of Ingress objects this controller satisfies. Requires the update-status parameter.

参考

https://github.com/nginxinc/kubernetes-ingress/blob/master/docs/report-ingress-status.md

https://kubernetes.github.io/ingress-nginx/user-guide/cli-arguments/