New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enabling ILB/ELB on windows using per-node, per-network LB endpoint. #34674
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -136,23 +136,32 @@ func (e *executor) Describe(ctx context.Context) (*api.NodeDescription, error) { | |
} | ||
|
||
func (e *executor) Configure(ctx context.Context, node *api.Node) error { | ||
na := node.Attachment | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not too familiar with this, but is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. node.Attachment has been deprecated https://github.com/docker/swarmkit/blob/master/api/objects.proto#L64 |
||
if na == nil { | ||
var ingressNA *api.NetworkAttachment | ||
lbAttachments := make(map[string]string) | ||
|
||
for _, na := range node.LbAttachments { | ||
if na.Network.Spec.Ingress { | ||
ingressNA = na | ||
} | ||
lbAttachments[na.Network.ID] = na.Addresses[0] | ||
} | ||
|
||
if ingressNA == nil { | ||
e.backend.ReleaseIngress() | ||
return nil | ||
return e.backend.GetLBAttachmentStore().ResetLBAttachments(lbAttachments) | ||
} | ||
|
||
options := types.NetworkCreate{ | ||
Driver: na.Network.DriverState.Name, | ||
Driver: ingressNA.Network.DriverState.Name, | ||
IPAM: &network.IPAM{ | ||
Driver: na.Network.IPAM.Driver.Name, | ||
Driver: ingressNA.Network.IPAM.Driver.Name, | ||
}, | ||
Options: na.Network.DriverState.Options, | ||
Options: ingressNA.Network.DriverState.Options, | ||
Ingress: true, | ||
CheckDuplicate: true, | ||
} | ||
|
||
for _, ic := range na.Network.IPAM.Configs { | ||
for _, ic := range ingressNA.Network.IPAM.Configs { | ||
c := network.IPAMConfig{ | ||
Subnet: ic.Subnet, | ||
IPRange: ic.Range, | ||
|
@@ -162,14 +171,17 @@ func (e *executor) Configure(ctx context.Context, node *api.Node) error { | |
} | ||
|
||
_, err := e.backend.SetupIngress(clustertypes.NetworkCreateRequest{ | ||
ID: na.Network.ID, | ||
ID: ingressNA.Network.ID, | ||
NetworkCreateRequest: types.NetworkCreateRequest{ | ||
Name: na.Network.Spec.Annotations.Name, | ||
Name: ingressNA.Network.Spec.Annotations.Name, | ||
NetworkCreate: options, | ||
}, | ||
}, na.Addresses[0]) | ||
}, ingressNA.Addresses[0]) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return err | ||
return e.backend.GetLBAttachmentStore().ResetLBAttachments(lbAttachments) | ||
} | ||
|
||
// Controller returns a docker container runner. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ import ( | |
"github.com/docker/docker/daemon/events" | ||
"github.com/docker/docker/daemon/exec" | ||
"github.com/docker/docker/daemon/logger" | ||
"github.com/docker/docker/daemon/network" | ||
"github.com/sirupsen/logrus" | ||
// register graph drivers | ||
_ "github.com/docker/docker/daemon/graphdriver/register" | ||
|
@@ -121,6 +122,8 @@ type Daemon struct { | |
pruneRunning int32 | ||
hosts map[string]bool // hosts stores the addresses the daemon is listening on | ||
startupDone chan struct{} | ||
|
||
lbAttachmentStore network.LBAttachmentStore | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
// StoreHosts stores the addresses the daemon is listening on | ||
|
@@ -488,6 +491,8 @@ func (daemon *Daemon) DaemonLeavesCluster() { | |
} else { | ||
logrus.Warnf("failed to initiate ingress network removal: %v", err) | ||
} | ||
|
||
daemon.lbAttachmentStore.ClearLBAttachments() | ||
} | ||
|
||
// setClusterProvider sets a component for querying the current cluster state. | ||
|
@@ -1242,3 +1247,8 @@ func fixMemorySwappiness(resources *containertypes.Resources) { | |
resources.MemorySwappiness = nil | ||
} | ||
} | ||
|
||
// GetLBAttachmentStore returns current load balancer store associated with the daemon | ||
func (daemon *Daemon) GetLBAttachmentStore() *network.LBAttachmentStore { | ||
return &daemon.lbAttachmentStore | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -182,27 +182,8 @@ func (daemon *Daemon) setupIngress(create *clustertypes.NetworkCreateRequest, ip | |
logrus.Errorf("Failed getting ingress network by id after creating: %v", err) | ||
} | ||
|
||
sb, err := controller.NewSandbox("ingress-sbox", libnetwork.OptionIngress()) | ||
if err != nil { | ||
if _, ok := err.(networktypes.ForbiddenError); !ok { | ||
logrus.Errorf("Failed creating ingress sandbox: %v", err) | ||
} | ||
return | ||
} | ||
|
||
ep, err := n.CreateEndpoint("ingress-endpoint", libnetwork.CreateOptionIpam(ip, nil, nil, nil)) | ||
if err != nil { | ||
logrus.Errorf("Failed creating ingress endpoint: %v", err) | ||
return | ||
} | ||
|
||
if err := ep.Join(sb, nil); err != nil { | ||
logrus.Errorf("Failed joining ingress sandbox to ingress endpoint: %v", err) | ||
return | ||
} | ||
|
||
if err := sb.EnableService(); err != nil { | ||
logrus.Errorf("Failed enabling service for ingress sandbox") | ||
if err = daemon.createLoadBalancerSandbox("ingress", create.ID, ip, n, libnetwork.OptionIngress()); err != nil { | ||
logrus.Errorf("Failed creating load balancer sandbox for ingress network: %v", err) | ||
} | ||
} | ||
|
||
|
@@ -283,6 +264,34 @@ func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.N | |
return resp, err | ||
} | ||
|
||
func (daemon *Daemon) createLoadBalancerSandbox(prefix, id string, ip net.IP, n libnetwork.Network, options ...libnetwork.SandboxOption) error { | ||
c := daemon.netController | ||
sandboxName := prefix + "-sbox" | ||
sb, err := c.NewSandbox(sandboxName, options...) | ||
if err != nil { | ||
if _, ok := err.(networktypes.ForbiddenError); !ok { | ||
return errors.Wrapf(err, "Failed creating %s sandbox", sandboxName) | ||
} | ||
return nil | ||
} | ||
|
||
endpointName := prefix + "-endpoint" | ||
ep, err := n.CreateEndpoint(endpointName, libnetwork.CreateOptionIpam(ip, nil, nil, nil), libnetwork.CreateOptionLoadBalancer()) | ||
if err != nil { | ||
return errors.Wrapf(err, "Failed creating %s in sandbox %s", endpointName, sandboxName) | ||
} | ||
|
||
if err := ep.Join(sb, nil); err != nil { | ||
return errors.Wrapf(err, "Failed joining %s to sandbox %s", endpointName, sandboxName) | ||
} | ||
|
||
if err := sb.EnableService(); err != nil { | ||
return errors.Wrapf(err, "Failed enabling service in %s sandbox", sandboxName) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) { | ||
if runconfig.IsPreDefinedNetwork(create.Name) && !agent { | ||
err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name) | ||
|
@@ -360,6 +369,18 @@ func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string | |
} | ||
daemon.LogNetworkEvent(n, "create") | ||
|
||
if agent && !n.Info().Ingress() && n.Type() == "overlay" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please move this code (and the code in deleteNetwork) to a new function. A separate function will make it easier to unit test, and help the reader understand the different steps performed as part of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
nodeIP, exists := daemon.GetLBAttachmentStore().GetLBIPForNetwork(id) | ||
if !exists { | ||
return nil, fmt.Errorf("Failed to find a load balancer IP to use for network: %v", id) | ||
} | ||
|
||
if err := daemon.createLoadBalancerSandbox(create.Name, id, nodeIP, n); err != nil { | ||
return nil, err | ||
} | ||
|
||
} | ||
|
||
return &types.NetworkCreateResponse{ | ||
ID: n.ID(), | ||
Warning: warning, | ||
|
@@ -496,6 +517,31 @@ func (daemon *Daemon) DeleteNetwork(networkID string) error { | |
return daemon.deleteNetwork(networkID, false) | ||
} | ||
|
||
func (daemon *Daemon) deleteLoadBalancerSandbox(n libnetwork.Network) { | ||
controller := daemon.netController | ||
|
||
//The only endpoint left should be the LB endpoint (nw.Name() + "-endpoint") | ||
endpoints := n.Endpoints() | ||
if len(endpoints) == 1 { | ||
sandboxName := n.Name() + "-sbox" | ||
|
||
if err := endpoints[0].Info().Sandbox().DisableService(); err != nil { | ||
logrus.Errorf("Failed to disable service on sandbox %s: %v", sandboxName, err) | ||
//Ignore error and attempt to delete the load balancer endpoint | ||
} | ||
|
||
if err := endpoints[0].Delete(true); err != nil { | ||
logrus.Errorf("Failed to delete endpoint %s (%s) in %s: %v", endpoints[0].Name(), endpoints[0].ID(), sandboxName, err) | ||
//Ignore error and attempt to delete the sandbox. | ||
} | ||
|
||
if err := controller.SandboxDestroy(sandboxName); err != nil { | ||
logrus.Errorf("Failed to delete %s sandbox: %v", sandboxName, err) | ||
//Ignore error and attempt to delete the network. | ||
} | ||
} | ||
} | ||
|
||
func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error { | ||
nw, err := daemon.FindNetwork(networkID) | ||
if err != nil { | ||
|
@@ -517,6 +563,10 @@ func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error { | |
return notAllowedError{err} | ||
} | ||
|
||
if !nw.Info().Ingress() && nw.Type() == "overlay" { | ||
daemon.deleteLoadBalancerSandbox(nw) | ||
} | ||
|
||
if err := nw.Delete(); err != nil { | ||
return err | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,12 @@ | ||
package network | ||
|
||
import ( | ||
"net" | ||
|
||
networktypes "github.com/docker/docker/api/types/network" | ||
clustertypes "github.com/docker/docker/daemon/cluster/provider" | ||
"github.com/docker/go-connections/nat" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
// Settings stores configuration details about the daemon network config | ||
|
@@ -31,3 +34,36 @@ type EndpointSettings struct { | |
*networktypes.EndpointSettings | ||
IPAMOperational bool | ||
} | ||
|
||
// LBAttachmentStore stores the load balancer IP address for a network id. | ||
type LBAttachmentStore struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
//key: networkd id | ||
//value: load balancer ip address | ||
networkToNodeLBIP map[string]net.IP | ||
} | ||
|
||
// ResetLBAttachments clears any exsiting load balancer IP to network mapping and | ||
// sets the mapping to the given lbAttachments. | ||
func (lbStore *LBAttachmentStore) ResetLBAttachments(lbAttachments map[string]string) error { | ||
lbStore.ClearLBAttachments() | ||
for nid, nodeIP := range lbAttachments { | ||
ip, _, err := net.ParseCIDR(nodeIP) | ||
if err != nil { | ||
lbStore.networkToNodeLBIP = make(map[string]net.IP) | ||
return errors.Wrapf(err, "Failed to parse load balancer address %s", nodeIP) | ||
} | ||
lbStore.networkToNodeLBIP[nid] = ip | ||
} | ||
return nil | ||
} | ||
|
||
// ClearLBAttachments clears all the mappings of network to load balancer IP Address. | ||
func (lbStore *LBAttachmentStore) ClearLBAttachments() { | ||
lbStore.networkToNodeLBIP = make(map[string]net.IP) | ||
} | ||
|
||
// GetLBIPForNetwork return the load balancer IP address for the given network. | ||
func (lbStore *LBAttachmentStore) GetLBIPForNetwork(networkID string) (net.IP, bool) { | ||
ip, exists := lbStore.networkToNodeLBIP[networkID] | ||
return ip, exists | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetAttachmentStore