Skip to content

Commit b63f4d6

Browse files
committed
Add --pull option to build command
Signed-off-by: David Son <[email protected]>
1 parent a5e8b64 commit b63f4d6

File tree

5 files changed

+112
-0
lines changed

5 files changed

+112
-0
lines changed

cmd/nerdctl/builder_build.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ If Dockerfile is not present and -f is not specified, it will look for Container
5151
buildCommand.Flags().StringP("output", "o", "", "Output destination (format: type=local,dest=path)")
5252
buildCommand.Flags().String("progress", "auto", "Set type of progress output (auto, plain, tty). Use plain to show container output")
5353
buildCommand.Flags().String("provenance", "", "Shorthand for \"--attest=type=provenance\"")
54+
buildCommand.Flags().Bool("pull", false, "On true, always attempt to pull latest image version from remote. Default uses buildkit's default.")
5455
buildCommand.Flags().StringArray("secret", nil, "Secret file to expose to the build: id=mysecret,src=/local/secret")
5556
buildCommand.Flags().StringArray("allow", nil, "Allow extra privileged entitlement, e.g. network.host, security.insecure")
5657
buildCommand.RegisterFlagCompletionFunc("allow", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
@@ -133,6 +134,14 @@ func processBuildCommandFlag(cmd *cobra.Command, args []string) (types.BuilderBu
133134
if err != nil {
134135
return types.BuilderBuildOptions{}, err
135136
}
137+
var pull *bool
138+
if cmd.Flags().Changed("pull") {
139+
pullFlag, err := cmd.Flags().GetBool("pull")
140+
if err != nil {
141+
return types.BuilderBuildOptions{}, err
142+
}
143+
pull = &pullFlag
144+
}
136145
secret, err := cmd.Flags().GetStringArray("secret")
137146
if err != nil {
138147
return types.BuilderBuildOptions{}, err
@@ -205,6 +214,7 @@ func processBuildCommandFlag(cmd *cobra.Command, args []string) (types.BuilderBu
205214
BuildArgs: buildArgs,
206215
Label: label,
207216
NoCache: noCache,
217+
Pull: pull,
208218
Secret: secret,
209219
Allow: allow,
210220
Attest: attest,

cmd/nerdctl/builder_linux_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ package main
1919
import (
2020
"bytes"
2121
"fmt"
22+
"os"
23+
"os/exec"
24+
"path/filepath"
2225
"testing"
2326

2427
"github.com/containerd/nerdctl/v2/pkg/testutil"
28+
"gotest.tools/v3/assert"
2529
)
2630

2731
func TestBuilderDebug(t *testing.T) {
@@ -36,3 +40,89 @@ CMD ["echo", "nerdctl-builder-debug-test-string"]
3640

3741
base.Cmd("builder", "debug", buildCtx).CmdOption(testutil.WithStdin(bytes.NewReader([]byte("c\n")))).AssertOK()
3842
}
43+
44+
func TestBuildWithPull(t *testing.T) {
45+
testutil.DockerIncompatible(t)
46+
testutil.RequiresBuild(t)
47+
48+
oldImage := testutil.BusyboxImage
49+
oldImageSha := "141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47"
50+
newImage := testutil.AlpineImage
51+
52+
buildkitConfig := fmt.Sprintf(`[worker.oci]
53+
enabled = false
54+
55+
[worker.containerd]
56+
enabled = true
57+
namespace = "%s"`, testutil.Namespace)
58+
59+
cleanup := useBuildkitConfig(t, buildkitConfig)
60+
defer cleanup()
61+
62+
testCases := []struct {
63+
name string
64+
pull string
65+
}{
66+
{
67+
name: "build with local image",
68+
pull: "false",
69+
},
70+
{
71+
name: "build with newest image",
72+
pull: "true",
73+
},
74+
{
75+
name: "build with buildkit default",
76+
// buildkit default pulls from remote
77+
pull: "default",
78+
},
79+
}
80+
81+
for _, tc := range testCases {
82+
tc := tc
83+
t.Run(tc.name, func(t *testing.T) {
84+
base := testutil.NewBase(t)
85+
defer base.Cmd("builder", "prune").AssertOK()
86+
base.Cmd("image", "prune", "--force", "--all").AssertOK()
87+
88+
base.Cmd("pull", oldImage).Run()
89+
base.Cmd("tag", oldImage, newImage).Run()
90+
91+
dockerfile := fmt.Sprintf(`FROM %s`, newImage)
92+
tmpDir := t.TempDir()
93+
err := os.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644)
94+
assert.NilError(t, err)
95+
96+
buildCtx := createBuildContext(t, dockerfile)
97+
98+
buildCmd := []string{"build", buildCtx}
99+
switch tc.pull {
100+
case "false":
101+
buildCmd = append(buildCmd, "--pull=false")
102+
base.Cmd(buildCmd...).AssertErrContains(oldImageSha)
103+
case "true":
104+
buildCmd = append(buildCmd, "--pull=true")
105+
base.Cmd(buildCmd...).AssertErrNotContains(oldImageSha)
106+
case "default":
107+
base.Cmd(buildCmd...).AssertErrNotContains(oldImageSha)
108+
}
109+
})
110+
}
111+
}
112+
113+
func useBuildkitConfig(t *testing.T, config string) (cleanup func()) {
114+
buildkitConfigPath := "/etc/buildkit/buildkitd.toml"
115+
116+
currConfig, err := exec.Command("cat", buildkitConfigPath).Output()
117+
assert.NilError(t, err)
118+
119+
os.WriteFile(buildkitConfigPath, []byte(config), 0644)
120+
_, err = exec.Command("systemctl", "restart", "buildkit").Output()
121+
assert.NilError(t, err)
122+
123+
return func() {
124+
assert.NilError(t, os.WriteFile(buildkitConfigPath, currConfig, 0644))
125+
_, err = exec.Command("systemctl", "restart", "buildkit").Output()
126+
assert.NilError(t, err)
127+
}
128+
}

docs/command-reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ Flags:
692692
- :whale: `type=image,name=example.com/image,push=true`: Push to a registry (see [`buildctl build`](https://github.com/moby/buildkit/tree/v0.9.0#imageregistry) documentation)
693693
- :whale: `--progress=(auto|plain|tty)`: Set type of progress output (auto, plain, tty). Use plain to show container output
694694
- :whale: `--provenance`: Shorthand for \"--attest=type=provenance\", see [`buildx_build.md`](https://github.com/docker/buildx/blob/v0.12.1/docs/reference/buildx_build.md#provenance) documentation
695+
- :whale: `--pull=(true|false)`: On true, always attempt to pull latest image version from remote. Default uses buildkit's default.
695696
- :whale: `--secret`: Secret file to expose to the build: id=mysecret,src=/local/secret
696697
- :whale: `--allow`: Allow extra privileged entitlement, e.g. network.host, security.insecure (It’s required to configure the buildkitd to enable the feature, see [`buildkitd.toml`](https://github.com/moby/buildkit/blob/master/docs/buildkitd.toml.md) documentation)
697698
- :whale: `--attest`: Attestation parameters (format: "type=sbom,generator=image"), see [`buildx_build.md`](https://github.com/docker/buildx/blob/v0.12.1/docs/reference/buildx_build.md#attest) documentation

pkg/api/types/builder_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ type BuilderBuildOptions struct {
6969
ExtendedBuildContext []string
7070
// NetworkMode mode for the build context
7171
NetworkMode string
72+
// Pull determines if we should try to pull latest image from remote. Default is buildkit's default.
73+
Pull *bool
7274
}
7375

7476
// BuilderPruneOptions specifies options for `nerdctl builder prune`.

pkg/cmd/builder/build.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,15 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
367367
buildctlArgs = append(buildctlArgs, "--no-cache")
368368
}
369369

370+
if options.Pull != nil {
371+
switch *options.Pull {
372+
case true:
373+
buildctlArgs = append(buildctlArgs, "--opt=image-resolve-mode=pull")
374+
case false:
375+
buildctlArgs = append(buildctlArgs, "--opt=image-resolve-mode=local")
376+
}
377+
}
378+
370379
for _, s := range strutil.DedupeStrSlice(options.Secret) {
371380
buildctlArgs = append(buildctlArgs, "--secret="+s)
372381
}

0 commit comments

Comments
 (0)