Change:
/kind bug What happened: ILB Frontend IP configuration does not change while updating service What you expected to happen: LB Frontend IP configuration should get updated How to reproduce it (as minimally and precisely as possible): Source issue : AKS service is created using .yaml manifest. ILB is described as it is shown in the documentation: annotations: "true" spec: ports: port: 80 type: LoadBalancer loadBalancerIP: 10.240.200.2 ILB instance with the "kubernetes-internal" name is created with a correct private IP address pointing to the service described. If I change the "loadBalancerIP" to another internal IP address and re-deploy the service, the last is deployed with the correct new IP address, but "kubernetes-internal" ILB still has the old Frontend IP configuration. Environment: Cloud provider or hardware configuration: Azure
/sig azure
This also not works for public LB. /cc Could you fix the bug and cherry pick to old versions?
I got this bug today, I changed the external LoadBalancerIP on a LoadBalancer service. The service event log showed that it immediately recognised the change ("oldIP =newIP") but I had to delete/recreate the service to see the change in the Azure loadbalancer.

Discussion:
// Here we'll firstly ensure service do not lie in the opposite LB. serviceName := getServiceName(service) glog.V(5).Infof("ensureloadbalancer(%s): START clusterName=%q", serviceName, clusterName) <del> flippedService := flipServiceInternalAnnotation(service) if _, err := az.reconcileLoadBalancer(clusterName, flippedService, nil, false /* wantLb */); err != nil { return nil, err } if _, err := az.reconcilePublicIP(clusterName, service, true /* wantLb */); err != nil { return nil, err } </del> lb, err := az.reconcileLoadBalancer(clusterName, service, nodes, true /* wantLb */) if err != nil {

return nil, err } <ins> updateService := updateServiceLoadBalancerIP(service, to.String(serviceIP)) flippedService := flipServiceInternalAnnotation(updateService) if _, err := az.reconcileLoadBalancer(clusterName, flippedService, nil, false /* wantLb */); err != nil { return nil, err } if _, err := az.reconcilePublicIP(clusterName, updateService, true /* wantLb */); err != nil { return nil, err } </ins> return lbStatus, nil }

return nil, nil, false, err } if status == nil { <del> // service is not om this load balancer </del> <ins> // service is not on this load balancer </ins> continue }

return copyService } <ins> func updateServiceLoadBalancerIP(service *v1.Service, serviceIP string) *v1.Service { copyService := service.DeepCopy() if len(serviceIP) > 0 && copyService != nil { copyService.Spec.LoadBalancerIP = serviceIP } return copyService } </ins> func (az *Cloud) findServiceIPAddress(ctx context.Context, clusterName string, service *v1.Service, isInternalLb bool) (string, error) { if len(service.Spec.LoadBalancerIP) > 0 { return service.Spec.LoadBalancerIP, nil

return &to32, nil } <ins> func (az *Cloud) isFrontendIPChanged(clusterName string, config network.FrontendIPConfiguration, service *v1.Service, lbFrontendIPConfigName string) (bool, error) { if az.serviceOwnsFrontendIP(config, service) && !strings.EqualFold(to.String(config.Name), lbFrontendIPConfigName) { return true, nil } if !strings.EqualFold(to.String(config.Name), lbFrontendIPConfigName) { return false, nil } loadBalancerIP := service.Spec.LoadBalancerIP isInternal := requiresInternalLoadBalancer(service) if isInternal { // Judge subnet subnetName := subnet(service) if subnetName != nil { subnet, existsSubnet, err := az.getSubnet(az.VnetName, *subnetName) if err != nil { return false, err } if !existsSubnet { return false, fmt.Errorf("failed to get subnet") } if config.Subnet != nil && !strings.EqualFold(to.String(config.Subnet.Name), to.String(subnet.Name)) { return true, nil } } if loadBalancerIP == "" { return config.PrivateIPAllocationMethod == network.Static, nil } return config.PrivateIPAllocationMethod != network.Static || !strings.EqualFold(loadBalancerIP, to.String(config.PrivateIPAddress)), nil } if loadBalancerIP == "" { return false, nil } pipName, err := az.determinePublicIPName(clusterName, service) if err != nil { return false, err } pipResourceGroup := az.getPublicIPAddressResourceGroup(service) pip, existsPip, err := az.getPublicIPAddress(pipResourceGroup, pipName) if err != nil { return false, err } if !existsPip { return true, nil } return config.PublicIPAddress != nil && !strings.EqualFold(to.String(pip.ID), to.String(config.PublicIPAddress.ID)), nil } </ins> // This ensures load balancer exists and the frontend ip config is setup. // This also reconciles the Service's Ports  with the LoadBalancer config. // This entails adding rules/probes for expected Ports and removing stale rules/ports.

} } } else { <del> if isInternal { for i := len(newConfigs) - 1; i >= 0; i-- { config := newConfigs[i] if az.serviceOwnsFrontendIP(config, service) && !strings.EqualFold(*config.Name, lbFrontendIPConfigName) { glog.V(2).Infof("reconcileLoadBalancer for service (%s)(%t): lb frontendconfig(%s) - dropping", serviceName, wantLb, *config.Name) newConfigs = append(newConfigs[:i], newConfigs[i+1:]...) dirtyConfigs = true } </del> <ins> for i := len(newConfigs) - 1; i >= 0; i-- { config := newConfigs[i] isFipChanged, err := az.isFrontendIPChanged(clusterName, config, service, lbFrontendIPConfigName) if err != nil { return nil, err } if isFipChanged { glog.V(2).Infof("reconcileLoadBalancer for service (%s)(%t): lb frontendconfig(%s) - dropping", serviceName, wantLb, *config.Name) newConfigs = append(newConfigs[:i], newConfigs[i+1:]...) dirtyConfigs = true </ins> } } foundConfig := false