mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Enabling ILB/ELB on windows using per-node, per-network LB endpoint.
Signed-off-by: Pradip Dhara <pradipd@microsoft.com>
This commit is contained in:
parent
a0bdc52fd7
commit
43360c627f
6 changed files with 167 additions and 9 deletions
|
@ -75,6 +75,7 @@ type endpoint struct {
|
||||||
dbIndex uint64
|
dbIndex uint64
|
||||||
dbExists bool
|
dbExists bool
|
||||||
serviceEnabled bool
|
serviceEnabled bool
|
||||||
|
loadBalancer bool
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +102,7 @@ func (ep *endpoint) MarshalJSON() ([]byte, error) {
|
||||||
epMap["virtualIP"] = ep.virtualIP.String()
|
epMap["virtualIP"] = ep.virtualIP.String()
|
||||||
epMap["ingressPorts"] = ep.ingressPorts
|
epMap["ingressPorts"] = ep.ingressPorts
|
||||||
epMap["svcAliases"] = ep.svcAliases
|
epMap["svcAliases"] = ep.svcAliases
|
||||||
|
epMap["loadBalancer"] = ep.loadBalancer
|
||||||
|
|
||||||
return json.Marshal(epMap)
|
return json.Marshal(epMap)
|
||||||
}
|
}
|
||||||
|
@ -201,6 +203,10 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
|
||||||
ep.virtualIP = net.ParseIP(vip.(string))
|
ep.virtualIP = net.ParseIP(vip.(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v, ok := epMap["loadBalancer"]; ok {
|
||||||
|
ep.loadBalancer = v.(bool)
|
||||||
|
}
|
||||||
|
|
||||||
sal, _ := json.Marshal(epMap["svcAliases"])
|
sal, _ := json.Marshal(epMap["svcAliases"])
|
||||||
var svcAliases []string
|
var svcAliases []string
|
||||||
json.Unmarshal(sal, &svcAliases)
|
json.Unmarshal(sal, &svcAliases)
|
||||||
|
@ -238,6 +244,7 @@ func (ep *endpoint) CopyTo(o datastore.KVObject) error {
|
||||||
dstEp.svcName = ep.svcName
|
dstEp.svcName = ep.svcName
|
||||||
dstEp.svcID = ep.svcID
|
dstEp.svcID = ep.svcID
|
||||||
dstEp.virtualIP = ep.virtualIP
|
dstEp.virtualIP = ep.virtualIP
|
||||||
|
dstEp.loadBalancer = ep.loadBalancer
|
||||||
|
|
||||||
dstEp.svcAliases = make([]string, len(ep.svcAliases))
|
dstEp.svcAliases = make([]string, len(ep.svcAliases))
|
||||||
copy(dstEp.svcAliases, ep.svcAliases)
|
copy(dstEp.svcAliases, ep.svcAliases)
|
||||||
|
@ -1013,6 +1020,13 @@ func CreateOptionMyAlias(alias string) EndpointOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//CreateOptionLoadBalancer function returns an option setter for denoting the endpoint is a load balancer for a network
|
||||||
|
func CreateOptionLoadBalancer() EndpointOption {
|
||||||
|
return func(ep *endpoint) {
|
||||||
|
ep.loadBalancer = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// JoinOptionPriority function returns an option setter for priority option to
|
// JoinOptionPriority function returns an option setter for priority option to
|
||||||
// be passed to the endpoint.Join() method.
|
// be passed to the endpoint.Join() method.
|
||||||
func JoinOptionPriority(ep Endpoint, prio int) EndpointOption {
|
func JoinOptionPriority(ep Endpoint, prio int) EndpointOption {
|
||||||
|
|
|
@ -31,6 +31,9 @@ type EndpointInfo interface {
|
||||||
|
|
||||||
// Sandbox returns the attached sandbox if there, nil otherwise.
|
// Sandbox returns the attached sandbox if there, nil otherwise.
|
||||||
Sandbox() Sandbox
|
Sandbox() Sandbox
|
||||||
|
|
||||||
|
// LoadBalancer returns whether the endpoint is the load balancer endpoint for the network.
|
||||||
|
LoadBalancer() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
|
// InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
|
||||||
|
@ -327,6 +330,12 @@ func (ep *endpoint) Sandbox() Sandbox {
|
||||||
return cnt
|
return cnt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ep *endpoint) LoadBalancer() bool {
|
||||||
|
ep.Lock()
|
||||||
|
defer ep.Unlock()
|
||||||
|
return ep.loadBalancer
|
||||||
|
}
|
||||||
|
|
||||||
func (ep *endpoint) StaticRoutes() []*types.StaticRoute {
|
func (ep *endpoint) StaticRoutes() []*types.StaticRoute {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
defer ep.Unlock()
|
defer ep.Unlock()
|
||||||
|
|
|
@ -89,4 +89,5 @@ type loadBalancer struct {
|
||||||
|
|
||||||
// Back pointer to service to which the loadbalancer belongs.
|
// Back pointer to service to which the loadbalancer belongs.
|
||||||
service *service
|
service *service
|
||||||
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,7 +287,7 @@ func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName s
|
||||||
// Add loadbalancer service and backend in all sandboxes in
|
// Add loadbalancer service and backend in all sandboxes in
|
||||||
// the network only if vip is valid.
|
// the network only if vip is valid.
|
||||||
if len(vip) != 0 {
|
if len(vip) != 0 {
|
||||||
n.(*network).addLBBackend(ip, vip, lb.fwMark, ingressPorts)
|
n.(*network).addLBBackend(ip, vip, lb, ingressPorts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the appropriate name resolutions
|
// Add the appropriate name resolutions
|
||||||
|
@ -355,7 +355,7 @@ func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName st
|
||||||
// Remove loadbalancer service(if needed) and backend in all
|
// Remove loadbalancer service(if needed) and backend in all
|
||||||
// sandboxes in the network only if the vip is valid.
|
// sandboxes in the network only if the vip is valid.
|
||||||
if len(vip) != 0 && entries == 0 {
|
if len(vip) != 0 && entries == 0 {
|
||||||
n.(*network).rmLBBackend(ip, vip, lb.fwMark, ingressPorts, rmService)
|
n.(*network).rmLBBackend(ip, vip, lb, ingressPorts, rmService)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the name resolutions
|
// Delete the name resolutions
|
||||||
|
|
|
@ -111,7 +111,7 @@ func (sb *sandbox) populateLoadbalancers(ep *endpoint) {
|
||||||
|
|
||||||
// Add loadbalancer backend to all sandboxes which has a connection to
|
// Add loadbalancer backend to all sandboxes which has a connection to
|
||||||
// this network. If needed add the service as well.
|
// this network. If needed add the service as well.
|
||||||
func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig) {
|
func (n *network) addLBBackend(ip, vip net.IP, lb *loadBalancer, ingressPorts []*PortConfig) {
|
||||||
n.WalkEndpoints(func(e Endpoint) bool {
|
n.WalkEndpoints(func(e Endpoint) bool {
|
||||||
ep := e.(*endpoint)
|
ep := e.(*endpoint)
|
||||||
if sb, ok := ep.getSandbox(); ok {
|
if sb, ok := ep.getSandbox(); ok {
|
||||||
|
@ -124,7 +124,7 @@ func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po
|
||||||
gwIP = ep.Iface().Address().IP
|
gwIP = ep.Iface().Address().IP
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.addLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, n.ingress)
|
sb.addLBBackend(ip, vip, lb.fwMark, ingressPorts, ep.Iface().Address(), gwIP, n.ingress)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -134,7 +134,7 @@ func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po
|
||||||
// Remove loadbalancer backend from all sandboxes which has a
|
// Remove loadbalancer backend from all sandboxes which has a
|
||||||
// connection to this network. If needed remove the service entry as
|
// connection to this network. If needed remove the service entry as
|
||||||
// well, as specified by the rmService bool.
|
// well, as specified by the rmService bool.
|
||||||
func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, rmService bool) {
|
func (n *network) rmLBBackend(ip, vip net.IP, lb *loadBalancer, ingressPorts []*PortConfig, rmService bool) {
|
||||||
n.WalkEndpoints(func(e Endpoint) bool {
|
n.WalkEndpoints(func(e Endpoint) bool {
|
||||||
ep := e.(*endpoint)
|
ep := e.(*endpoint)
|
||||||
if sb, ok := ep.getSandbox(); ok {
|
if sb, ok := ep.getSandbox(); ok {
|
||||||
|
@ -147,7 +147,7 @@ func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Por
|
||||||
gwIP = ep.Iface().Address().IP
|
gwIP = ep.Iface().Address().IP
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.rmLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, rmService, n.ingress)
|
sb.rmLBBackend(ip, vip, lb.fwMark, ingressPorts, ep.Iface().Address(), gwIP, rmService, n.ingress)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -1,11 +1,145 @@
|
||||||
package libnetwork
|
package libnetwork
|
||||||
|
|
||||||
import "net"
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig) {
|
"github.com/Microsoft/hcsshim"
|
||||||
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type policyLists struct {
|
||||||
|
ilb *hcsshim.PolicyList
|
||||||
|
elb *hcsshim.PolicyList
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, rmService bool) {
|
var lbPolicylistMap map[*loadBalancer]*policyLists
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
lbPolicylistMap = make(map[*loadBalancer]*policyLists)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *network) addLBBackend(ip, vip net.IP, lb *loadBalancer, ingressPorts []*PortConfig) {
|
||||||
|
|
||||||
|
if system.GetOSVersion().Build > 16236 {
|
||||||
|
lb.Lock()
|
||||||
|
defer lb.Unlock()
|
||||||
|
//find the load balancer IP for the network.
|
||||||
|
var sourceVIP string
|
||||||
|
for _, e := range n.Endpoints() {
|
||||||
|
epInfo := e.Info()
|
||||||
|
if epInfo == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if epInfo.LoadBalancer() {
|
||||||
|
sourceVIP = epInfo.Iface().Address().IP.String()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sourceVIP == "" {
|
||||||
|
logrus.Errorf("Failed to find load balancer IP for network %s", n.Name())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var endpoints []hcsshim.HNSEndpoint
|
||||||
|
|
||||||
|
for eid := range lb.backEnds {
|
||||||
|
//Call HNS to get back ID (GUID) corresponding to the endpoint.
|
||||||
|
hnsEndpoint, err := hcsshim.GetHNSEndpointByName(eid)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Failed to find HNS ID for endpoint %v: %v", eid, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints = append(endpoints, *hnsEndpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
if policies, ok := lbPolicylistMap[lb]; ok {
|
||||||
|
|
||||||
|
if policies.ilb != nil {
|
||||||
|
policies.ilb.Delete()
|
||||||
|
policies.ilb = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if policies.elb != nil {
|
||||||
|
policies.elb.Delete()
|
||||||
|
policies.elb = nil
|
||||||
|
}
|
||||||
|
delete(lbPolicylistMap, lb)
|
||||||
|
}
|
||||||
|
|
||||||
|
ilbPolicy, err := hcsshim.AddLoadBalancer(endpoints, true, sourceVIP, vip.String(), 0, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Failed to add ILB policy for service %s (%s) with endpoints %v using load balancer IP %s on network %s: %v",
|
||||||
|
lb.service.name, vip.String(), endpoints, sourceVIP, n.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lbPolicylistMap[lb] = &policyLists{
|
||||||
|
ilb: ilbPolicy,
|
||||||
|
}
|
||||||
|
|
||||||
|
publishedPorts := make(map[uint32]uint32)
|
||||||
|
|
||||||
|
for i, port := range ingressPorts {
|
||||||
|
protocol := uint16(6)
|
||||||
|
|
||||||
|
// Skip already published port
|
||||||
|
if publishedPorts[port.PublishedPort] == port.TargetPort {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if port.Protocol == ProtocolUDP {
|
||||||
|
protocol = 17
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if already has udp matching to add wild card publishing
|
||||||
|
for j := i + 1; j < len(ingressPorts); j++ {
|
||||||
|
if ingressPorts[j].TargetPort == port.TargetPort &&
|
||||||
|
ingressPorts[j].PublishedPort == port.PublishedPort {
|
||||||
|
protocol = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishedPorts[port.PublishedPort] = port.TargetPort
|
||||||
|
|
||||||
|
lbPolicylistMap[lb].elb, err = hcsshim.AddLoadBalancer(endpoints, false, sourceVIP, "", protocol, uint16(port.TargetPort), uint16(port.PublishedPort))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Failed to add ELB policy for service %s (ip:%s target port:%v published port:%v) with endpoints %v using load balancer IP %s on network %s: %v",
|
||||||
|
lb.service.name, vip.String(), uint16(port.TargetPort), uint16(port.PublishedPort), endpoints, sourceVIP, n.Name(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *network) rmLBBackend(ip, vip net.IP, lb *loadBalancer, ingressPorts []*PortConfig, rmService bool) {
|
||||||
|
if system.GetOSVersion().Build > 16236 {
|
||||||
|
if len(lb.backEnds) > 0 {
|
||||||
|
//Reprogram HNS (actually VFP) with the existing backends.
|
||||||
|
n.addLBBackend(ip, vip, lb, ingressPorts)
|
||||||
|
} else {
|
||||||
|
lb.Lock()
|
||||||
|
defer lb.Unlock()
|
||||||
|
logrus.Debugf("No more backends for service %s (ip:%s). Removing all policies", lb.service.name, lb.vip.String())
|
||||||
|
|
||||||
|
if policyLists, ok := lbPolicylistMap[lb]; ok {
|
||||||
|
if policyLists.ilb != nil {
|
||||||
|
policyLists.ilb.Delete()
|
||||||
|
policyLists.ilb = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if policyLists.elb != nil {
|
||||||
|
policyLists.elb.Delete()
|
||||||
|
policyLists.elb = nil
|
||||||
|
}
|
||||||
|
delete(lbPolicylistMap, lb)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logrus.Errorf("Failed to find policies for service %s (%s)", lb.service.name, lb.vip.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sb *sandbox) populateLoadbalancers(ep *endpoint) {
|
func (sb *sandbox) populateLoadbalancers(ep *endpoint) {
|
||||||
|
|
Loading…
Reference in a new issue