// SetupIngress setups ingress networking. func (daemon *Daemon) SetupIngress(create clustertypes.NetworkCreateRequest, nodeIP string) error { ip, _, err := net.ParseCIDR(nodeIP) if err != nil { return err } go func() { controller := daemon.netController controller.AgentInitWait() if n, err := daemon.GetNetworkByName(create.Name); err == nil && n != nil && n.ID() != create.ID { if err := controller.SandboxDestroy("ingress-sbox"); err != nil { logrus.Errorf("Failed to delete stale ingress sandbox: %v", err) return } if err := n.Delete(); err != nil { logrus.Errorf("Failed to delete stale ingress network %s: %v", n.ID(), err) return } } if _, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true); err != nil { // If it is any other error other than already // exists error log error and return. if _, ok := err.(libnetwork.NetworkNameError); !ok { logrus.Errorf("Failed creating ingress network: %v", err) return } // Otherwise continue down the call to create or recreate sandbox. } n, err := daemon.GetNetworkByID(create.ID) if err != nil { logrus.Errorf("Failed getting ingress network by id after creating: %v", err) return } sb, err := controller.NewSandbox("ingress-sbox", libnetwork.OptionIngress()) if err != nil { 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 nil }
// BuildCreateEndpointOptions builds endpoint options from a given network. func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *networktypes.EndpointSettings, sb libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) { var ( bindings = make(nat.PortMap) pbList []types.PortBinding exposeList []types.TransportPort createOptions []libnetwork.EndpointOption ) defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName() if (!container.EnableServiceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) || container.NetworkSettings.IsAnonymousEndpoint { createOptions = append(createOptions, libnetwork.CreateOptionAnonymous()) } if epConfig != nil { ipam := epConfig.IPAMConfig if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "" || len(ipam.LinkLocalIPs) > 0) { var ipList []net.IP for _, ips := range ipam.LinkLocalIPs { if ip := net.ParseIP(ips); ip != nil { ipList = append(ipList, ip) } } createOptions = append(createOptions, libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), ipList, nil)) } for _, alias := range epConfig.Aliases { createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias)) } } if container.NetworkSettings.Service != nil { svcCfg := container.NetworkSettings.Service var vip string if svcCfg.VirtualAddresses[n.ID()] != nil { vip = svcCfg.VirtualAddresses[n.ID()].IPv4 } var portConfigs []*libnetwork.PortConfig for _, portConfig := range svcCfg.ExposedPorts { portConfigs = append(portConfigs, &libnetwork.PortConfig{ Name: portConfig.Name, Protocol: libnetwork.PortConfig_Protocol(portConfig.Protocol), TargetPort: portConfig.TargetPort, PublishedPort: portConfig.PublishedPort, }) } createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, net.ParseIP(vip), portConfigs, svcCfg.Aliases[n.ID()])) } if !containertypes.NetworkMode(n.Name()).IsUserDefined() { createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) } // configs that are applicable only for the endpoint in the network // to which container was connected to on docker run. // Ideally all these network-specific endpoint configurations must be moved under // container.NetworkSettings.Networks[n.Name()] if n.Name() == container.HostConfig.NetworkMode.NetworkName() || (n.Name() == defaultNetName && container.HostConfig.NetworkMode.IsDefault()) { if container.Config.MacAddress != "" { mac, err := net.ParseMAC(container.Config.MacAddress) if err != nil { return nil, err } genericOption := options.Generic{ netlabel.MacAddress: mac, } createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) } } // Port-mapping rules belong to the container & applicable only to non-internal networks portmaps := GetSandboxPortMapInfo(sb) if n.Info().Internal() || len(portmaps) > 0 { return createOptions, nil } if container.HostConfig.PortBindings != nil { for p, b := range container.HostConfig.PortBindings { bindings[p] = []nat.PortBinding{} for _, bb := range b { bindings[p] = append(bindings[p], nat.PortBinding{ HostIP: bb.HostIP, HostPort: bb.HostPort, }) } } } portSpecs := container.Config.ExposedPorts ports := make([]nat.Port, len(portSpecs)) var i int for p := range portSpecs { ports[i] = p i++ } nat.SortPortMap(ports, bindings) for _, port := range ports { expose := types.TransportPort{} expose.Proto = types.ParseProtocol(port.Proto()) expose.Port = uint16(port.Int()) exposeList = append(exposeList, expose) pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} binding := bindings[port] for i := 0; i < len(binding); i++ { pbCopy := pb.GetCopy() newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) var portStart, portEnd int if err == nil { portStart, portEnd, err = newP.Range() } if err != nil { return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err) } pbCopy.HostPort = uint16(portStart) pbCopy.HostPortEnd = uint16(portEnd) pbCopy.HostIP = net.ParseIP(binding[i].HostIP) pbList = append(pbList, pbCopy) } if container.HostConfig.PublishAllPorts && len(binding) == 0 { pbList = append(pbList, pb) } } var dns []string if len(container.HostConfig.DNS) > 0 { dns = container.HostConfig.DNS } else if len(daemonDNS) > 0 { dns = daemonDNS } if len(dns) > 0 { createOptions = append(createOptions, libnetwork.CreateOptionDNS(dns)) } createOptions = append(createOptions, libnetwork.CreateOptionPortMapping(pbList), libnetwork.CreateOptionExposedPorts(exposeList)) return createOptions, nil }
// BuildCreateEndpointOptions builds endpoint options from a given network. func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *network.EndpointSettings, sb libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) { var ( portSpecs = make(nat.PortSet) bindings = make(nat.PortMap) pbList []types.PortBinding exposeList []types.TransportPort createOptions []libnetwork.EndpointOption ) if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint { createOptions = append(createOptions, libnetwork.CreateOptionAnonymous()) } if epConfig != nil { ipam := epConfig.IPAMConfig if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") { createOptions = append(createOptions, libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil)) } for _, alias := range epConfig.Aliases { createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias)) } } if !containertypes.NetworkMode(n.Name()).IsUserDefined() { createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) } // configs that are applicable only for the endpoint in the network // to which container was connected to on docker run. // Ideally all these network-specific endpoint configurations must be moved under // container.NetworkSettings.Networks[n.Name()] if n.Name() == container.HostConfig.NetworkMode.NetworkName() || (n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) { if container.Config.MacAddress != "" { mac, err := net.ParseMAC(container.Config.MacAddress) if err != nil { return nil, err } genericOption := options.Generic{ netlabel.MacAddress: mac, } createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) } } // Port-mapping rules belong to the container & applicable only to non-internal networks portmaps := getSandboxPortMapInfo(sb) if n.Info().Internal() || len(portmaps) > 0 { return createOptions, nil } if container.Config.ExposedPorts != nil { portSpecs = container.Config.ExposedPorts } if container.HostConfig.PortBindings != nil { for p, b := range container.HostConfig.PortBindings { bindings[p] = []nat.PortBinding{} for _, bb := range b { bindings[p] = append(bindings[p], nat.PortBinding{ HostIP: bb.HostIP, HostPort: bb.HostPort, }) } } } ports := make([]nat.Port, len(portSpecs)) var i int for p := range portSpecs { ports[i] = p i++ } nat.SortPortMap(ports, bindings) for _, port := range ports { expose := types.TransportPort{} expose.Proto = types.ParseProtocol(port.Proto()) expose.Port = uint16(port.Int()) exposeList = append(exposeList, expose) pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} binding := bindings[port] for i := 0; i < len(binding); i++ { pbCopy := pb.GetCopy() newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) var portStart, portEnd int if err == nil { portStart, portEnd, err = newP.Range() } if err != nil { return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err) } pbCopy.HostPort = uint16(portStart) pbCopy.HostPortEnd = uint16(portEnd) pbCopy.HostIP = net.ParseIP(binding[i].HostIP) pbList = append(pbList, pbCopy) } if container.HostConfig.PublishAllPorts && len(binding) == 0 { pbList = append(pbList, pb) } } createOptions = append(createOptions, libnetwork.CreateOptionPortMapping(pbList), libnetwork.CreateOptionExposedPorts(exposeList)) return createOptions, nil }
// BuildCreateEndpointOptions builds endpoint options from a given network. func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) { var ( portSpecs = make(nat.PortSet) bindings = make(nat.PortMap) pbList []types.PortBinding exposeList []types.TransportPort createOptions []libnetwork.EndpointOption ) if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint { createOptions = append(createOptions, libnetwork.CreateOptionAnonymous()) } if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok { ipam := epConfig.IPAMConfig if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") { createOptions = append(createOptions, libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil)) } } if !container.HostConfig.NetworkMode.IsUserDefined() { createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution()) } // Other configs are applicable only for the endpoint in the network // to which container was connected to on docker run. if n.Name() != container.HostConfig.NetworkMode.NetworkName() && !(n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) { return createOptions, nil } if container.Config.ExposedPorts != nil { portSpecs = container.Config.ExposedPorts } if container.HostConfig.PortBindings != nil { for p, b := range container.HostConfig.PortBindings { bindings[p] = []nat.PortBinding{} for _, bb := range b { bindings[p] = append(bindings[p], nat.PortBinding{ HostIP: bb.HostIP, HostPort: bb.HostPort, }) } } } ports := make([]nat.Port, len(portSpecs)) var i int for p := range portSpecs { ports[i] = p i++ } nat.SortPortMap(ports, bindings) for _, port := range ports { expose := types.TransportPort{} expose.Proto = types.ParseProtocol(port.Proto()) expose.Port = uint16(port.Int()) exposeList = append(exposeList, expose) pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} binding := bindings[port] for i := 0; i < len(binding); i++ { pbCopy := pb.GetCopy() newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort)) var portStart, portEnd int if err == nil { portStart, portEnd, err = newP.Range() } if err != nil { return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err) } pbCopy.HostPort = uint16(portStart) pbCopy.HostPortEnd = uint16(portEnd) pbCopy.HostIP = net.ParseIP(binding[i].HostIP) pbList = append(pbList, pbCopy) } if container.HostConfig.PublishAllPorts && len(binding) == 0 { pbList = append(pbList, pb) } } createOptions = append(createOptions, libnetwork.CreateOptionPortMapping(pbList), libnetwork.CreateOptionExposedPorts(exposeList)) if container.Config.MacAddress != "" { mac, err := net.ParseMAC(container.Config.MacAddress) if err != nil { return nil, err } genericOption := options.Generic{ netlabel.MacAddress: mac, } createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption)) } return createOptions, nil }
// SetupIngress setups ingress networking. func (daemon *Daemon) SetupIngress(create clustertypes.NetworkCreateRequest, nodeIP string) error { ip, _, err := net.ParseCIDR(nodeIP) if err != nil { return err } go func() { controller := daemon.netController controller.AgentInitWait() if n, err := daemon.GetNetworkByName(create.Name); err == nil && n != nil && n.ID() != create.ID { if err := controller.SandboxDestroy("ingress-sbox"); err != nil { logrus.Errorf("Failed to delete stale ingress sandbox: %v", err) return } // Cleanup any stale endpoints that might be left over during previous iterations epList := n.Endpoints() for _, ep := range epList { if err := ep.Delete(true); err != nil { logrus.Errorf("Failed to delete endpoint %s (%s): %v", ep.Name(), ep.ID(), err) } } if err := n.Delete(); err != nil { logrus.Errorf("Failed to delete stale ingress network %s: %v", n.ID(), err) return } } if _, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true); err != nil { // If it is any other error other than already // exists error log error and return. if _, ok := err.(libnetwork.NetworkNameError); !ok { logrus.Errorf("Failed creating ingress network: %v", err) return } // Otherwise continue down the call to create or recreate sandbox. } n, err := daemon.GetNetworkByID(create.ID) if err != nil { logrus.Errorf("Failed getting ingress network by id after creating: %v", err) return } 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) } if err := sb.EnableService(); err != nil { logrus.WithError(err).Error("Failed enabling service for ingress sandbox") } }() return nil }