Merge pull request #1554 from docker/poll_completed

fix race condition with init containers
This commit is contained in:
Nicolas De loof 2021-04-22 09:05:33 +02:00 committed by GitHub
commit bce61295ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 57 deletions

2
go.mod
View File

@ -17,7 +17,7 @@ require (
github.com/awslabs/goformation/v4 v4.15.6
github.com/buger/goterm v1.0.0
github.com/cnabio/cnab-to-oci v0.3.1-beta1
github.com/compose-spec/compose-go v0.0.0-20210412113016-e35895260882
github.com/compose-spec/compose-go v0.0.0-20210421142148-66b18e67d2c0
github.com/containerd/console v1.0.1
github.com/containerd/containerd v1.4.3
github.com/containerd/continuity v0.0.0-20200928162600-f2cc35102c2a // indirect

4
go.sum
View File

@ -308,8 +308,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/compose-spec/compose-go v0.0.0-20210412113016-e35895260882 h1:vLKOiHY9QPS1eiBvGfsEI7wR23B1bGNvwOF5aVl25Fs=
github.com/compose-spec/compose-go v0.0.0-20210412113016-e35895260882/go.mod h1:6eIT9U2OgdHmkRD6szmqatCrWWEEUSwl/j2iJYH4jLo=
github.com/compose-spec/compose-go v0.0.0-20210421142148-66b18e67d2c0 h1:aoUSQGFmWi8dn1OfT4H5Mx48u5wHt+n07nLFw5j1JXs=
github.com/compose-spec/compose-go v0.0.0-20210421142148-66b18e67d2c0/go.mod h1:6eIT9U2OgdHmkRD6szmqatCrWWEEUSwl/j2iJYH4jLo=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340 h1:9atoWyI9RtXFwf7UDbme/6M8Ud0rFrx+Q3ZWgSnsxtw=

View File

@ -19,9 +19,7 @@ package compose
import (
"context"
"fmt"
"net/url"
"os"
"path"
"strings"
"github.com/compose-spec/compose-go/types"
@ -50,7 +48,7 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti
if service.Build != nil {
imageName := getImageName(service, project.Name)
imagesToBuild = append(imagesToBuild, imageName)
buildOptions, err := s.toBuildOptions(service, project.WorkingDir, imageName)
buildOptions, err := s.toBuildOptions(service, imageName)
if err != nil {
return err
}
@ -132,7 +130,7 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri
continue
}
imagesToBuild = append(imagesToBuild, imageName)
opt, err := s.toBuildOptions(service, project.WorkingDir, imageName)
opt, err := s.toBuildOptions(service, imageName)
if err != nil {
return nil, nil, err
}
@ -257,13 +255,10 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opts
return imagesBuilt, err
}
func (s *composeService) toBuildOptions(service types.ServiceConfig, contextPath string, imageTag string) (build.Options, error) {
func (s *composeService) toBuildOptions(service types.ServiceConfig, imageTag string) (build.Options, error) {
var tags []string
tags = append(tags, imageTag)
if service.Build.Dockerfile == "" {
service.Build.Dockerfile = "Dockerfile"
}
var buildArgs map[string]string
var plats []specs.Platform
@ -275,22 +270,11 @@ func (s *composeService) toBuildOptions(service types.ServiceConfig, contextPath
plats = append(plats, p)
}
var input build.Inputs
_, err := url.ParseRequestURI(service.Build.Context)
if err == nil {
input = build.Inputs{
return build.Options{
Inputs: build.Inputs{
ContextPath: service.Build.Context,
DockerfilePath: service.Build.Dockerfile,
}
} else {
input = build.Inputs{
ContextPath: path.Join(contextPath, service.Build.Context),
DockerfilePath: path.Join(contextPath, service.Build.Context, service.Build.Dockerfile),
}
}
return build.Options{
Inputs: input,
},
BuildArgs: flatten(mergeArgs(service.Build.Args, buildArgs)),
Tags: tags,
Target: service.Build.Target,

View File

@ -25,10 +25,10 @@ import (
"github.com/compose-spec/compose-go/types"
"github.com/containerd/containerd/platforms"
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
"github.com/docker/compose-cli/api/compose"
@ -147,13 +147,13 @@ func getContainerProgressName(container moby.Container) string {
func (s *composeService) waitDependencies(ctx context.Context, project *types.Project, service types.ServiceConfig) error {
eg, _ := errgroup.WithContext(ctx)
for dep, config := range service.DependsOn {
switch config.Condition {
case "service_healthy":
eg.Go(func() error {
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop()
for {
<-ticker.C
eg.Go(func() error {
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop()
for {
<-ticker.C
switch config.Condition {
case types.ServiceConditionHealthy:
healthy, err := s.isServiceHealthy(ctx, project, dep)
if err != nil {
return err
@ -161,17 +161,26 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
if healthy {
return nil
}
case types.ServiceConditionCompletedSuccessfully:
exited, code, err := s.isServiceCompleted(ctx, project, dep)
if err != nil {
return err
}
if exited {
if code != 0 {
return fmt.Errorf("service %q didn't completed successfully: exit %d", dep, code)
}
return nil
}
case types.ServiceConditionStarted:
// already managed by InDependencyOrder
return nil
default:
logrus.Warnf("unsupported depends_on condition: %s", config.Condition)
return nil
}
})
case "service_completed_successfully":
exit, err := s.waitCompleted(ctx, project, dep)
if err != nil {
return err
}
if exit != 0 {
return fmt.Errorf("service %q didn't completed successfully: exit %d", dep, exit)
}
}
})
}
return eg.Wait()
}
@ -360,26 +369,21 @@ func (s *composeService) isServiceHealthy(ctx context.Context, project *types.Pr
return true, nil
}
func (s *composeService) waitCompleted(ctx context.Context, project *types.Project, dep string) (int64, error) {
containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{
Filters: filters.NewArgs(
projectFilter(project.Name),
serviceFilter(dep),
),
})
func (s *composeService) isServiceCompleted(ctx context.Context, project *types.Project, dep string) (bool, int, error) {
containers, err := s.getContainers(ctx, project.Name, oneOffExclude, true, dep)
if err != nil {
return 0, err
return false, 0, err
}
for _, c := range containers {
wait, errors := s.apiClient.ContainerWait(ctx, c.ID, container.WaitConditionNextExit)
select {
case w := <-wait:
return w.StatusCode, nil
case err := <-errors:
return 0, err
container, err := s.apiClient.ContainerInspect(ctx, c.ID)
if err != nil {
return false, 0, err
}
if container.State != nil && container.State.Status == "exited" {
return true, container.State.ExitCode, nil
}
}
return 0, nil
return false, 0, nil
}
func (s *composeService) startService(ctx context.Context, project *types.Project, service types.ServiceConfig) error {