From 5b0839041b4bc0c04f212b5e1136c0bcbc8bbf3b Mon Sep 17 00:00:00 2001 From: Romain Laurent Date: Thu, 3 Oct 2024 18:16:47 +0200 Subject: [PATCH] feat(ryuk): use an external ryuk --- docker.go | 66 +++++++++++++++++++++++---------------- internal/config/config.go | 11 +++++++ 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/docker.go b/docker.go index 9319c630dd..994a8de7fc 100644 --- a/docker.go +++ b/docker.go @@ -979,6 +979,36 @@ func (p *DockerProvider) BuildImage(ctx context.Context, img ImageBuildInfo) (st return buildOptions.Tags[0], nil } +func (p *DockerProvider) getTermChan(ctx context.Context, sessionID string) (chan bool, error) { + var ( + r *Reaper + err error + ) + + if p.config.RyukDisabled { + return nil, nil + } + + if p.config.RyukExternalAddress != "" { + r = &Reaper{ + Endpoint: p.config.RyukExternalAddress, + SessionID: sessionID, + } + } else { + r, err = reuseOrCreateReaper(context.WithValue(ctx, core.DockerHostContextKey, p.host), core.SessionID(), p) + if err != nil { + return nil, fmt.Errorf("%w: creating reaper failed", err) + } + } + + termSignal, err := r.Connect() + if err != nil { + return nil, fmt.Errorf("%w: connecting to reaper failed", err) + } + + return termSignal, nil +} + // CreateContainer fulfils a request for a container without starting it func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerRequest) (Container, error) { var err error @@ -1026,14 +1056,10 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque var termSignal chan bool // the reaper does not need to start a reaper for itself isReaperContainer := strings.HasSuffix(imageName, config.ReaperDefaultImage) - if !p.config.RyukDisabled && !isReaperContainer { - r, err := reuseOrCreateReaper(context.WithValue(ctx, core.DockerHostContextKey, p.host), core.SessionID(), p) - if err != nil { - return nil, fmt.Errorf("%w: creating reaper failed", err) - } - termSignal, err = r.Connect() + if !isReaperContainer { + termSignal, err = p.getTermChan(ctx, core.SessionID()) if err != nil { - return nil, fmt.Errorf("%w: connecting to reaper failed", err) + return nil, err } } @@ -1277,16 +1303,9 @@ func (p *DockerProvider) ReuseOrCreateContainer(ctx context.Context, req Contain sessionID := core.SessionID() - var termSignal chan bool - if !p.config.RyukDisabled { - r, err := reuseOrCreateReaper(context.WithValue(ctx, core.DockerHostContextKey, p.host), sessionID, p) - if err != nil { - return nil, fmt.Errorf("reaper: %w", err) - } - termSignal, err = r.Connect() - if err != nil { - return nil, fmt.Errorf("%w: connecting to reaper failed", err) - } + termSignal, err := p.getTermChan(ctx, sessionID) + if err != nil { + return nil, err } // default hooks include logger hook and pre-create hook @@ -1483,16 +1502,9 @@ func (p *DockerProvider) CreateNetwork(ctx context.Context, req NetworkRequest) sessionID := core.SessionID() - var termSignal chan bool - if !p.config.RyukDisabled { - r, err := reuseOrCreateReaper(context.WithValue(ctx, core.DockerHostContextKey, p.host), sessionID, p) - if err != nil { - return nil, fmt.Errorf("%w: creating network reaper failed", err) - } - termSignal, err = r.Connect() - if err != nil { - return nil, fmt.Errorf("%w: connecting to network reaper failed", err) - } + termSignal, err := p.getTermChan(ctx, sessionID) + if err != nil { + return nil, err } // add the labels that the reaper will use to terminate the network to the request diff --git a/internal/config/config.go b/internal/config/config.go index a172fa3a16..d68c4ca548 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -60,6 +60,12 @@ type Config struct { // Environment variable: TESTCONTAINERS_RYUK_DISABLED RyukDisabled bool `properties:"ryuk.disabled,default=false"` + // RyukExternalAddress is the address of the external Garbage Collector container. + // If set, Testcontainers will not attempt to start its own Ryuk container. + // + // Environment variable: TESTCONTAINERS_RYUK_EXTERNAL_ADDRESS + RyukExternalAddress string `properties:"ryuk.external.address,default="` + // RyukPrivileged is a flag to enable or disable the privileged mode for the Garbage Collector container. // Setting this to true will run the Garbage Collector container in privileged mode. // @@ -116,6 +122,11 @@ func read() Config { config.RyukDisabled = ryukDisabledEnv == "true" } + ryukExternalAddress := os.Getenv("TESTCONTAINERS_RYUK_EXTERNAL_ADDRESS") + if ryukExternalAddress != "" { + config.RyukExternalAddress = ryukExternalAddress + } + hubImageNamePrefix := os.Getenv("TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX") if hubImageNamePrefix != "" { config.HubImageNamePrefix = hubImageNamePrefix