diff --git a/daemon/cluster/executor/backend.go b/daemon/cluster/executor/backend.go index fba4adec18..fb88613c1d 100644 --- a/daemon/cluster/executor/backend.go +++ b/daemon/cluster/executor/backend.go @@ -27,6 +27,8 @@ type Backend interface { ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error ContainerStop(name string, seconds *int) error ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error + ActivateContainerServiceBinding(containerName string) error + DeactivateContainerServiceBinding(containerName string) error UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error ContainerInspectCurrent(name string, size bool) (*types.ContainerJSON, error) ContainerWaitWithContext(ctx context.Context, name string) error diff --git a/daemon/cluster/executor/container/adapter.go b/daemon/cluster/executor/container/adapter.go index bd5745cc5b..618f4b22b4 100644 --- a/daemon/cluster/executor/container/adapter.go +++ b/daemon/cluster/executor/container/adapter.go @@ -331,6 +331,14 @@ func (c *containerAdapter) createVolumes(ctx context.Context) error { return nil } +func (c *containerAdapter) activateServiceBinding() error { + return c.backend.ActivateContainerServiceBinding(c.container.name()) +} + +func (c *containerAdapter) deactivateServiceBinding() error { + return c.backend.DeactivateContainerServiceBinding(c.container.name()) +} + // todo: typed/wrapped errors func isContainerCreateNameConflict(err error) bool { return strings.Contains(err.Error(), "Conflict. The name") diff --git a/daemon/cluster/executor/container/controller.go b/daemon/cluster/executor/container/controller.go index 7b8ed663e8..0185e415b5 100644 --- a/daemon/cluster/executor/container/controller.go +++ b/daemon/cluster/executor/container/controller.go @@ -183,6 +183,10 @@ func (r *controller) Start(ctx context.Context) error { // no health check if ctnr.Config == nil || ctnr.Config.Healthcheck == nil { + if err := r.adapter.activateServiceBinding(); err != nil { + log.G(ctx).WithError(err).Errorf("failed to activate service binding for container %s which has no healthcheck config", r.adapter.container.name()) + return err + } return nil } @@ -225,6 +229,10 @@ func (r *controller) Start(ctx context.Context) error { // set health check error, and wait for container to fully exit ("die" event) healthErr = ErrContainerUnhealthy case "health_status: healthy": + if err := r.adapter.activateServiceBinding(); err != nil { + log.G(ctx).WithError(err).Errorf("failed to activate service binding for container %s after healthy event", r.adapter.container.name()) + return err + } return nil } case <-ctx.Done(): @@ -290,6 +298,12 @@ func (r *controller) Shutdown(ctx context.Context) error { r.cancelPull() } + // remove container from service binding + if err := r.adapter.deactivateServiceBinding(); err != nil { + log.G(ctx).WithError(err).Errorf("failed to deactivate service binding for container %s", r.adapter.container.name()) + return err + } + if err := r.adapter.shutdown(ctx); err != nil { if isUnknownContainer(err) || isStoppedContainer(err) { return nil diff --git a/daemon/container_operations.go b/daemon/container_operations.go index ca6a377fec..66eb7965f4 100644 --- a/daemon/container_operations.go +++ b/daemon/container_operations.go @@ -719,6 +719,13 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName return err } + if !container.Managed { + // add container name/alias to DNS + if err := daemon.ActivateContainerServiceBinding(container.Name); err != nil { + return fmt.Errorf("Activate container service binding for %s failed: %v", container.Name, err) + } + } + if err := container.UpdateJoinInfo(n, ep); err != nil { return fmt.Errorf("Updating join info failed: %v", err) } @@ -987,3 +994,29 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, netw } return nil } + +// ActivateContainerServiceBinding puts this container into load balancer active rotation and DNS response +func (daemon *Daemon) ActivateContainerServiceBinding(containerName string) error { + container, err := daemon.GetContainer(containerName) + if err != nil { + return err + } + sb := daemon.getNetworkSandbox(container) + if sb == nil { + return fmt.Errorf("network sandbox not exists for container %s", containerName) + } + return sb.EnableService() +} + +// DeactivateContainerServiceBinding remove this container fromload balancer active rotation, and DNS response +func (daemon *Daemon) DeactivateContainerServiceBinding(containerName string) error { + container, err := daemon.GetContainer(containerName) + if err != nil { + return err + } + sb := daemon.getNetworkSandbox(container) + if sb == nil { + return fmt.Errorf("network sandbox not exists for container %s", containerName) + } + return sb.DisableService() +} diff --git a/daemon/network.go b/daemon/network.go index bde0bcdbff..a1ca959a34 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -178,6 +178,10 @@ func (daemon *Daemon) SetupIngress(create clustertypes.NetworkCreateRequest, nod 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