Build apps with BuildKit so build stages stop piling up (closes #220)
Check / check (pull_request) Skipped
Check / check (pull_request) Skipped
The classic builder left an untagged image for every step of every stage of a multi-stage build. BuildKit keeps stages in Docker's build cache, which Docker keeps under a size limit on its own. BuildKit reports progress as encoded trace messages, so these are decoded with BuildKit's own library and written to the deployment log as plain text. The README notes that engines older than 28.2 need build cache cleanup turned on in daemon.json. Model: opus-5-5
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package docker //nolint:testpackage // tests unexported regexps and Client struct
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
@@ -11,8 +13,10 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
controlapi "github.com/moby/buildkit/api/services/control"
|
||||
)
|
||||
|
||||
// mainBranch is the branch name used across validation tests.
|
||||
@@ -239,3 +243,74 @@ func TestPerformCloneRemovesContainerVolumes(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestPerformBuildUsesBuildKit runs a build against a fake Docker API and
|
||||
// checks that it asks for BuildKit and that BuildKit's progress reaches the
|
||||
// build log as plain text.
|
||||
func TestPerformBuildUsesBuildKit(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Now()
|
||||
status := controlapi.StatusResponse{Vertexes: []*controlapi.Vertex{{
|
||||
Digest: "sha256:1111",
|
||||
Name: "[build 2/2] RUN make",
|
||||
Started: &now,
|
||||
Completed: &now,
|
||||
}}}
|
||||
|
||||
data, err := status.Marshal()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
trace, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.URL.Path, "/build"):
|
||||
if r.URL.Query().Get("version") != "2" {
|
||||
http.Error(w, "not a BuildKit build", http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(w, "{\"id\":\"moby.buildkit.trace\",\"aux\":%s}\n", trace)
|
||||
default:
|
||||
_, _ = w.Write([]byte(`{"Id":"sha256:built"}`))
|
||||
}
|
||||
},
|
||||
))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
dockerAPI, err := client.NewClientWithOpts(
|
||||
client.WithHost("tcp://" + srv.Listener.Addr().String()),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := &Client{docker: dockerAPI, log: slog.Default()}
|
||||
|
||||
var buildLog bytes.Buffer
|
||||
|
||||
imageID, err := c.performBuild(t.Context(), BuildImageOptions{
|
||||
ContextDir: t.TempDir(),
|
||||
Tags: []string{"upaas-test:1"},
|
||||
LogWriter: &buildLog,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if imageID != "sha256:built" {
|
||||
t.Errorf("unexpected image ID %q", imageID)
|
||||
}
|
||||
|
||||
if !strings.Contains(buildLog.String(), "[build 2/2] RUN make") {
|
||||
t.Errorf("build log is missing the build step:\n%s", buildLog.String())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user