From 258d12b2e72e47eeb57af99f78ee25aae234ac9a Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Tue, 13 Jul 2021 18:09:30 +0200 Subject: [PATCH] Keep BuildKit state in a volume Signed-off-by: CrazyMax --- commands/rm.go | 39 +++++++-------------------- commands/stop.go | 45 ++++++++++++++++++++++++++++--- docs/reference/buildx_rm.md | 14 ++++++++++ driver/docker-container/driver.go | 28 ++++++++++++++----- driver/docker/driver.go | 2 +- driver/driver.go | 2 +- driver/kubernetes/driver.go | 2 +- 7 files changed, 90 insertions(+), 42 deletions(-) diff --git a/commands/rm.go b/commands/rm.go index 37c0fc3a8abf..b09b99e39a11 100644 --- a/commands/rm.go +++ b/commands/rm.go @@ -11,7 +11,8 @@ import ( ) type rmOptions struct { - builder string + builder string + keepState bool } func runRm(dockerCli command.Cli, in rmOptions) error { @@ -28,7 +29,7 @@ func runRm(dockerCli command.Cli, in rmOptions) error { if err != nil { return err } - err1 := stop(ctx, dockerCli, ng, true) + err1 := rm(ctx, dockerCli, ng, in.keepState) if err := txn.Remove(ng.Name); err != nil { return err } @@ -40,7 +41,7 @@ func runRm(dockerCli command.Cli, in rmOptions) error { return err } if ng != nil { - err1 := stop(ctx, dockerCli, ng, true) + err1 := rm(ctx, dockerCli, ng, in.keepState) if err := txn.Remove(ng.Name); err != nil { return err } @@ -66,10 +67,13 @@ func rmCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command { }, } + flags := cmd.Flags() + flags.BoolVar(&options.keepState, "keep-state", false, "Keep BuildKit state") + return cmd } -func stop(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, rm bool) error { +func rm(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, keepState bool) error { dis, err := driversForNodeGroup(ctx, dockerCli, ng, "") if err != nil { return err @@ -79,34 +83,9 @@ func stop(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, rm bo if err := di.Driver.Stop(ctx, true); err != nil { return err } - if rm { - if err := di.Driver.Rm(ctx, true); err != nil { - return err - } - } - } - if di.Err != nil { - err = di.Err - } - } - return err -} - -func stopCurrent(ctx context.Context, dockerCli command.Cli, rm bool) error { - dis, err := getDefaultDrivers(ctx, dockerCli, false, "") - if err != nil { - return err - } - for _, di := range dis { - if di.Driver != nil { - if err := di.Driver.Stop(ctx, true); err != nil { + if err := di.Driver.Rm(ctx, true, !keepState); err != nil { return err } - if rm { - if err := di.Driver.Rm(ctx, true); err != nil { - return err - } - } } if di.Err != nil { err = di.Err diff --git a/commands/stop.go b/commands/stop.go index 7126869695a3..2f1efc674f0c 100644 --- a/commands/stop.go +++ b/commands/stop.go @@ -1,6 +1,9 @@ package commands import ( + "context" + + "github.com/docker/buildx/store" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/moby/buildkit/util/appcontext" @@ -25,7 +28,7 @@ func runStop(dockerCli command.Cli, in stopOptions) error { if err != nil { return err } - if err := stop(ctx, dockerCli, ng, false); err != nil { + if err := stop(ctx, dockerCli, ng); err != nil { return err } return nil @@ -36,10 +39,10 @@ func runStop(dockerCli command.Cli, in stopOptions) error { return err } if ng != nil { - return stop(ctx, dockerCli, ng, false) + return stop(ctx, dockerCli, ng) } - return stopCurrent(ctx, dockerCli, false) + return stopCurrent(ctx, dockerCli) } func stopCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command { @@ -66,3 +69,39 @@ func stopCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command { return cmd } + +func stop(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup) error { + dis, err := driversForNodeGroup(ctx, dockerCli, ng, "") + if err != nil { + return err + } + for _, di := range dis { + if di.Driver != nil { + if err := di.Driver.Stop(ctx, true); err != nil { + return err + } + } + if di.Err != nil { + err = di.Err + } + } + return err +} + +func stopCurrent(ctx context.Context, dockerCli command.Cli) error { + dis, err := getDefaultDrivers(ctx, dockerCli, false, "") + if err != nil { + return err + } + for _, di := range dis { + if di.Driver != nil { + if err := di.Driver.Stop(ctx, true); err != nil { + return err + } + } + if di.Err != nil { + err = di.Err + } + } + return err +} diff --git a/docs/reference/buildx_rm.md b/docs/reference/buildx_rm.md index 12456b3010bc..f846eb2a98bb 100644 --- a/docs/reference/buildx_rm.md +++ b/docs/reference/buildx_rm.md @@ -7,6 +7,13 @@ docker buildx rm [NAME] Remove a builder instance +### Options + +| Name | Description | +| --- | --- | +| `--builder string` | Override the configured builder instance | +| [`--keep-state`](#keep-state) | Keep BuildKit state | + @@ -14,3 +21,10 @@ Remove a builder instance Removes the specified or current builder. It is a no-op attempting to remove the default builder. + +## Examples + +### Keep BuildKit state (--keep-state) + +Keep BuildKit state, so it can be reused by a new builder with the same name. +Currently, only supported by the [`docker-container` driver](buildx_create.md#driver). diff --git a/driver/docker-container/driver.go b/driver/docker-container/driver.go index a2e475e92b1b..a0b261d722f6 100644 --- a/driver/docker-container/driver.go +++ b/driver/docker-container/driver.go @@ -17,14 +17,18 @@ import ( "github.com/docker/docker/api/types" dockertypes "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/network" dockerclient "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" "github.com/moby/buildkit/client" + "github.com/moby/buildkit/util/appdefaults" "github.com/moby/buildkit/util/tracing/detect" "github.com/pkg/errors" ) +const volumeStateSuffix = "_state" + type Driver struct { driver.InitConfig factory driver.Factory @@ -103,6 +107,13 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error { hc := &container.HostConfig{ Privileged: true, UsernsMode: "host", + Mounts: []mount.Mount{ + { + Type: mount.TypeVolume, + Source: d.Name + volumeStateSuffix, + Target: appdefaults.Root, + }, + }, } if d.netMode != "" { hc.NetworkMode = container.NetworkMode(d.netMode) @@ -226,7 +237,7 @@ func (d *Driver) start(ctx context.Context, l progress.SubLogger) error { } func (d *Driver) Info(ctx context.Context) (*driver.Info, error) { - container, err := d.DockerAPI.ContainerInspect(ctx, d.Name) + ctn, err := d.DockerAPI.ContainerInspect(ctx, d.Name) if err != nil { if dockerclient.IsErrNotFound(err) { return &driver.Info{ @@ -236,7 +247,7 @@ func (d *Driver) Info(ctx context.Context) (*driver.Info, error) { return nil, err } - if container.State.Running { + if ctn.State.Running { return &driver.Info{ Status: driver.Running, }, nil @@ -258,16 +269,21 @@ func (d *Driver) Stop(ctx context.Context, force bool) error { return nil } -func (d *Driver) Rm(ctx context.Context, force bool) error { +func (d *Driver) Rm(ctx context.Context, force bool, rmVolume bool) error { info, err := d.Info(ctx) if err != nil { return err } if info.Status != driver.Inactive { - return d.DockerAPI.ContainerRemove(ctx, d.Name, dockertypes.ContainerRemoveOptions{ + if err := d.DockerAPI.ContainerRemove(ctx, d.Name, dockertypes.ContainerRemoveOptions{ RemoveVolumes: true, - Force: true, - }) + Force: force, + }); err != nil { + return err + } + if rmVolume { + return d.DockerAPI.VolumeRemove(ctx, d.Name+volumeStateSuffix, false) + } } return nil } diff --git a/driver/docker/driver.go b/driver/docker/driver.go index 8c896797a651..af94f093a8d4 100644 --- a/driver/docker/driver.go +++ b/driver/docker/driver.go @@ -33,7 +33,7 @@ func (d *Driver) Stop(ctx context.Context, force bool) error { return nil } -func (d *Driver) Rm(ctx context.Context, force bool) error { +func (d *Driver) Rm(ctx context.Context, force bool, rmVolume bool) error { return nil } diff --git a/driver/driver.go b/driver/driver.go index c9ed229f90b2..74006755ddea 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -54,7 +54,7 @@ type Driver interface { Bootstrap(context.Context, progress.Logger) error Info(context.Context) (*Info, error) Stop(ctx context.Context, force bool) error - Rm(ctx context.Context, force bool) error + Rm(ctx context.Context, force bool, rmVolume bool) error Client(ctx context.Context) (*client.Client, error) Features() map[Feature]bool IsMobyDriver() bool diff --git a/driver/kubernetes/driver.go b/driver/kubernetes/driver.go index fc0bdff0942d..b80069fe1c46 100644 --- a/driver/kubernetes/driver.go +++ b/driver/kubernetes/driver.go @@ -143,7 +143,7 @@ func (d *Driver) Stop(ctx context.Context, force bool) error { return nil } -func (d *Driver) Rm(ctx context.Context, force bool) error { +func (d *Driver) Rm(ctx context.Context, force bool, rmVolume bool) error { if err := d.deploymentClient.Delete(ctx, d.deployment.Name, metav1.DeleteOptions{}); err != nil { return errors.Wrapf(err, "error while calling deploymentClient.Delete for %q", d.deployment.Name) }