diff --git a/controller/api/destination/server_test.go b/controller/api/destination/server_test.go index 49a701d1e..367f675fc 100644 --- a/controller/api/destination/server_test.go +++ b/controller/api/destination/server_test.go @@ -93,6 +93,24 @@ spec: value: 0.0.0.0:4143 name: linkerd-proxy`, ` +apiVersion: v1 +kind: Pod +metadata: + name: name2-2 + namespace: ns +status: + phase: Succeeded + podIP: 172.17.0.13`, + ` +apiVersion: v1 +kind: Pod +metadata: + name: name2-3 + namespace: ns +status: + phase: Failed + podIP: 172.17.0.13`, + ` apiVersion: linkerd.io/v1alpha2 kind: ServiceProfile metadata: diff --git a/controller/api/destination/watcher/ip_watcher.go b/controller/api/destination/watcher/ip_watcher.go index d3028f577..4451fac43 100644 --- a/controller/api/destination/watcher/ip_watcher.go +++ b/controller/api/destination/watcher/ip_watcher.go @@ -154,10 +154,23 @@ func (iw *IPWatcher) GetPod(podIP string) (*corev1.Pod, error) { } func getResource(ip string, informer cache.SharedIndexInformer) (interface{}, error) { - objs, err := informer.GetIndexer().ByIndex(podIPIndex, ip) + matchingObjs, err := informer.GetIndexer().ByIndex(podIPIndex, ip) if err != nil { return nil, status.Error(codes.Unknown, err.Error()) } + + objs := make([]interface{}, 0) + for _, obj := range matchingObjs { + // Ignore terminated pods, + // their IPs can be reused for new Running pods + pod, ok := obj.(*corev1.Pod) + if ok && podTerminated(pod) { + continue + } + + objs = append(objs, obj) + } + if len(objs) > 1 { return nil, status.Errorf(codes.FailedPrecondition, "IP address conflict: %v, %v", objs[0], objs[1]) } @@ -167,6 +180,11 @@ func getResource(ip string, informer cache.SharedIndexInformer) (interface{}, er return nil, nil } +func podTerminated(pod *corev1.Pod) bool { + phase := pod.Status.Phase + return phase == corev1.PodSucceeded || phase == corev1.PodFailed +} + func (iw *IPWatcher) addService(obj interface{}) { service := obj.(*corev1.Service) if service.Namespace == kubeSystem || service.Spec.ClusterIP == "None" { @@ -285,10 +303,18 @@ func (iw *IPWatcher) getOrNewServiceSubscriptions(clusterIP string) *serviceSubs pods := []*corev1.Pod{} for _, obj := range objs { if pod, ok := obj.(*corev1.Pod); ok { - // Skip pods with HostNetwork. - if !pod.Spec.HostNetwork { - pods = append(pods, pod) + // Skip pods with HostNetwork + if pod.Spec.HostNetwork { + continue } + + // Ignore terminated pods, + // their IPs can be reused for new Running pods + if podTerminated(pod) { + continue + } + + pods = append(pods, pod) } } if len(pods) > 1 {