mirror of
https://github.com/docker/cli.git
synced 2026-01-13 18:22:35 +03:00
Merge pull request #6195 from thaJeztah/build_no_dct
build: remove DCT support for classic builder
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
@@ -20,9 +18,7 @@ import (
|
||||
"github.com/docker/cli/cli/command/completion"
|
||||
"github.com/docker/cli/cli/command/image/build"
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/cli/cli/trust"
|
||||
"github.com/docker/cli/internal/jsonstream"
|
||||
"github.com/docker/cli/internal/lazyregexp"
|
||||
"github.com/docker/cli/opts"
|
||||
buildtypes "github.com/docker/docker/api/types/build"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
@@ -65,7 +61,6 @@ type buildOptions struct {
|
||||
target string
|
||||
imageIDFile string
|
||||
platform string
|
||||
untrusted bool
|
||||
}
|
||||
|
||||
// dockerfileFromStdin returns true when the user specified that the Dockerfile
|
||||
@@ -144,7 +139,8 @@ func NewBuildCommand(dockerCli command.Cli) *cobra.Command {
|
||||
flags.SetAnnotation("target", annotation.ExternalURL, []string{"https://docs.docker.com/reference/cli/docker/buildx/build/#target"})
|
||||
flags.StringVar(&options.imageIDFile, "iidfile", "", "Write the image ID to the file")
|
||||
|
||||
command.AddTrustVerificationFlags(flags, &options.untrusted, dockerCli.ContentTrustEnabled())
|
||||
flags.Bool("disable-content-trust", dockerCli.ContentTrustEnabled(), "Skip image verification (deprecated)")
|
||||
_ = flags.MarkHidden("disable-content-trust")
|
||||
|
||||
flags.StringVar(&options.platform, "platform", os.Getenv("DOCKER_DEFAULT_PLATFORM"), "Set platform if server is multi-platform capable")
|
||||
flags.SetAnnotation("platform", "version", []string{"1.38"})
|
||||
@@ -286,26 +282,6 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
var resolvedTags []*resolvedTag
|
||||
if !options.untrusted {
|
||||
translator := func(ctx context.Context, ref reference.NamedTagged) (reference.Canonical, error) {
|
||||
return TrustedReference(ctx, dockerCli, ref)
|
||||
}
|
||||
// if there is a tar wrapper, the dockerfile needs to be replaced inside it
|
||||
if buildCtx != nil {
|
||||
// Wrap the tar archive to replace the Dockerfile entry with the rewritten
|
||||
// Dockerfile which uses trusted pulls.
|
||||
buildCtx = replaceDockerfileForContentTrust(ctx, buildCtx, relDockerfile, translator, &resolvedTags)
|
||||
} else if dockerfileCtx != nil {
|
||||
// if there was not archive context still do the possible replacements in Dockerfile
|
||||
newDockerfile, _, err := rewriteDockerfileFromForContentTrust(ctx, dockerfileCtx, translator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dockerfileCtx = io.NopCloser(bytes.NewBuffer(newDockerfile))
|
||||
}
|
||||
}
|
||||
|
||||
if options.compress {
|
||||
buildCtx, err = build.Compress(buildCtx)
|
||||
if err != nil {
|
||||
@@ -402,21 +378,10 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !options.untrusted {
|
||||
// Since the build was successful, now we must tag any of the resolved
|
||||
// images from the above Dockerfile rewrite.
|
||||
for _, resolved := range resolvedTags {
|
||||
if err := trust.TagTrusted(ctx, dockerCli.Client(), dockerCli.Err(), resolved.digestRef, resolved.tagRef); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type translatorFunc func(context.Context, reference.NamedTagged) (reference.Canonical, error)
|
||||
|
||||
// validateTag checks if the given image name can be resolved.
|
||||
func validateTag(rawRepo string) (string, error) {
|
||||
_, err := reference.ParseNormalizedNamed(rawRepo)
|
||||
@@ -427,118 +392,6 @@ func validateTag(rawRepo string) (string, error) {
|
||||
return rawRepo, nil
|
||||
}
|
||||
|
||||
var dockerfileFromLinePattern = lazyregexp.New(`(?i)^[\s]*FROM[ \f\r\t\v]+(?P<image>[^ \f\r\t\v\n#]+)`)
|
||||
|
||||
// resolvedTag records the repository, tag, and resolved digest reference
|
||||
// from a Dockerfile rewrite.
|
||||
type resolvedTag struct {
|
||||
digestRef reference.Canonical
|
||||
tagRef reference.NamedTagged
|
||||
}
|
||||
|
||||
// noBaseImageSpecifier is the symbol used by the FROM
|
||||
// command to specify that no base image is to be used.
|
||||
const noBaseImageSpecifier = "scratch"
|
||||
|
||||
// rewriteDockerfileFromForContentTrust rewrites the given Dockerfile by resolving images in
|
||||
// "FROM <image>" instructions to a digest reference. `translator` is a
|
||||
// function that takes a repository name and tag reference and returns a
|
||||
// trusted digest reference.
|
||||
// This should be called *only* when content trust is enabled
|
||||
func rewriteDockerfileFromForContentTrust(ctx context.Context, dockerfile io.Reader, translator translatorFunc) (newDockerfile []byte, resolvedTags []*resolvedTag, err error) {
|
||||
scanner := bufio.NewScanner(dockerfile)
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
// Scan the lines of the Dockerfile, looking for a "FROM" line.
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
matches := dockerfileFromLinePattern.FindStringSubmatch(line)
|
||||
if matches != nil && matches[1] != noBaseImageSpecifier {
|
||||
// Replace the line with a resolved "FROM repo@digest"
|
||||
var ref reference.Named
|
||||
ref, err = reference.ParseNormalizedNamed(matches[1])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ref = reference.TagNameOnly(ref)
|
||||
if ref, ok := ref.(reference.NamedTagged); ok {
|
||||
trustedRef, err := translator(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, "FROM "+reference.FamiliarString(trustedRef))
|
||||
resolvedTags = append(resolvedTags, &resolvedTag{
|
||||
digestRef: trustedRef,
|
||||
tagRef: ref,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_, err := fmt.Fprintln(buf, line)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return buf.Bytes(), resolvedTags, scanner.Err()
|
||||
}
|
||||
|
||||
// replaceDockerfileForContentTrust wraps the given input tar archive stream and
|
||||
// uses the translator to replace the Dockerfile which uses a trusted reference.
|
||||
// Returns a new tar archive stream with the replaced Dockerfile.
|
||||
func replaceDockerfileForContentTrust(ctx context.Context, inputTarStream io.ReadCloser, dockerfileName string, translator translatorFunc, resolvedTags *[]*resolvedTag) io.ReadCloser {
|
||||
pipeReader, pipeWriter := io.Pipe()
|
||||
go func() {
|
||||
tarReader := tar.NewReader(inputTarStream)
|
||||
tarWriter := tar.NewWriter(pipeWriter)
|
||||
|
||||
defer inputTarStream.Close()
|
||||
|
||||
for {
|
||||
hdr, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
// Signals end of archive.
|
||||
_ = tarWriter.Close()
|
||||
_ = pipeWriter.Close()
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
_ = pipeWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
content := io.Reader(tarReader)
|
||||
if hdr.Name == dockerfileName {
|
||||
// This entry is the Dockerfile. Since the tar archive was
|
||||
// generated from a directory on the local filesystem, the
|
||||
// Dockerfile will only appear once in the archive.
|
||||
var newDockerfile []byte
|
||||
newDockerfile, *resolvedTags, err = rewriteDockerfileFromForContentTrust(ctx, content, translator)
|
||||
if err != nil {
|
||||
_ = pipeWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
hdr.Size = int64(len(newDockerfile))
|
||||
content = bytes.NewBuffer(newDockerfile)
|
||||
}
|
||||
|
||||
if err := tarWriter.WriteHeader(hdr); err != nil {
|
||||
_ = pipeWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := io.Copy(tarWriter, content); err != nil {
|
||||
_ = pipeWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return pipeReader
|
||||
}
|
||||
|
||||
func imageBuildOptions(dockerCli command.Cli, options buildOptions) buildtypes.ImageBuildOptions {
|
||||
configFile := dockerCli.ConfigFile()
|
||||
return buildtypes.ImageBuildOptions{
|
||||
|
||||
@@ -47,7 +47,6 @@ func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
|
||||
options.compress = true
|
||||
options.dockerfileName = "-"
|
||||
options.context = dir.Path()
|
||||
options.untrusted = true
|
||||
assert.NilError(t, runBuild(context.TODO(), cli, options))
|
||||
|
||||
expected := []string{fakeBuild.options.Dockerfile, ".dockerignore", "foo"}
|
||||
@@ -74,7 +73,6 @@ func TestRunBuildResetsUidAndGidInContext(t *testing.T) {
|
||||
|
||||
options := newBuildOptions()
|
||||
options.context = dir.Path()
|
||||
options.untrusted = true
|
||||
assert.NilError(t, runBuild(context.TODO(), cli, options))
|
||||
|
||||
headers := fakeBuild.headers(t)
|
||||
@@ -109,7 +107,6 @@ COPY data /data
|
||||
options := newBuildOptions()
|
||||
options.context = dir.Path()
|
||||
options.dockerfileName = df.Path()
|
||||
options.untrusted = true
|
||||
assert.NilError(t, runBuild(context.TODO(), cli, options))
|
||||
|
||||
expected := []string{fakeBuild.options.Dockerfile, ".dockerignore", "data"}
|
||||
@@ -170,7 +167,6 @@ RUN echo hello world
|
||||
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeBuild.build})
|
||||
options := newBuildOptions()
|
||||
options.context = tmpDir.Join("context-link")
|
||||
options.untrusted = true
|
||||
assert.NilError(t, runBuild(context.TODO(), cli, options))
|
||||
|
||||
assert.DeepEqual(t, fakeBuild.filenames(t), []string{"Dockerfile"})
|
||||
|
||||
@@ -2803,7 +2803,6 @@ _docker_image_build() {
|
||||
"
|
||||
|
||||
local boolean_options="
|
||||
--disable-content-trust=false
|
||||
--force-rm
|
||||
--help
|
||||
--no-cache
|
||||
|
||||
@@ -139,7 +139,6 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l cpu-quota -d
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s c -l cpu-shares -d 'CPU shares (relative weight)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l cpuset-cpus -d 'CPUs in which to allow execution (0-3, 0,1)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l cpuset-mems -d 'MEMs in which to allow execution (0-3, 0,1)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l disable-content-trust -d 'Skip image verification'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s f -l file -d "Name of the Dockerfile (Default is ‘PATH/Dockerfile’)"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l force-rm -d 'Always remove intermediate containers'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l help -d 'Print usage'
|
||||
|
||||
@@ -1005,7 +1005,6 @@ __docker_image_subcommand() {
|
||||
"($help)--cpu-rt-runtime=[Limit the CPU real-time runtime]:CPU real-time runtime in microseconds: " \
|
||||
"($help)--cpuset-cpus=[CPUs in which to allow execution]:CPUs: " \
|
||||
"($help)--cpuset-mems=[MEMs in which to allow execution]:MEMs: " \
|
||||
"($help)--disable-content-trust[Skip image verification]" \
|
||||
"($help -f --file)"{-f=,--file=}"[Name of the Dockerfile]:Dockerfile:_files" \
|
||||
"($help)--force-rm[Always remove intermediate containers]" \
|
||||
"($help)--isolation=[Container isolation technology]:isolation:(default hyperv process)" \
|
||||
|
||||
@@ -21,7 +21,6 @@ Build an image from a Dockerfile
|
||||
| `-c`, `--cpu-shares` | `int64` | `0` | CPU shares (relative weight) |
|
||||
| `--cpuset-cpus` | `string` | | CPUs in which to allow execution (0-3, 0,1) |
|
||||
| `--cpuset-mems` | `string` | | MEMs in which to allow execution (0-3, 0,1) |
|
||||
| `--disable-content-trust` | `bool` | `true` | Skip image verification |
|
||||
| [`-f`](https://docs.docker.com/reference/cli/docker/buildx/build/#file), [`--file`](https://docs.docker.com/reference/cli/docker/buildx/build/#file) | `string` | | Name of the Dockerfile (Default is `PATH/Dockerfile`) |
|
||||
| `--force-rm` | `bool` | | Always remove intermediate containers |
|
||||
| `--iidfile` | `string` | | Write the image ID to the file |
|
||||
|
||||
@@ -21,7 +21,6 @@ Build an image from a Dockerfile
|
||||
| `-c`, `--cpu-shares` | `int64` | `0` | CPU shares (relative weight) |
|
||||
| `--cpuset-cpus` | `string` | | CPUs in which to allow execution (0-3, 0,1) |
|
||||
| `--cpuset-mems` | `string` | | MEMs in which to allow execution (0-3, 0,1) |
|
||||
| `--disable-content-trust` | `bool` | `true` | Skip image verification |
|
||||
| [`-f`](https://docs.docker.com/reference/cli/docker/buildx/build/#file), [`--file`](https://docs.docker.com/reference/cli/docker/buildx/build/#file) | `string` | | Name of the Dockerfile (Default is `PATH/Dockerfile`) |
|
||||
| `--force-rm` | `bool` | | Always remove intermediate containers |
|
||||
| `--iidfile` | `string` | | Write the image ID to the file |
|
||||
|
||||
@@ -21,7 +21,6 @@ Build an image from a Dockerfile
|
||||
| `-c`, `--cpu-shares` | `int64` | `0` | CPU shares (relative weight) |
|
||||
| `--cpuset-cpus` | `string` | | CPUs in which to allow execution (0-3, 0,1) |
|
||||
| `--cpuset-mems` | `string` | | MEMs in which to allow execution (0-3, 0,1) |
|
||||
| `--disable-content-trust` | `bool` | `true` | Skip image verification |
|
||||
| [`-f`](https://docs.docker.com/reference/cli/docker/buildx/build/#file), [`--file`](https://docs.docker.com/reference/cli/docker/buildx/build/#file) | `string` | | Name of the Dockerfile (Default is `PATH/Dockerfile`) |
|
||||
| `--force-rm` | `bool` | | Always remove intermediate containers |
|
||||
| `--iidfile` | `string` | | Write the image ID to the file |
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/fs"
|
||||
"gotest.tools/v3/icmd"
|
||||
"gotest.tools/v3/skip"
|
||||
)
|
||||
|
||||
func TestBuildFromContextDirectoryWithTag(t *testing.T) {
|
||||
@@ -62,68 +61,6 @@ func TestBuildFromContextDirectoryWithTag(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestTrustedBuild(t *testing.T) {
|
||||
skip.If(t, environment.RemoteDaemon())
|
||||
t.Setenv("DOCKER_BUILDKIT", "0")
|
||||
|
||||
dir := fixtures.SetupConfigFile(t)
|
||||
defer dir.Remove()
|
||||
image1 := fixtures.CreateMaskedTrustedRemoteImage(t, registryPrefix, "trust-build1", "latest")
|
||||
image2 := fixtures.CreateMaskedTrustedRemoteImage(t, registryPrefix, "trust-build2", "latest")
|
||||
|
||||
buildDir := fs.NewDir(t, "test-trusted-build-context-dir",
|
||||
fs.WithFile("Dockerfile", fmt.Sprintf(`
|
||||
FROM %s as build-base
|
||||
RUN echo ok > /foo
|
||||
FROM %s
|
||||
COPY --from=build-base foo bar
|
||||
`, image1, image2)))
|
||||
defer buildDir.Remove()
|
||||
|
||||
result := icmd.RunCmd(
|
||||
icmd.Command("docker", "build", "-t", "myimage", "."),
|
||||
withWorkingDir(buildDir),
|
||||
fixtures.WithConfig(dir.Path()),
|
||||
fixtures.WithTrust,
|
||||
fixtures.WithNotary,
|
||||
)
|
||||
|
||||
result.Assert(t, icmd.Expected{
|
||||
Out: fmt.Sprintf("FROM %s@sha", image1[:len(image1)-7]),
|
||||
Err: fmt.Sprintf("Tagging %s@sha", image1[:len(image1)-7]),
|
||||
})
|
||||
result.Assert(t, icmd.Expected{
|
||||
Out: fmt.Sprintf("FROM %s@sha", image2[:len(image2)-7]),
|
||||
})
|
||||
}
|
||||
|
||||
func TestTrustedBuildUntrustedImage(t *testing.T) {
|
||||
skip.If(t, environment.RemoteDaemon())
|
||||
t.Setenv("DOCKER_BUILDKIT", "0")
|
||||
|
||||
dir := fixtures.SetupConfigFile(t)
|
||||
defer dir.Remove()
|
||||
buildDir := fs.NewDir(t, "test-trusted-build-context-dir",
|
||||
fs.WithFile("Dockerfile", fmt.Sprintf(`
|
||||
FROM %s
|
||||
RUN []
|
||||
`, fixtures.AlpineImage)))
|
||||
defer buildDir.Remove()
|
||||
|
||||
result := icmd.RunCmd(
|
||||
icmd.Command("docker", "build", "-t", "myimage", "."),
|
||||
withWorkingDir(buildDir),
|
||||
fixtures.WithConfig(dir.Path()),
|
||||
fixtures.WithTrust,
|
||||
fixtures.WithNotary,
|
||||
)
|
||||
|
||||
result.Assert(t, icmd.Expected{
|
||||
ExitCode: 1,
|
||||
Err: "does not have trust data for",
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuildIidFileSquash(t *testing.T) {
|
||||
environment.SkipIfNotExperimentalDaemon(t)
|
||||
t.Setenv("DOCKER_BUILDKIT", "0")
|
||||
|
||||
Reference in New Issue
Block a user