Skip to content

Commit a8a7dbe

Browse files
committed
gateway: compress frontend input payloads
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
1 parent 80fe7f0 commit a8a7dbe

3 files changed

Lines changed: 80 additions & 2 deletions

File tree

frontend/dockerfile/dockerfile_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@ import (
1919
"runtime"
2020
"slices"
2121
"strings"
22+
"sync/atomic"
2223
"testing"
2324
"time"
2425

2526
cacheimporttypes "github.com/moby/buildkit/cache/remotecache/v1/types"
2627
"github.com/tonistiigi/fsutil"
2728
"golang.org/x/sync/errgroup"
29+
"google.golang.org/grpc"
30+
grpcgzip "google.golang.org/grpc/encoding/gzip"
2831
"google.golang.org/grpc/status"
2932
"google.golang.org/protobuf/proto"
3033
"google.golang.org/protobuf/types/known/anypb"
@@ -44,6 +47,7 @@ import (
4447
"github.com/moby/buildkit/frontend/dockerfile/builder"
4548
"github.com/moby/buildkit/frontend/dockerui"
4649
gateway "github.com/moby/buildkit/frontend/gateway/client"
50+
gatewayapi "github.com/moby/buildkit/frontend/gateway/pb"
4751
"github.com/moby/buildkit/frontend/subrequests"
4852
"github.com/moby/buildkit/identity"
4953
"github.com/moby/buildkit/session"
@@ -141,6 +145,7 @@ var allTests = integration.TestFuncs(
141145
testFrontendUseForwardedSolveResults,
142146
testFrontendEvaluate,
143147
testFrontendInputs,
148+
testFrontendInputsCompressed,
144149
testErrorsSourceMap,
145150
testMultiArgs,
146151
testFrontendSubrequests,
@@ -7340,6 +7345,72 @@ COPY foo foo2
73407345
require.Equal(t, expected, actual)
73417346
}
73427347

7348+
type inputsCompressionInterceptor struct {
7349+
calls atomic.Int64
7350+
compressed atomic.Bool
7351+
}
7352+
7353+
func (i *inputsCompressionInterceptor) unary(ctx context.Context, method string, req any, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
7354+
if method == gatewayapi.LLBBridge_Inputs_FullMethodName {
7355+
i.calls.Add(1)
7356+
for _, opt := range opts {
7357+
if compressor, ok := opt.(grpc.CompressorCallOption); ok && compressor.CompressorType == grpcgzip.Name {
7358+
i.compressed.Store(true)
7359+
}
7360+
}
7361+
}
7362+
return invoker(ctx, method, req, reply, cc, opts...)
7363+
}
7364+
7365+
func testFrontendInputsCompressed(t *testing.T, sb integration.Sandbox) {
7366+
integration.SkipOnPlatform(t, "windows")
7367+
f := getFrontend(t, sb)
7368+
if _, ok := f.(*clientFrontend); !ok {
7369+
t.Skip("only test with client frontend")
7370+
}
7371+
7372+
inputsInterceptor := &inputsCompressionInterceptor{}
7373+
c, err := client.New(sb.Context(), sb.Address(), client.WithGRPCDialOption(grpc.WithChainUnaryInterceptor(inputsInterceptor.unary)))
7374+
require.NoError(t, err)
7375+
defer c.Close()
7376+
7377+
payload := bytes.Repeat([]byte("a"), 64<<10)
7378+
input := llb.Scratch().File(llb.Mkfile("/payload", 0600, payload))
7379+
7380+
destDir := t.TempDir()
7381+
dockerfile := []byte(`
7382+
FROM scratch
7383+
COPY payload payload
7384+
`)
7385+
dir := integration.Tmpdir(
7386+
t,
7387+
fstest.CreateFile("Dockerfile", dockerfile, 0600),
7388+
)
7389+
7390+
_, err = f.Solve(sb.Context(), c, client.SolveOpt{
7391+
Exports: []client.ExportEntry{
7392+
{
7393+
Type: client.ExporterLocal,
7394+
OutputDir: destDir,
7395+
},
7396+
},
7397+
LocalMounts: map[string]fsutil.FS{
7398+
dockerui.DefaultLocalNameDockerfile: dir,
7399+
},
7400+
FrontendInputs: map[string]llb.State{
7401+
dockerui.DefaultLocalNameContext: input,
7402+
},
7403+
}, nil)
7404+
require.NoError(t, err)
7405+
7406+
actual, err := os.ReadFile(filepath.Join(destDir, "payload"))
7407+
require.NoError(t, err)
7408+
require.Equal(t, payload, actual)
7409+
7410+
require.NotZero(t, inputsInterceptor.calls.Load(), "expected an Inputs request")
7411+
require.True(t, inputsInterceptor.compressed.Load(), "expected Inputs request to use gzip compression")
7412+
}
7413+
73437414
func testFrontendSubrequests(t *testing.T, sb integration.Sandbox) {
73447415
f := getFrontend(t, sb)
73457416
if _, ok := f.(*clientFrontend); !ok {

frontend/gateway/gateway.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import (
5757
spb "google.golang.org/genproto/googleapis/rpc/status"
5858
"google.golang.org/grpc"
5959
"google.golang.org/grpc/codes"
60+
_ "google.golang.org/grpc/encoding/gzip" // register gzip compressor for gateway RPC responses
6061
"google.golang.org/grpc/health"
6162
"google.golang.org/grpc/health/grpc_health_v1"
6263
"google.golang.org/grpc/status"

frontend/gateway/grpcclient/client.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"google.golang.org/grpc"
3636
"google.golang.org/grpc/codes"
3737
"google.golang.org/grpc/credentials/insecure"
38+
"google.golang.org/grpc/encoding/gzip"
3839
"google.golang.org/grpc/status"
3940
)
4041

@@ -412,7 +413,12 @@ func (c *grpcClient) Solve(ctx context.Context, creq client.SolveRequest) (res *
412413
}
413414
}
414415

415-
resp, err := c.client.Solve(ctx, req)
416+
var opts []grpc.CallOption
417+
if len(req.FrontendInputs) > 0 {
418+
opts = append(opts, grpc.UseCompressor(gzip.Name))
419+
}
420+
421+
resp, err := c.client.Solve(ctx, req, opts...)
416422
if err != nil {
417423
return nil, err
418424
}
@@ -800,7 +806,7 @@ func (c *grpcClient) Inputs(ctx context.Context) (map[string]llb.State, error) {
800806
return nil, err
801807
}
802808

803-
resp, err := c.client.Inputs(ctx, &pb.InputsRequest{})
809+
resp, err := c.client.Inputs(ctx, &pb.InputsRequest{}, grpc.UseCompressor(gzip.Name))
804810
if err != nil {
805811
return nil, err
806812
}

0 commit comments

Comments
 (0)