Change:
From we can find that, hardcode "private" and "public", seems only support that network with such name. , it fetch the first ip. usually, it can include both v6 and v4 ip. what's the meaning to just fetch the first one ? is it v4 or v6 ?
ping and
Yes. Zoom out a level or two in the code, and you'll see we're trying to either a) setup an openstack loadbalancer to point to the minion node (a single address) using , or b) report to kubernetes all the addresses we know about the node and whether they are "internal" or "external" in . All we have at the starting point is the server name (from kubernetes), and we need to make up the rest of this information somehow. (I agree (a) should reuse the NodeAddresses() function from (b), but the latter is a newer function and the code hasn't yet been refactored in that way. This doesn't really change the substance of this discussion.) Re (1): The logic as currently implemented is: Assume any network named "private" is "internal" Assume any network named "public" is "external" Assume the AccessIPs (IPv4 and IPv6) are "external" Any other network addresses are ignored. I implemented the first two ("private" and "public") following the Rackspace public cloud precedent, and on the basis that users in other OpenStack clouds can use these names if they want to encourage an address other than the Access addresses. For the (a) use case, we just take the first address we find in order of the above; for (b) we report that full list. I preferred "private" to "public" since (again, at least on Rackspace public cloud), the traffic on "private" network is sometimes cheaper/free. I agree this isn't great, and please suggest something better if you have a use case in mind. Perhaps we should pull a list of network names that should be considered "internal" and "external" from the provider config? Perhaps I could assume that provider networks are public and non-provider networks are internal? I don't want to add too much configuration here if there's a good algorithm that will Just Work. I think in practice it's probably ok to continue to prefer "internal" to "external" for loadbalancer setup, but I can contrive hypothetical cases that need more flexibility here too. Again, if you have a concrete need for such a thing, please file a bug so we have some idea of the flexibility required. Complicating all this is that Kubernetes never actually defined what an "internal" address was. just says "Generally the IP address of the node that is routable only within the cluster" which isn't a sufficiently strict definition. Looking at where Kubernetes actually uses it: just uses the first address reported (preferring InternalIPs to ExternalIPs) and the Kubernetes master configures an "SSH Tunnel Check" which just uses the first ExternalIP ... which kind of makes it pointless to ever even bother reporting anything beyond the first address. In both cases, it's assumed that this address is reachable by the Kubernetes master nodes, which makes the Internal vs External distinction a bit pointless. Re (2): is meant to return more than one IP, and the loadbalancer setup can only use a single IP for each node (or would unnecessarily track/healthceck multiple paths to the same backend for multiple addresses). If you're seeing single addresses returned by then you should file a bug. All the above treats IPv4 and IPv6 as equally important, if the OpenStack cloud has both, and the "first" address used for the loadbalancer will be an arbitrary choice between the two protocols (not quite true: will use AccessIPv4 before AccessIPv6). I think that's how it should be (the rest of the code should be protocol agnostic), but I wouldn't be surprised if there's some part of Kubernetes that doesn't support IPv6 properly. There certainly used to be lots of places that assumed IPv4 in Kubernetes, and GCE doesn't support IPv6 iirc so it gets less testing - if you've found something that breaks with IPv6, please file bugs. Now this bug: what would you like done here? Would you like the current situation to be documented further? Is the "private"/"public" naming thing too restrictive for your usecase? Something else?
Hi, if we talked about openstack, I expect it not bind to rackspace, although, the kubernetes called RK SDK, But from my understanding, seems RK itself SDK not bind network to "private" and "pubic". User can define public network with their names, like site-network, for example. or "testnet", And for private, it should be seem. For nova list, the addresses, it can have "OS-EXT-IPS:type":"fixed" or "OS-EXT-IPS:type":"floating" for floating, I think what you means "Public", for fixed, I think its what you means "Private". In other words, we'd better to find related information from other fields in nova or neutron infromation. Instead of bind to "private" and "public" name.
I this issue and wrote a patch that implements what suggests. I will send a PR soon
Glad to see some improvements here. And wish to use it if implemented

Discussion:
return &serverList[0], nil } <del> func findAddrs(netblob interface{}) []string { // Run-time types for the win :( ret := []string{} list, ok := netblob.([]interface{}) if !ok { return ret } for _, item := range list { props, ok := item.(map[string]interface{}) if !ok { continue } tmp, ok := props["addr"] </del> <ins> func getAddressesByName(client *gophercloud.ServiceClient, name string) ([]api.NodeAddress, error) { srv, err := getServerByName(client, name) if err != nil { return nil, err } addrs := []api.NodeAddress{} for network, netblob := range srv.Addresses { list, ok := netblob.([]interface{}) </ins> if !ok { continue } <del> addr, ok := tmp.(string) if !ok { continue </del> <ins> for _, item := range list { var addressType api.NodeAddressType props, ok := item.(map[string]interface{}) if !ok { continue } extIPType, ok := props["OS-EXT-IPS:type"] if (ok && extIPType == "floating") || (!ok && network == "public") { addressType = api.NodeExternalIP } else { addressType = api.NodeInternalIP } tmp, ok := props["addr"] if !ok { continue } addr, ok := tmp.(string) if !ok { continue } api.AddToNodeAddresses(&addrs, api.NodeAddress{ Type:    addressType, Address: addr, }, ) </ins> } <del> ret = append(ret, addr) </del> } <del> return ret </del> <ins> // AccessIPs are usually duplicates of "public" addresses. if srv.AccessIPv4 != "" { api.AddToNodeAddresses(&addrs, api.NodeAddress{ Type:    api.NodeExternalIP, Address: srv.AccessIPv4, }, ) } if srv.AccessIPv6 != "" { api.AddToNodeAddresses(&addrs, api.NodeAddress{ Type:    api.NodeExternalIP, Address: srv.AccessIPv6, }, ) } return addrs, nil </ins> } <del> func getAddressByName(api *gophercloud.ServiceClient, name string) (string, error) { srv, err := getServerByName(api, name) </del> <ins> func getAddressByName(client *gophercloud.ServiceClient, name string) (string, error) { addrs, err := getAddressesByName(client, name) </ins> if err != nil { return "", err <ins> } else if len(addrs) == 0 { return "", ErrNoAddressFound </ins> } <del> var s string if s == "" { if tmp := findAddrs(srv.Addresses["private"]); len(tmp) >= 1 { s = tmp[0] } } if s == "" { if tmp := findAddrs(srv.Addresses["public"]); len(tmp) >= 1 { s = tmp[0] </del> <ins> for _, addr := range addrs { if addr.Type == api.NodeInternalIP { return addr.Address, nil </ins> } } <del> if s == "" { s = srv.AccessIPv4 } if s == "" { s = srv.AccessIPv6 } if s == "" { return "", ErrNoAddressFound } return s, nil </del> <ins> return addrs[0].Address, nil </ins> } // Implementation of Instances.CurrentNodeName

func (i *Instances) NodeAddresses(name string) ([]api.NodeAddress, error) { glog.V(4).Infof("NodeAddresses(%v) called", name) <del> srv, err := getServerByName(i.compute, name) </del> <ins> addrs, err := getAddressesByName(i.compute, name) </ins> if err != nil { return nil, err } <del> addrs := []api.NodeAddress{} for _, addr := range findAddrs(srv.Addresses["private"]) { addrs = append(addrs, api.NodeAddress{ Type:    api.NodeInternalIP, Address: addr, }) } for _, addr := range findAddrs(srv.Addresses["public"]) { addrs = append(addrs, api.NodeAddress{ Type:    api.NodeExternalIP, Address: addr, }) } // AccessIPs are usually duplicates of "public" addresses. api.AddToNodeAddresses(&addrs, api.NodeAddress{ Type:    api.NodeExternalIP, Address: srv.AccessIPv6, }, api.NodeAddress{ Type:    api.NodeExternalIP, Address: srv.AccessIPv4, }, ) </del> glog.V(4).Infof("NodeAddresses(%v) => %v", name, addrs) return addrs, nil }