Add --metadata-file flag to output build metadata
Signed-off-by: Jesse Rittner <rittneje@gmail.com>v0.9
parent
3e808950fc
commit
0406194498
14
README.md
14
README.md
|
@ -374,6 +374,20 @@ consider client-side load balancing using consistent hashing.
|
|||
|
||||
See [`./examples/kubernetes/consistenthash`](./examples/kubernetes/consistenthash).
|
||||
|
||||
## Metadata
|
||||
|
||||
To output build metadata such as the image digest, pass the `--metadata-file` flag.
|
||||
The metadata will be written as a JSON object to the specified file.
|
||||
The directory of the specified file must already exist and be writable.
|
||||
|
||||
```
|
||||
buildctl build ... --metadata-file metadata.json
|
||||
```
|
||||
|
||||
```
|
||||
{"containerimage.digest": "sha256:ea0cfb27fd41ea0405d3095880c1efa45710f5bcdddb7d7d5a7317ad4825ae14",...}
|
||||
```
|
||||
|
||||
## Systemd socket activation
|
||||
|
||||
On Systemd based systems, you can communicate with the daemon via [Systemd socket activation](http://0pointer.de/blog/projects/socket-activation.html), use `buildkitd --addr fd://`.
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/containerd/continuity"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/client/llb"
|
||||
"github.com/moby/buildkit/cmd/buildctl/build"
|
||||
|
@ -101,6 +102,10 @@ var buildCommand = cli.Command{
|
|||
Name: "ssh",
|
||||
Usage: "Allow forwarding SSH agent to the builder. Format default|<id>[=<socket>|<key>[,<key>]]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "metadata-file",
|
||||
Usage: "Output build metadata (e.g., image digest) to a file as JSON",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -290,7 +295,15 @@ func buildAction(clicontext *cli.Context) error {
|
|||
for k, v := range resp.ExporterResponse {
|
||||
logrus.Debugf("exporter response: %s=%s", k, v)
|
||||
}
|
||||
return err
|
||||
|
||||
metadataFile := clicontext.String("metadata-file")
|
||||
if metadataFile != "" && resp.ExporterResponse != nil {
|
||||
if err := writeMetadataFile(metadataFile, resp.ExporterResponse); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
eg.Go(func() error {
|
||||
|
@ -300,3 +313,11 @@ func buildAction(clicontext *cli.Context) error {
|
|||
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
func writeMetadataFile(filename string, exporterResponse map[string]string) error {
|
||||
b, err := json.Marshal(exporterResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return continuity.AtomicWriteFile(filename, b, 0666)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -111,6 +112,61 @@ func testBuildContainerdExporter(t *testing.T, sb integration.Sandbox) {
|
|||
require.Equal(t, ok, true)
|
||||
}
|
||||
|
||||
func testBuildMetadataFile(t *testing.T, sb integration.Sandbox) {
|
||||
st := llb.Image("busybox").
|
||||
Run(llb.Shlex("sh -c 'echo -n bar > /foo'"))
|
||||
|
||||
rdr, err := marshal(st.Root())
|
||||
require.NoError(t, err)
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "buildkit-buildctl")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
imageName := "example.com/moby/metadata:test"
|
||||
metadataFile := filepath.Join(tmpDir, "metadata.json")
|
||||
|
||||
buildCmd := []string{
|
||||
"build", "--progress=plain",
|
||||
"--output type=image,name=" + imageName + ",push=false",
|
||||
"--metadata-file", metadataFile,
|
||||
}
|
||||
|
||||
cmd := sb.Cmd(strings.Join(buildCmd, " "))
|
||||
cmd.Stdin = rdr
|
||||
err = cmd.Run()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.FileExists(t, metadataFile)
|
||||
metadataBytes, err := ioutil.ReadFile(metadataFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
var metadata map[string]string
|
||||
err = json.Unmarshal(metadataBytes, &metadata)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, imageName, metadata["image.name"])
|
||||
|
||||
digest := metadata["containerimage.digest"]
|
||||
require.NotEmpty(t, digest)
|
||||
|
||||
cdAddress := sb.ContainerdAddress()
|
||||
if cdAddress == "" {
|
||||
t.Log("no containerd worker, skipping digest verification")
|
||||
} else {
|
||||
client, err := containerd.New(cdAddress, containerd.WithTimeout(60*time.Second))
|
||||
require.NoError(t, err)
|
||||
defer client.Close()
|
||||
|
||||
ctx := namespaces.WithNamespace(context.Background(), "buildkit")
|
||||
|
||||
img, err := client.GetImage(ctx, imageName)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, img.Metadata().Target.Digest.String(), digest)
|
||||
}
|
||||
}
|
||||
|
||||
func marshal(st llb.State) (io.Reader, error) {
|
||||
def, err := st.Marshal(context.TODO())
|
||||
if err != nil {
|
||||
|
|
|
@ -18,6 +18,7 @@ func TestCLIIntegration(t *testing.T) {
|
|||
testBuildWithLocalFiles,
|
||||
testBuildLocalExporter,
|
||||
testBuildContainerdExporter,
|
||||
testBuildMetadataFile,
|
||||
testPrune,
|
||||
testUsage,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue