service_common.go 12 KB

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