Skip to content

Commit 0228437

Browse files
authored
Merge pull request docker#10756 from milas/network-race
up: fix race condition on network connect
2 parents 3906a7a + 10b290e commit 0228437

File tree

4 files changed

+170
-156
lines changed

4 files changed

+170
-156
lines changed

pkg/compose/convergence.go

Lines changed: 31 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import (
2929
"github.com/containerd/containerd/platforms"
3030
moby "github.com/docker/docker/api/types"
3131
containerType "github.com/docker/docker/api/types/container"
32-
"github.com/docker/docker/api/types/network"
3332
specs "github.com/opencontainers/image-spec/specs-go/v1"
3433
"github.com/pkg/errors"
3534
"github.com/sirupsen/logrus"
@@ -233,7 +232,13 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
233232
name := getContainerName(project.Name, service, number)
234233
i := i
235234
eg.Go(func() error {
236-
container, err := c.service.createContainer(ctx, project, service, name, number, false, true, false)
235+
opts := createOptions{
236+
AutoRemove: false,
237+
AttachStdin: false,
238+
UseNetworkAliases: true,
239+
Labels: mergeLabels(service.Labels, service.CustomLabels),
240+
}
241+
container, err := c.service.createContainer(ctx, project, service, name, number, opts)
237242
updated[actual+i] = container
238243
return err
239244
})
@@ -399,12 +404,11 @@ func getScale(config types.ServiceConfig) (int, error) {
399404
}
400405

401406
func (s *composeService) createContainer(ctx context.Context, project *types.Project, service types.ServiceConfig,
402-
name string, number int, autoRemove bool, useNetworkAliases bool, attachStdin bool) (container moby.Container, err error) {
407+
name string, number int, opts createOptions) (container moby.Container, err error) {
403408
w := progress.ContextWriter(ctx)
404409
eventName := "Container " + name
405410
w.Event(progress.CreatingEvent(eventName))
406-
container, err = s.createMobyContainer(ctx, project, service, name, number, nil,
407-
autoRemove, useNetworkAliases, attachStdin, w, mergeLabels(service.Labels, service.CustomLabels))
411+
container, err = s.createMobyContainer(ctx, project, service, name, number, nil, opts, w)
408412
if err != nil {
409413
return
410414
}
@@ -429,9 +433,13 @@ func (s *composeService) recreateContainer(ctx context.Context, project *types.P
429433
}
430434
name := getContainerName(project.Name, service, number)
431435
tmpName := fmt.Sprintf("%s_%s", replaced.ID[:12], name)
432-
created, err = s.createMobyContainer(ctx, project, service, tmpName, number, inherited,
433-
false, true, false, w,
434-
mergeLabels(service.Labels, service.CustomLabels).Add(api.ContainerReplaceLabel, replaced.ID))
436+
opts := createOptions{
437+
AutoRemove: false,
438+
AttachStdin: false,
439+
UseNetworkAliases: true,
440+
Labels: mergeLabels(service.Labels, service.CustomLabels).Add(api.ContainerReplaceLabel, replaced.ID),
441+
}
442+
created, err = s.createMobyContainer(ctx, project, service, tmpName, number, inherited, opts, w)
435443
if err != nil {
436444
return created, err
437445
}
@@ -484,19 +492,18 @@ func (s *composeService) startContainer(ctx context.Context, container moby.Cont
484492
return nil
485493
}
486494

487-
func (s *composeService) createMobyContainer(ctx context.Context, //nolint:gocyclo
495+
func (s *composeService) createMobyContainer(ctx context.Context,
488496
project *types.Project,
489497
service types.ServiceConfig,
490498
name string,
491499
number int,
492500
inherit *moby.Container,
493-
autoRemove, useNetworkAliases, attachStdin bool,
501+
opts createOptions,
494502
w progress.Writer,
495-
labels types.Labels,
496503
) (moby.Container, error) {
497504
var created moby.Container
498-
containerConfig, hostConfig, networkingConfig, err := s.getCreateOptions(ctx, project, service, number, inherit,
499-
autoRemove, attachStdin, labels)
505+
cfgs, err := s.getCreateConfigs(ctx, project, service, number, inherit, opts)
506+
500507
if err != nil {
501508
return created, err
502509
}
@@ -514,18 +521,7 @@ func (s *composeService) createMobyContainer(ctx context.Context, //nolint:gocyc
514521
plat = &p
515522
}
516523

517-
links, err := s.getLinks(ctx, project.Name, service, number)
518-
if err != nil {
519-
return created, err
520-
}
521-
if networkingConfig != nil {
522-
for k, s := range networkingConfig.EndpointsConfig {
523-
s.Links = links
524-
networkingConfig.EndpointsConfig[k] = s
525-
}
526-
}
527-
528-
response, err := s.apiClient().ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, plat, name)
524+
response, err := s.apiClient().ContainerCreate(ctx, cfgs.Container, cfgs.Host, cfgs.Network, plat, name)
529525
if err != nil {
530526
return created, err
531527
}
@@ -548,29 +544,19 @@ func (s *composeService) createMobyContainer(ctx context.Context, //nolint:gocyc
548544
Networks: inspectedContainer.NetworkSettings.Networks,
549545
},
550546
}
551-
for _, netName := range service.NetworksByPriority() {
552-
netwrk := project.Networks[netName]
553-
cfg := service.Networks[netName]
554-
aliases := []string{getContainerName(project.Name, service, number)}
555-
if useNetworkAliases {
556-
aliases = append(aliases, service.Name)
557-
if cfg != nil {
558-
aliases = append(aliases, cfg.Aliases...)
559-
}
560-
}
561-
if val, ok := created.NetworkSettings.Networks[netwrk.Name]; ok {
562-
if shortIDAliasExists(created.ID, val.Aliases...) {
563-
continue
564-
}
565-
err = s.apiClient().NetworkDisconnect(ctx, netwrk.Name, created.ID, false)
566-
if err != nil {
547+
548+
// the highest-priority network is the primary and is included in the ContainerCreate API
549+
// call via container.NetworkMode & network.NetworkingConfig
550+
// any remaining networks are connected one-by-one here after creation (but before start)
551+
serviceNetworks := service.NetworksByPriority()
552+
if len(serviceNetworks) > 1 {
553+
for _, networkKey := range serviceNetworks[1:] {
554+
mobyNetworkName := project.Networks[networkKey].Name
555+
epSettings := createEndpointSettings(project, service, number, networkKey, cfgs.Links, opts.UseNetworkAliases)
556+
if err := s.apiClient().NetworkConnect(ctx, mobyNetworkName, created.ID, epSettings); err != nil {
567557
return created, err
568558
}
569559
}
570-
err = s.connectContainerToNetwork(ctx, created.ID, netwrk.Name, cfg, links, aliases...)
571-
if err != nil {
572-
return created, err
573-
}
574560
}
575561

576562
err = s.injectSecrets(ctx, project, service, created.ID)
@@ -635,43 +621,6 @@ func (s *composeService) getLinks(ctx context.Context, projectName string, servi
635621
return links, nil
636622
}
637623

638-
func shortIDAliasExists(containerID string, aliases ...string) bool {
639-
for _, alias := range aliases {
640-
if alias == containerID[:12] {
641-
return true
642-
}
643-
}
644-
return false
645-
}
646-
647-
func (s *composeService) connectContainerToNetwork(ctx context.Context, id string, netwrk string, cfg *types.ServiceNetworkConfig, links []string, aliases ...string) error {
648-
var (
649-
ipv4Address string
650-
ipv6Address string
651-
ipam *network.EndpointIPAMConfig
652-
)
653-
if cfg != nil {
654-
ipv4Address = cfg.Ipv4Address
655-
ipv6Address = cfg.Ipv6Address
656-
ipam = &network.EndpointIPAMConfig{
657-
IPv4Address: ipv4Address,
658-
IPv6Address: ipv6Address,
659-
LinkLocalIPs: cfg.LinkLocalIPs,
660-
}
661-
}
662-
err := s.apiClient().NetworkConnect(ctx, netwrk, id, &network.EndpointSettings{
663-
Aliases: aliases,
664-
IPAddress: ipv4Address,
665-
GlobalIPv6Address: ipv6Address,
666-
Links: links,
667-
IPAMConfig: ipam,
668-
})
669-
if err != nil {
670-
return err
671-
}
672-
return nil
673-
}
674-
675624
func (s *composeService) isServiceHealthy(ctx context.Context, containers Containers, fallbackRunning bool) (bool, error) {
676625
for _, c := range containers {
677626
container, err := s.apiClient().ContainerInspect(ctx, c.ID)

0 commit comments

Comments
 (0)