Skip to content

Commit 5fdad00

Browse files
committed
buildctl: add example/build-using-dockerfile
This command mimics `docker build` CLI flags so that Docker users can more easily get started with BuildKit. Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
1 parent 5fa37d1 commit 5fdad00

File tree

2 files changed

+199
-7
lines changed

2 files changed

+199
-7
lines changed

README.md

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,57 @@ Key features:
2727

2828
Read the proposal from https://github.com/moby/moby/issues/32925
2929

30-
#### Quick start
30+
#### Quick start for Docker users in 5 steps
3131

32-
Dependencies:
33-
- [runc](https://github.com/opencontainers/runc)
34-
- [containerd](https://github.com/containerd/containerd) (if you want to use containerd worker)
32+
1. Install [runc](https://github.com/opencontainers/runc)
3533

36-
37-
The following command installs `buildd` and `buildctl` to `/usr/local/bin`:
34+
2. Install BuildKit and the `build-using-dockerfile` example to `/usr/local/bin`:
3835

3936
```bash
4037
$ make && sudo make install
38+
$ go build ./examples/build-using-dockerfile && sudo install build-using-dockerfile /usr/local/bin
39+
```
40+
41+
3. Start the BuildKit daemon `buildd`:
42+
```bash
43+
$ sudo buildd
44+
```
45+
46+
4. Build your Dockerfile with the `build-using-dockerfile` example.
47+
48+
```bash
49+
$ cd your-docker-app
50+
$ ls
51+
Dockerfile
52+
...
53+
$ sudo build-using-dockerfile .
54+
$ ls
55+
Dockerfile
56+
oci.tar
57+
...
58+
```
59+
60+
You can omit `sudo` if the user can access `/run/buildkit/buildd.sock`.
61+
62+
5. Import the build artifact `oci.tar` to Docker:
63+
64+
If you use [skopeo](https://github.com/projectatomic/skopeo):
65+
```bash
66+
$ skopeo copy oci-archive:oci.tar docker-daemon:foo/bar:latest
4167
```
4268

43-
You can also use `make binaries-all` to prepare `buildd-containerd` (containerd worker only) and `buildd-standalone` (OCI worker only).
69+
------------------------------
70+
71+
## Advanced guide
72+
73+
#### Installation and usage
74+
75+
Dependencies:
76+
- [runc](https://github.com/opencontainers/runc)
77+
- [containerd](https://github.com/containerd/containerd) (if you want to use containerd worker)
78+
79+
80+
In addition to `make`, you can also use `make binaries-all` to prepare `buildd-containerd` (containerd worker only) and `buildd-standalone` (OCI worker only).
4481

4582
`examples/buildkit*` directory contains scripts that define how to build different configurations of BuildKit and its dependencies using the `client` package. Running one of these script generates a protobuf definition of a build graph. Note that the script itself does not execute any steps of the build.
4683

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
10+
"github.com/containerd/console"
11+
"github.com/moby/buildkit/client"
12+
"github.com/moby/buildkit/util/appcontext"
13+
"github.com/moby/buildkit/util/appdefaults"
14+
"github.com/moby/buildkit/util/progress/progressui"
15+
"github.com/pkg/errors"
16+
"github.com/urfave/cli"
17+
"golang.org/x/sync/errgroup"
18+
)
19+
20+
func main() {
21+
app := cli.NewApp()
22+
app.Name = "build-using-dockerfile"
23+
app.UsageText = `build-using-dockerfile [OPTIONS] PATH | URL | -`
24+
app.Description = `
25+
build using Dockerfile.
26+
27+
This command mimics behavior of "docker build" command so that people can easily get started with BuildKit.
28+
This command is NOT the replacement of "docker build", and should NOT be used for building production images.
29+
30+
By default, the built image is exported as a tar archive with OCI Image Layout ("./oci.tar").
31+
32+
You can import oci.tar to Docker as follows:
33+
34+
$ skopeo copy oci-archive:oci.tar docker-daemon:foo/bar:latest
35+
`
36+
// TODO: call `docker load` rather than creating a file
37+
exporterOptDefault := cli.StringSlice([]string{"output=./oci.tar"})
38+
dockerIncompatibleFlags := []cli.Flag{
39+
cli.StringFlag{
40+
Name: "buildkit-exporter",
41+
Usage: "Define exporter for build result",
42+
Value: "oci", // TODO: docker v1 exporter (unless moby supports OCI importer)
43+
},
44+
cli.StringSliceFlag{
45+
Name: "buildkit-exporter-opt",
46+
Usage: "Define custom options for exporter",
47+
Value: &exporterOptDefault,
48+
},
49+
cli.StringFlag{
50+
Name: "buildkit-addr",
51+
Usage: "listening address",
52+
EnvVar: "BUILDKIT_HOST",
53+
Value: appdefaults.Address,
54+
},
55+
}
56+
app.Flags = append([]cli.Flag{
57+
cli.StringFlag{
58+
Name: "file, f",
59+
Usage: "Name of the Dockerfile (Default is 'PATH/Dockerfile')",
60+
},
61+
cli.StringFlag{
62+
Name: "target",
63+
Usage: "Set the target build stage to build.",
64+
},
65+
cli.StringSliceFlag{
66+
Name: "build-arg",
67+
Usage: "Set build-time variables",
68+
},
69+
}, dockerIncompatibleFlags...)
70+
app.Action = action
71+
if err := app.Run(os.Args); err != nil {
72+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
73+
os.Exit(1)
74+
}
75+
}
76+
77+
func action(clicontext *cli.Context) error {
78+
c, err := client.New(clicontext.GlobalString("buildkit-addr"), client.WithBlock())
79+
if err != nil {
80+
return err
81+
}
82+
solveOpt, err := newSolveOpt(clicontext)
83+
if err != nil {
84+
return err
85+
}
86+
ch := make(chan *client.SolveStatus)
87+
eg, ctx := errgroup.WithContext(appcontext.Context())
88+
eg.Go(func() error {
89+
return c.Solve(ctx, nil, *solveOpt, ch)
90+
})
91+
eg.Go(func() error {
92+
if c, err := console.ConsoleFromFile(os.Stderr); err == nil {
93+
// not using shared context to not disrupt display but let is finish reporting errors
94+
return progressui.DisplaySolveStatus(context.TODO(), c, ch)
95+
}
96+
return nil
97+
})
98+
return eg.Wait()
99+
}
100+
101+
func newSolveOpt(clicontext *cli.Context) (*client.SolveOpt, error) {
102+
buildCtx := clicontext.Args().First()
103+
if buildCtx == "" {
104+
return nil, errors.New("please specify build context (e.g. \".\" for the current directory)")
105+
} else if buildCtx == "-" {
106+
return nil, errors.New("stdin not supported yet")
107+
}
108+
109+
file := clicontext.String("file")
110+
if file == "" {
111+
file = filepath.Join(buildCtx, "Dockerfile")
112+
}
113+
exporterAttrs, err := attrMap(clicontext.StringSlice("buildkit-exporter-opt"))
114+
if err != nil {
115+
return nil, errors.Wrap(err, "invalid buildkit-exporter-opt")
116+
}
117+
118+
localDirs := map[string]string{
119+
"context": buildCtx,
120+
"dockerfile": filepath.Dir(file),
121+
}
122+
123+
frontendAttrs := map[string]string{
124+
"filename": filepath.Base(file),
125+
}
126+
if target := clicontext.String("target"); target != "" {
127+
frontendAttrs["target"] = target
128+
}
129+
buildArgs, err := attrMap(clicontext.StringSlice("build-arg"))
130+
if err != nil {
131+
return nil, err
132+
}
133+
for k, v := range buildArgs {
134+
frontendAttrs["build-arg:"+k] = v
135+
}
136+
return &client.SolveOpt{
137+
Exporter: clicontext.String("buildkit-exporter"),
138+
ExporterAttrs: exporterAttrs,
139+
LocalDirs: localDirs,
140+
Frontend: "dockerfile.v0", // TODO: use gateway
141+
FrontendAttrs: frontendAttrs,
142+
}, nil
143+
}
144+
145+
func attrMap(sl []string) (map[string]string, error) {
146+
m := map[string]string{}
147+
for _, v := range sl {
148+
parts := strings.SplitN(v, "=", 2)
149+
if len(parts) != 2 {
150+
return nil, errors.Errorf("invalid value %s", v)
151+
}
152+
m[parts[0]] = parts[1]
153+
}
154+
return m, nil
155+
}

0 commit comments

Comments
 (0)