service_common.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. // +build linux windows
  2. package libnetwork
  3. import (
  4. "net"
  5. "github.com/docker/libnetwork/common"
  6. "github.com/sirupsen/logrus"
  7. )
  8. const maxSetStringLen = 350
  9. func (c *controller) addEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, addService bool, method string) error {
  10. n, err := c.NetworkByID(nID)
  11. if err != nil {
  12. return err
  13. }
  14. logrus.Debugf("addEndpointNameResolution %s %s add_service:%t sAliases:%v tAliases:%v", eID, svcName, addService, serviceAliases, taskAliases)
  15. // Add container resolution mappings
  16. c.addContainerNameResolution(nID, eID, containerName, taskAliases, ip, method)
  17. serviceID := svcID
  18. if serviceID == "" {
  19. // This is the case of a normal container not part of a service
  20. serviceID = eID
  21. }
  22. // Add endpoint IP to special "tasks.svc_name" so that the applications have access to DNS RR.
  23. n.(*network).addSvcRecords(eID, "tasks."+svcName, serviceID, ip, nil, false, method)
  24. for _, alias := range serviceAliases {
  25. n.(*network).addSvcRecords(eID, "tasks."+alias, serviceID, ip, nil, false, method)
  26. }
  27. // Add service name to vip in DNS, if vip is valid. Otherwise resort to DNS RR
  28. if len(vip) == 0 {
  29. n.(*network).addSvcRecords(eID, svcName, serviceID, ip, nil, false, method)
  30. for _, alias := range serviceAliases {
  31. n.(*network).addSvcRecords(eID, alias, serviceID, ip, nil, false, method)
  32. }
  33. }
  34. if addService && len(vip) != 0 {
  35. n.(*network).addSvcRecords(eID, svcName, serviceID, vip, nil, false, method)
  36. for _, alias := range serviceAliases {
  37. n.(*network).addSvcRecords(eID, alias, serviceID, vip, nil, false, method)
  38. }
  39. }
  40. return nil
  41. }
  42. func (c *controller) addContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error {
  43. n, err := c.NetworkByID(nID)
  44. if err != nil {
  45. return err
  46. }
  47. logrus.Debugf("addContainerNameResolution %s %s", eID, containerName)
  48. // Add resolution for container name
  49. n.(*network).addSvcRecords(eID, containerName, eID, ip, nil, true, method)
  50. // Add resolution for taskaliases
  51. for _, alias := range taskAliases {
  52. n.(*network).addSvcRecords(eID, alias, eID, ip, nil, true, method)
  53. }
  54. return nil
  55. }
  56. func (c *controller) deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, rmService, multipleEntries bool, method string) error {
  57. n, err := c.NetworkByID(nID)
  58. if err != nil {
  59. return err
  60. }
  61. logrus.Debugf("deleteEndpointNameResolution %s %s rm_service:%t suppress:%t sAliases:%v tAliases:%v", eID, svcName, rmService, multipleEntries, serviceAliases, taskAliases)
  62. // Delete container resolution mappings
  63. c.delContainerNameResolution(nID, eID, containerName, taskAliases, ip, method)
  64. serviceID := svcID
  65. if serviceID == "" {
  66. // This is the case of a normal container not part of a service
  67. serviceID = eID
  68. }
  69. // Delete the special "tasks.svc_name" backend record.
  70. if !multipleEntries {
  71. n.(*network).deleteSvcRecords(eID, "tasks."+svcName, serviceID, ip, nil, false, method)
  72. for _, alias := range serviceAliases {
  73. n.(*network).deleteSvcRecords(eID, "tasks."+alias, serviceID, ip, nil, false, method)
  74. }
  75. }
  76. // If we are doing DNS RR delete the endpoint IP from DNS record right away.
  77. if !multipleEntries && len(vip) == 0 {
  78. n.(*network).deleteSvcRecords(eID, svcName, serviceID, ip, nil, false, method)
  79. for _, alias := range serviceAliases {
  80. n.(*network).deleteSvcRecords(eID, alias, serviceID, ip, nil, false, method)
  81. }
  82. }
  83. // Remove the DNS record for VIP only if we are removing the service
  84. if rmService && len(vip) != 0 && !multipleEntries {
  85. n.(*network).deleteSvcRecords(eID, svcName, serviceID, vip, nil, false, method)
  86. for _, alias := range serviceAliases {
  87. n.(*network).deleteSvcRecords(eID, alias, serviceID, vip, nil, false, method)
  88. }
  89. }
  90. return nil
  91. }
  92. func (c *controller) delContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error {
  93. n, err := c.NetworkByID(nID)
  94. if err != nil {
  95. return err
  96. }
  97. logrus.Debugf("delContainerNameResolution %s %s", eID, containerName)
  98. // Delete resolution for container name
  99. n.(*network).deleteSvcRecords(eID, containerName, eID, ip, nil, true, method)
  100. // Delete resolution for taskaliases
  101. for _, alias := range taskAliases {
  102. n.(*network).deleteSvcRecords(eID, alias, eID, ip, nil, true, method)
  103. }
  104. return nil
  105. }
  106. func newService(name string, id string, ingressPorts []*PortConfig, serviceAliases []string) *service {
  107. return &service{
  108. name: name,
  109. id: id,
  110. ingressPorts: ingressPorts,
  111. loadBalancers: make(map[string]*loadBalancer),
  112. aliases: serviceAliases,
  113. ipToEndpoint: common.NewSetMatrix(),
  114. }
  115. }
  116. func (c *controller) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int {
  117. skey := serviceKey{
  118. id: sid,
  119. ports: portConfigs(ingressPorts).String(),
  120. }
  121. c.Lock()
  122. s, ok := c.serviceBindings[skey]
  123. c.Unlock()
  124. if !ok {
  125. return 0
  126. }
  127. s.Lock()
  128. lb := s.loadBalancers[nid]
  129. s.Unlock()
  130. return int(lb.fwMark)
  131. }
  132. // cleanupServiceDiscovery when the network is being deleted, erase all the associated service discovery records
  133. func (c *controller) cleanupServiceDiscovery(cleanupNID string) {
  134. c.Lock()
  135. defer c.Unlock()
  136. if cleanupNID == "" {
  137. logrus.Debugf("cleanupServiceDiscovery for all networks")
  138. c.svcRecords = make(map[string]svcInfo)
  139. return
  140. }
  141. logrus.Debugf("cleanupServiceDiscovery for network:%s", cleanupNID)
  142. delete(c.svcRecords, cleanupNID)
  143. }
  144. func (c *controller) cleanupServiceBindings(cleanupNID string) {
  145. var cleanupFuncs []func()
  146. logrus.Debugf("cleanupServiceBindings for %s", cleanupNID)
  147. c.Lock()
  148. services := make([]*service, 0, len(c.serviceBindings))
  149. for _, s := range c.serviceBindings {
  150. services = append(services, s)
  151. }
  152. c.Unlock()
  153. for _, s := range services {
  154. s.Lock()
  155. // Skip the serviceBindings that got deleted
  156. if s.deleted {
  157. s.Unlock()
  158. continue
  159. }
  160. for nid, lb := range s.loadBalancers {
  161. if cleanupNID != "" && nid != cleanupNID {
  162. continue
  163. }
  164. for eid, ip := range lb.backEnds {
  165. epID := eid
  166. epIP := ip
  167. service := s
  168. loadBalancer := lb
  169. networkID := nid
  170. cleanupFuncs = append(cleanupFuncs, func() {
  171. // ContainerName and taskAliases are not available here, this is still fine because the Service discovery
  172. // cleanup already happened before. The only thing that rmServiceBinding is still doing here a part from the Load
  173. // Balancer bookeeping, is to keep consistent the mapping of endpoint to IP.
  174. if err := c.rmServiceBinding(service.name, service.id, networkID, epID, "", loadBalancer.vip,
  175. service.ingressPorts, service.aliases, []string{}, epIP, "cleanupServiceBindings", false); err != nil {
  176. logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v",
  177. service.id, networkID, epID, err)
  178. }
  179. })
  180. }
  181. }
  182. s.Unlock()
  183. }
  184. for _, f := range cleanupFuncs {
  185. f()
  186. }
  187. }
  188. func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases, taskAliases []string, ip net.IP, method string) error {
  189. var addService bool
  190. n, err := c.NetworkByID(nID)
  191. if err != nil {
  192. return err
  193. }
  194. skey := serviceKey{
  195. id: svcID,
  196. ports: portConfigs(ingressPorts).String(),
  197. }
  198. var s *service
  199. for {
  200. c.Lock()
  201. var ok bool
  202. s, ok = c.serviceBindings[skey]
  203. if !ok {
  204. // Create a new service if we are seeing this service
  205. // for the first time.
  206. s = newService(svcName, svcID, ingressPorts, serviceAliases)
  207. c.serviceBindings[skey] = s
  208. }
  209. c.Unlock()
  210. s.Lock()
  211. if !s.deleted {
  212. // ok the object is good to be used
  213. break
  214. }
  215. s.Unlock()
  216. }
  217. logrus.Debugf("addServiceBinding from %s START for %s %s p:%p nid:%s skey:%v", method, svcName, eID, s, nID, skey)
  218. defer s.Unlock()
  219. lb, ok := s.loadBalancers[nID]
  220. if !ok {
  221. // Create a new load balancer if we are seeing this
  222. // network attachment on the service for the first
  223. // time.
  224. fwMarkCtrMu.Lock()
  225. lb = &loadBalancer{
  226. vip: vip,
  227. fwMark: fwMarkCtr,
  228. backEnds: make(map[string]net.IP),
  229. service: s,
  230. }
  231. fwMarkCtr++
  232. fwMarkCtrMu.Unlock()
  233. s.loadBalancers[nID] = lb
  234. addService = true
  235. }
  236. lb.backEnds[eID] = ip
  237. ok, entries := s.assignIPToEndpoint(ip.String(), eID)
  238. if !ok || entries > 1 {
  239. setStr, b := s.printIPToEndpoint(ip.String())
  240. logrus.Warnf("addServiceBinding %s possible transient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr[:maxSetStringLen])
  241. }
  242. // Add loadbalancer service and backend in all sandboxes in
  243. // the network only if vip is valid.
  244. if len(vip) != 0 {
  245. n.(*network).addLBBackend(ip, vip, lb, ingressPorts)
  246. }
  247. // Add the appropriate name resolutions
  248. c.addEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, addService, "addServiceBinding")
  249. logrus.Debugf("addServiceBinding from %s END for %s %s", method, svcName, eID)
  250. return nil
  251. }
  252. func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases []string, taskAliases []string, ip net.IP, method string, deleteSvcRecords bool) error {
  253. var rmService bool
  254. n, err := c.NetworkByID(nID)
  255. if err != nil {
  256. return err
  257. }
  258. skey := serviceKey{
  259. id: svcID,
  260. ports: portConfigs(ingressPorts).String(),
  261. }
  262. c.Lock()
  263. s, ok := c.serviceBindings[skey]
  264. c.Unlock()
  265. if !ok {
  266. logrus.Warnf("rmServiceBinding %s %s %s aborted c.serviceBindings[skey] !ok", method, svcName, eID)
  267. return nil
  268. }
  269. s.Lock()
  270. defer s.Unlock()
  271. logrus.Debugf("rmServiceBinding from %s START for %s %s p:%p nid:%s sKey:%v deleteSvc:%t", method, svcName, eID, s, nID, skey, deleteSvcRecords)
  272. lb, ok := s.loadBalancers[nID]
  273. if !ok {
  274. logrus.Warnf("rmServiceBinding %s %s %s aborted s.loadBalancers[nid] !ok", method, svcName, eID)
  275. return nil
  276. }
  277. _, ok = lb.backEnds[eID]
  278. if !ok {
  279. logrus.Warnf("rmServiceBinding %s %s %s aborted lb.backEnds[eid] !ok", method, svcName, eID)
  280. return nil
  281. }
  282. delete(lb.backEnds, eID)
  283. if len(lb.backEnds) == 0 {
  284. // All the backends for this service have been
  285. // removed. Time to remove the load balancer and also
  286. // remove the service entry in IPVS.
  287. rmService = true
  288. delete(s.loadBalancers, nID)
  289. logrus.Debugf("rmServiceBinding %s delete %s, p:%p in loadbalancers len:%d", eID, nID, lb, len(s.loadBalancers))
  290. }
  291. ok, entries := s.removeIPToEndpoint(ip.String(), eID)
  292. if !ok || entries > 0 {
  293. setStr, b := s.printIPToEndpoint(ip.String())
  294. logrus.Warnf("rmServiceBinding %s possible transient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr[:maxSetStringLen])
  295. }
  296. // Remove loadbalancer service(if needed) and backend in all
  297. // sandboxes in the network only if the vip is valid.
  298. if len(vip) != 0 && entries == 0 {
  299. n.(*network).rmLBBackend(ip, vip, lb, ingressPorts, rmService)
  300. }
  301. // Delete the name resolutions
  302. if deleteSvcRecords {
  303. c.deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, rmService, entries > 0, "rmServiceBinding")
  304. }
  305. if len(s.loadBalancers) == 0 {
  306. // All loadbalancers for the service removed. Time to
  307. // remove the service itself.
  308. c.Lock()
  309. // Mark the object as deleted so that the add won't use it wrongly
  310. s.deleted = true
  311. // NOTE The delete from the serviceBindings map has to be the last operation else we are allowing a race between this service
  312. // that is getting deleted and a new service that will be created if the entry is not anymore there
  313. delete(c.serviceBindings, skey)
  314. c.Unlock()
  315. }
  316. logrus.Debugf("rmServiceBinding from %s END for %s %s", method, svcName, eID)
  317. return nil
  318. }