Merge pull request #1739 from tonistiigi/empty-layer
clear file mount stubs and fix empty layer casesv0.8
commit
dda009a58c
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/moby/buildkit/exporter/containerimage/exptypes"
|
||||
"github.com/moby/buildkit/solver"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -238,6 +239,10 @@ func marshalRemote(r *solver.Remote, state *marshalState) string {
|
|||
}
|
||||
desc := r.Descriptors[len(r.Descriptors)-1]
|
||||
|
||||
if desc.Digest == exptypes.EmptyGZLayer {
|
||||
return parentID
|
||||
}
|
||||
|
||||
state.descriptors[desc.Digest] = DescriptorProviderPair{
|
||||
Descriptor: desc,
|
||||
Provider: r.Provider,
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/mount"
|
||||
containerdoci "github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/continuity/fs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
|
@ -106,17 +107,19 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root cache.Moun
|
|||
defer release()
|
||||
}
|
||||
|
||||
var sgids []uint32
|
||||
uid, gid, err := oci.ParseUIDGID(meta.User)
|
||||
if err != nil {
|
||||
lm := snapshot.LocalMounterWithMounts(rootMounts)
|
||||
rootfsPath, err := lm.Mount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lm.Unmount()
|
||||
defer executor.MountStubsCleaner(rootfsPath, mounts)()
|
||||
|
||||
var sgids []uint32
|
||||
uid, gid, err := oci.ParseUIDGID(meta.User)
|
||||
if err != nil {
|
||||
uid, gid, sgids, err = oci.GetUser(rootfsPath, meta.User)
|
||||
if err != nil {
|
||||
lm.Unmount()
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -127,17 +130,13 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root cache.Moun
|
|||
|
||||
newp, err := fs.RootPath(rootfsPath, meta.Cwd)
|
||||
if err != nil {
|
||||
lm.Unmount()
|
||||
return errors.Wrapf(err, "working dir %s points to invalid target", newp)
|
||||
}
|
||||
if _, err := os.Stat(newp); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(newp, 0755, identity); err != nil {
|
||||
lm.Unmount()
|
||||
return errors.Wrapf(err, "failed to create working directory %s", newp)
|
||||
}
|
||||
}
|
||||
|
||||
lm.Unmount()
|
||||
}
|
||||
|
||||
provider, ok := w.networkProviders[meta.NetMode]
|
||||
|
@ -196,7 +195,11 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root cache.Moun
|
|||
cioOpts = append(cioOpts, cio.WithTerminal)
|
||||
}
|
||||
|
||||
task, err := container.NewTask(ctx, cio.NewCreator(cioOpts...), containerd.WithRootFS(rootMounts))
|
||||
task, err := container.NewTask(ctx, cio.NewCreator(cioOpts...), containerd.WithRootFS([]mount.Mount{{
|
||||
Source: rootfsPath,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
}}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -215,6 +215,8 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root cache.Mountable,
|
|||
}
|
||||
defer mount.Unmount(rootFSPath, 0)
|
||||
|
||||
defer executor.MountStubsCleaner(rootFSPath, mounts)()
|
||||
|
||||
uid, gid, sgids, err := oci.GetUser(rootFSPath, meta.User)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package executor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/continuity/fs"
|
||||
)
|
||||
|
||||
func MountStubsCleaner(dir string, mounts []Mount) func() {
|
||||
names := []string{"/etc/resolv.conf", "/etc/hosts"}
|
||||
|
||||
for _, m := range mounts {
|
||||
names = append(names, m.Dest)
|
||||
}
|
||||
|
||||
paths := make([]string, 0, len(names))
|
||||
|
||||
for _, p := range names {
|
||||
p = filepath.Join("/", p)
|
||||
if p == "/" {
|
||||
continue
|
||||
}
|
||||
realPath, err := fs.RootPath(dir, p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = os.Lstat(realPath)
|
||||
if errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) {
|
||||
paths = append(paths, realPath)
|
||||
}
|
||||
}
|
||||
|
||||
return func() {
|
||||
for _, p := range paths {
|
||||
st, err := os.Lstat(p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if st.Size() != 0 {
|
||||
continue
|
||||
}
|
||||
os.Remove(p)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,16 @@
|
|||
package exptypes
|
||||
|
||||
import specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
import (
|
||||
"github.com/opencontainers/go-digest"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
const ExporterImageConfigKey = "containerimage.config"
|
||||
const ExporterInlineCache = "containerimage.inlinecache"
|
||||
const ExporterPlatformsKey = "refs.platforms"
|
||||
|
||||
const EmptyGZLayer = digest.Digest("sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1")
|
||||
|
||||
type Platforms struct {
|
||||
Platforms []Platform
|
||||
}
|
||||
|
|
|
@ -28,10 +28,6 @@ import (
|
|||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
const (
|
||||
emptyGZLayer = digest.Digest("sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1")
|
||||
)
|
||||
|
||||
type WriterOpt struct {
|
||||
Snapshotter snapshot.Snapshotter
|
||||
ContentStore content.Store
|
||||
|
@ -426,13 +422,13 @@ func normalizeLayersAndHistory(remote *solver.Remote, history []ocispec.History,
|
|||
var layerIndex int
|
||||
for i, h := range history {
|
||||
if !h.EmptyLayer {
|
||||
if h.Created == nil {
|
||||
h.Created = refMeta[layerIndex].createdAt
|
||||
}
|
||||
if remote.Descriptors[layerIndex].Digest == emptyGZLayer {
|
||||
if remote.Descriptors[layerIndex].Digest == exptypes.EmptyGZLayer {
|
||||
h.EmptyLayer = true
|
||||
remote.Descriptors = append(remote.Descriptors[:layerIndex], remote.Descriptors[layerIndex+1:]...)
|
||||
} else {
|
||||
if h.Created == nil {
|
||||
h.Created = refMeta[layerIndex].createdAt
|
||||
}
|
||||
layerIndex++
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ func testSecretFileParams(t *testing.T, sb integration.Sandbox) {
|
|||
dockerfile := []byte(`
|
||||
FROM busybox
|
||||
RUN --mount=type=secret,required=false,mode=741,uid=100,gid=102,target=/mysecret [ "$(stat -c "%u %g %f" /mysecret)" = "100 102 81e1" ]
|
||||
RUN [ ! -f /mysecret ] # check no stub left behind
|
||||
`)
|
||||
|
||||
dir, err := tmpdir(
|
||||
|
|
|
@ -9,15 +9,12 @@ import (
|
|||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/moby/buildkit/cache"
|
||||
"github.com/moby/buildkit/exporter/containerimage/exptypes"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
emptyGZLayer = digest.Digest("sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1")
|
||||
)
|
||||
|
||||
type Opt struct {
|
||||
ImageStore images.Store
|
||||
ContentStore content.Store
|
||||
|
@ -93,7 +90,7 @@ func toDigests(layers []specs.Descriptor) []digest.Digest {
|
|||
func layerKey(layers []digest.Digest) string {
|
||||
b := &strings.Builder{}
|
||||
for _, l := range layers {
|
||||
if l != emptyGZLayer {
|
||||
if l != exptypes.EmptyGZLayer {
|
||||
b.Write([]byte(l))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue