From 14ff14ea4fe5b1b43788ce63cd68080c86125bc8 Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Tue, 2 Mar 2021 16:14:53 -0800 Subject: [PATCH 1/4] automatically start/upgrade buildkitd - Automatically start a buildkit daemon if no BUILDKIT_HOST is provided (and if not already started) - Customization of BUILDKIT_HOST is still possible, just like before - Automatically upgrade the managed daemon to the version used by dagger if necessary - Add CI test to make sure the managed buildkit and the vendored buildkit versions match Signed-off-by: Andrea Luzzardi --- .github/workflows/ci.yml | 4 - Makefile | 9 +- README.md | 10 +-- dagger/client.go | 12 +-- pkg/buildkitd/buildkitd.go | 168 +++++++++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 19 deletions(-) create mode 100644 pkg/buildkitd/buildkitd.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83bf1b22..ec259108 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,10 +35,6 @@ jobs: run: | make lint - - name: Start buildkit - run: | - docker run -d --name buildkitd --privileged moby/buildkit:v0.8.2 - - name: Integration test run: | make integration diff --git a/Makefile b/Makefile index d2889dc0..6929bc5f 100644 --- a/Makefile +++ b/Makefile @@ -19,10 +19,17 @@ cuefmt: @(cue fmt -s ./examples/*) .PHONY: lint -lint: cuefmt +lint: cuefmt check-buildkit-version golangci-lint run @test -z "$$(git status -s . | grep -e "^ M" | grep .cue | cut -d ' ' -f3 | tee /dev/stderr)" +.PHONY: check-buildkit-version +check-buildkit-version: + @test \ + "$(shell grep buildkit ./go.mod | cut -d' ' -f2)" = \ + "$(shell grep ' = "v' ./pkg/buildkitd/buildkitd.go | sed -E 's/^.*version.*=.*\"(v.*)\"/\1/' )" \ + || { echo buildkit version mismatch go.mod != pkg/buildkitd/buildkitd.go ; exit 1; } + .PHONY: integration integration: dagger-debug # Self-diagnostics diff --git a/README.md b/README.md index 461eef0e..b0c7e794 100644 --- a/README.md +++ b/README.md @@ -74,15 +74,7 @@ $ make $ cp ./cmd/dagger/dagger /usr/local/bin ``` -3. Run [buildkitd](https://github.com/moby/buildkit) on your local machine. The simplest way to do this is using [Docker](https://docker.com): `docker run -d --name buildkitd --privileged moby/buildkit:latest` - -On a machine with Docker installed, run: - -``` -$ docker run -d --name buildkitd --privileged moby/buildkit:latest -``` - -4. Compute a test configuration +3. Compute a test configuration Currently `dagger` can only do one thing: compute a configuration with optional inputs, and print the result. diff --git a/dagger/client.go b/dagger/client.go index 28006019..f5d38cd1 100644 --- a/dagger/client.go +++ b/dagger/client.go @@ -22,15 +22,12 @@ import ( bkgw "github.com/moby/buildkit/frontend/gateway/client" // docker output + "dagger.io/go/pkg/buildkitd" "dagger.io/go/pkg/progressui" "dagger.io/go/dagger/compiler" ) -const ( - defaultBuildkitHost = "docker-container://buildkitd" -) - // A dagger client type Client struct { c *bk.Client @@ -41,7 +38,12 @@ func NewClient(ctx context.Context, host string) (*Client, error) { host = os.Getenv("BUILDKIT_HOST") } if host == "" { - host = defaultBuildkitHost + h, err := buildkitd.Start(ctx) + if err != nil { + return nil, err + } + + host = h } c, err := bk.New(ctx, host) if err != nil { diff --git a/pkg/buildkitd/buildkitd.go b/pkg/buildkitd/buildkitd.go new file mode 100644 index 00000000..1a5cf901 --- /dev/null +++ b/pkg/buildkitd/buildkitd.go @@ -0,0 +1,168 @@ +package buildkitd + +import ( + "context" + "fmt" + "os/exec" + "strings" + + "github.com/docker/distribution/reference" + "github.com/rs/zerolog/log" +) + +const ( + image = "moby/buildkit" + version = "v0.8.2" + imageVersion = image + ":" + version + containerName = "dagger-buildkitd" +) + +func Start(ctx context.Context) (string, error) { + lg := log.Ctx(ctx) + + // Attempt to detect the current buildkit version + currentVersion, err := getBuildkitVersion(ctx) + if err != nil { + // If that failed, it might either be because buildkitd is not running + // or because the docker CLI is out of service. + if err := checkDocker(ctx); err != nil { + return "", err + } + + currentVersion = "" + lg.Debug().Msg("no buildkit daemon detected") + } else { + lg.Debug().Str("version", currentVersion).Msg("detected buildkit version") + } + + if currentVersion != version { + if currentVersion != "" { + lg. + Info(). + Str("version", version). + Msg("upgrading buildkit") + if err := remvoveBuildkit(ctx); err != nil { + return "", err + } + } else { + lg. + Info(). + Str("version", version). + Msg("starting buildkit") + } + if err := startBuildkit(ctx); err != nil { + return "", err + } + } + + return fmt.Sprintf("docker-container://%s", containerName), nil +} + +// ensure the docker CLI is available and properly set up (e.g. permissions to +// communicate with the daemon, etc) +func checkDocker(ctx context.Context) error { + cmd := exec.CommandContext(ctx, "docker", "info") + output, err := cmd.CombinedOutput() + if err != nil { + log. + Ctx(ctx). + Error(). + Err(err). + Bytes("output", output). + Msg("failed to run docker") + return err + } + + return nil +} + +func startBuildkit(ctx context.Context) error { + lg := log. + Ctx(ctx). + With(). + Str("version", version). + Logger() + + lg.Debug().Msg("pulling buildkit image") + cmd := exec.CommandContext(ctx, + "docker", + "pull", + imageVersion, + ) + output, err := cmd.CombinedOutput() + if err != nil { + lg. + Error(). + Err(err). + Bytes("output", output). + Msg("failed to pull buildkit image") + return err + } + + cmd = exec.CommandContext(ctx, + "docker", + "run", + "-d", + "--restart", "always", + "--name", containerName, + "--privileged", + imageVersion, + ) + output, err = cmd.CombinedOutput() + if err != nil { + log. + Ctx(ctx). + Error(). + Err(err). + Bytes("output", output). + Msg("unable to start buildkitd") + return err + } + return nil +} + +func remvoveBuildkit(ctx context.Context) error { + lg := log. + Ctx(ctx) + + cmd := exec.CommandContext(ctx, + "docker", + "rm", + "-fv", + containerName, + ) + output, err := cmd.CombinedOutput() + if err != nil { + lg. + Error(). + Err(err). + Bytes("output", output). + Msg("failed to stop buildkit") + return err + } + + return nil +} + +func getBuildkitVersion(ctx context.Context) (string, error) { + cmd := exec.CommandContext(ctx, + "docker", + "inspect", + "--format", + "{{.Config.Image}}", + containerName, + ) + output, err := cmd.CombinedOutput() + if err != nil { + return "", err + } + ref, err := reference.ParseNormalizedNamed(strings.TrimSpace(string(output))) + if err != nil { + return "", err + } + tag, ok := ref.(reference.Tagged) + if !ok { + return "", fmt.Errorf("failed to parse image: %s", output) + } + return tag.Tag(), nil +} From 8e9a432cafa93a2838e59d32a7494c3d911c2c3e Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Tue, 2 Mar 2021 18:53:15 -0800 Subject: [PATCH 2/4] buildkitd: store state persistently in a volume Signed-off-by: Andrea Luzzardi --- pkg/buildkitd/buildkitd.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/buildkitd/buildkitd.go b/pkg/buildkitd/buildkitd.go index 1a5cf901..7900762f 100644 --- a/pkg/buildkitd/buildkitd.go +++ b/pkg/buildkitd/buildkitd.go @@ -15,6 +15,7 @@ const ( version = "v0.8.2" imageVersion = image + ":" + version containerName = "dagger-buildkitd" + volumeName = "dagger-buildkitd" ) func Start(ctx context.Context) (string, error) { @@ -104,6 +105,7 @@ func startBuildkit(ctx context.Context) error { "run", "-d", "--restart", "always", + "-v", volumeName+":/var/lib/buildkit", "--name", containerName, "--privileged", imageVersion, From 14f535655d39847a85d0193559c9c0010357ba77 Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Tue, 2 Mar 2021 18:59:07 -0800 Subject: [PATCH 3/4] ci: ensure cue version is consistent Signed-off-by: Andrea Luzzardi --- .github/workflows/ci.yml | 2 +- Makefile | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec259108..4ca14d41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: sudo apt-get update sudo apt-get install -y --no-install-recommends shellcheck curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sudo sh -s -- -b /usr/local/bin v1.23.8 - curl -L https://github.com/cuelang/cue/releases/download/v0.3.0-beta.4/cue_0.3.0-beta.4_Linux_x86_64.tar.gz | sudo tar zxf - -C /usr/local/bin + curl -L https://github.com/cuelang/cue/releases/download/v0.3.0-beta.5/cue_0.3.0-beta.5_Linux_x86_64.tar.gz | sudo tar zxf - -C /usr/local/bin - name: Check out uses: actions/checkout@v2 diff --git a/Makefile b/Makefile index 6929bc5f..ba2c989d 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ cuefmt: @(cue fmt -s ./examples/*) .PHONY: lint -lint: cuefmt check-buildkit-version +lint: cuefmt check-buildkit-version check-cue-version golangci-lint run @test -z "$$(git status -s . | grep -e "^ M" | grep .cue | cut -d ' ' -f3 | tee /dev/stderr)" @@ -30,9 +30,16 @@ check-buildkit-version: "$(shell grep ' = "v' ./pkg/buildkitd/buildkitd.go | sed -E 's/^.*version.*=.*\"(v.*)\"/\1/' )" \ || { echo buildkit version mismatch go.mod != pkg/buildkitd/buildkitd.go ; exit 1; } +.PHONY: check-cue-version +check-cue-version: + @grep -q "$(shell grep cue ./go.mod | cut -d' ' -f2)" .github/workflows/ci.yml \ + || { echo cue version mismatch go.mod != .github/workflows/ci.yml ; exit 1; } + + .PHONY: integration integration: dagger-debug # Self-diagnostics ./tests/test-test.sh 2>/dev/null # Actual integration tests DAGGER_BINARY="./cmd/dagger/dagger-debug" time ./tests/test.sh all + From 408053f09269b961f4077b5c09cd7cdbeb3bc972 Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Tue, 2 Mar 2021 19:06:49 -0800 Subject: [PATCH 4/4] ci: use cue version from go.mod Signed-off-by: Andrea Luzzardi --- .github/workflows/ci.yml | 13 +++++++++---- Makefile | 8 +------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ca14d41..f1b11b9f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,16 +17,21 @@ jobs: go-version: 1.16 id: go + - name: Check out + uses: actions/checkout@v2 + - name: Install Dependencies run: | sudo apt-get update sudo apt-get install -y --no-install-recommends shellcheck + + export CUE_VERSION="$(grep cue ./go.mod | cut -d' ' -f2)" + export CUE_TARBALL="cue_$(echo "$CUE_VERSION" | sed 's/^v//')_Linux_x86_64.tar.gz" + + echo "Installing cue version $CUE_VERSION" curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sudo sh -s -- -b /usr/local/bin v1.23.8 - curl -L https://github.com/cuelang/cue/releases/download/v0.3.0-beta.5/cue_0.3.0-beta.5_Linux_x86_64.tar.gz | sudo tar zxf - -C /usr/local/bin - - - name: Check out - uses: actions/checkout@v2 + curl -L https://github.com/cuelang/cue/releases/download/${CUE_VERSION}/${CUE_TARBALL} | sudo tar zxf - -C /usr/local/bin - name: Build run: | make diff --git a/Makefile b/Makefile index ba2c989d..efc5b1f6 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ cuefmt: @(cue fmt -s ./examples/*) .PHONY: lint -lint: cuefmt check-buildkit-version check-cue-version +lint: cuefmt check-buildkit-version golangci-lint run @test -z "$$(git status -s . | grep -e "^ M" | grep .cue | cut -d ' ' -f3 | tee /dev/stderr)" @@ -30,12 +30,6 @@ check-buildkit-version: "$(shell grep ' = "v' ./pkg/buildkitd/buildkitd.go | sed -E 's/^.*version.*=.*\"(v.*)\"/\1/' )" \ || { echo buildkit version mismatch go.mod != pkg/buildkitd/buildkitd.go ; exit 1; } -.PHONY: check-cue-version -check-cue-version: - @grep -q "$(shell grep cue ./go.mod | cut -d' ' -f2)" .github/workflows/ci.yml \ - || { echo cue version mismatch go.mod != .github/workflows/ci.yml ; exit 1; } - - .PHONY: integration integration: dagger-debug # Self-diagnostics