Change:
I'm not sure if it's the intended behaviour, but when I specify publicIPs for a service, external portals are only opened if createExternalLoadBalancer is set, too (this is checked in the OnUpdate function in ). After reading the docs, I would have expected that IPTables rules for external IPs are independent of the createExternalLoadBalancer flag. Also, we're running kubernetes locally, so setting createExternalLoadBalancer doesn't work since there's no cloud provider specified.
I was about to say it should work, but then I went and re-read the code and found at least one bug. Let me dig a bit more
You're right - the IPs actually propagate to the proxy, but it ignores them if createExternal... is not set. I think it is kosher to just do it. I'm prepping a PR
PR is up - if you feel bold you could test it in your environment...
Thanks, it's working fine with your patch.

Discussion:
timeout    time.Duration mu         sync.Mutex // protects active active     bool <del> // TODO: make this an net.IP address publicIP []string </del> <ins> publicIP   []string // TODO: make this a []net.IP </ins> } func (si *serviceInfo) isActive() bool {

if exists && info.isActive() && info.portalPort == service.Spec.Port && info.portalIP.Equal(serviceIP) { continue } <del> if exists && (info.portalPort != service.Spec.Port || !info.portalIP.Equal(serviceIP) || service.Spec.CreateExternalLoadBalancer != (len(info.publicIP) > 0)) { </del> <ins> if exists && (info.portalPort != service.Spec.Port || !info.portalIP.Equal(serviceIP) || !ipsEqual(service.Spec.PublicIPs, info.publicIP)) { </ins> glog.V(4).Infof("Something changed for service %q: stopping it", service.Name) err := proxier.closePortal(service.Name, info) if err != nil {

} info.portalIP = serviceIP info.portalPort = service.Spec.Port <del> if service.Spec.CreateExternalLoadBalancer { info.publicIP = service.Spec.PublicIPs } </del> <ins> info.publicIP = service.Spec.PublicIPs </ins> err = proxier.openPortal(service.Name, info) if err != nil { glog.Errorf("Failed to open portal for %q: %v", service.Name, err)

} } <ins> func ipsEqual(lhs, rhs []string) bool { if len(lhs) != len(rhs) { return false } for i := range lhs { if lhs[i] != rhs[i] { return false } } return true } </ins> func (proxier *Proxier) openPortal(service string, info *serviceInfo) error { args := iptablesPortalArgs(info.portalIP, info.portalPort, info.protocol, proxier.listenAddress, info.proxyPort, service) existed, err := proxier.iptables.EnsureRule(iptables.TableNAT, iptablesProxyChain, args...)

if err != nil { return nil, err } <del> var ip net.IP </del> if len(service.Spec.PublicIPs) > 0 { for _, publicIP := range service.Spec.PublicIPs { <del> ip, err = balancer.CreateTCPLoadBalancer(service.Name, zone.Region, net.ParseIP(publicIP), service.Spec.Port, hostsFromMinionList(hosts)) </del> <ins> _, err = balancer.CreateTCPLoadBalancer(service.Name, zone.Region, net.ParseIP(publicIP), service.Spec.Port, hostsFromMinionList(hosts)) </ins> if err != nil { <del> break </del> <ins> // TODO: have to roll-back any successful calls. return nil, err </ins> } } } else { <del> ip, err = balancer.CreateTCPLoadBalancer(service.Name, zone.Region, nil, service.Spec.Port, hostsFromMinionList(hosts)) } if err != nil { return nil, err </del> <ins> ip, err := balancer.CreateTCPLoadBalancer(service.Name, zone.Region, nil, service.Spec.Port, hostsFromMinionList(hosts)) if err != nil { return nil, err } service.Spec.PublicIPs = []string{ip.String()} </ins> } <del> service.Spec.PublicIPs = []string{ip.String()} </del> } err := rs.registry.CreateService(ctx, service) if err != nil {