github.com/moby/docker@v26.1.3+incompatible/daemon/create_unix.go (about) 1 //go:build !windows 2 3 package daemon // import "github.com/docker/docker/daemon" 4 5 import ( 6 "context" 7 "fmt" 8 "os" 9 "path/filepath" 10 11 "github.com/containerd/log" 12 containertypes "github.com/docker/docker/api/types/container" 13 mounttypes "github.com/docker/docker/api/types/mount" 14 "github.com/docker/docker/container" 15 "github.com/docker/docker/errdefs" 16 "github.com/docker/docker/internal/compatcontext" 17 "github.com/docker/docker/oci" 18 volumemounts "github.com/docker/docker/volume/mounts" 19 volumeopts "github.com/docker/docker/volume/service/opts" 20 "github.com/opencontainers/selinux/go-selinux/label" 21 "github.com/pkg/errors" 22 ) 23 24 // createContainerOSSpecificSettings performs host-OS specific container create functionality 25 func (daemon *Daemon) createContainerOSSpecificSettings(ctx context.Context, container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig) error { 26 if err := daemon.Mount(container); err != nil { 27 return err 28 } 29 defer daemon.Unmount(container) 30 31 rootIDs := daemon.idMapping.RootPair() 32 if err := container.SetupWorkingDirectory(rootIDs); err != nil { 33 return err 34 } 35 36 // Set the default masked and readonly paths with regard to the host config options if they are not set. 37 if hostConfig.MaskedPaths == nil && !hostConfig.Privileged { 38 hostConfig.MaskedPaths = oci.DefaultSpec().Linux.MaskedPaths // Set it to the default if nil 39 container.HostConfig.MaskedPaths = hostConfig.MaskedPaths 40 } 41 if hostConfig.ReadonlyPaths == nil && !hostConfig.Privileged { 42 hostConfig.ReadonlyPaths = oci.DefaultSpec().Linux.ReadonlyPaths // Set it to the default if nil 43 container.HostConfig.ReadonlyPaths = hostConfig.ReadonlyPaths 44 } 45 46 for spec := range config.Volumes { 47 destination := filepath.Clean(spec) 48 49 // Skip volumes for which we already have something mounted on that 50 // destination because of a --volume-from. 51 if container.HasMountFor(destination) { 52 log.G(ctx).WithField("container", container.ID).WithField("destination", spec).Debug("mountpoint already exists, skipping anonymous volume") 53 // Not an error, this could easily have come from the image config. 54 continue 55 } 56 path, err := container.GetResourcePath(destination) 57 if err != nil { 58 return err 59 } 60 61 stat, err := os.Stat(path) 62 if err == nil && !stat.IsDir() { 63 return fmt.Errorf("cannot mount volume over existing file, file exists %s", path) 64 } 65 66 v, err := daemon.volumes.Create(context.TODO(), "", hostConfig.VolumeDriver, volumeopts.WithCreateReference(container.ID)) 67 if err != nil { 68 return err 69 } 70 71 if err := label.Relabel(v.Mountpoint, container.MountLabel, true); err != nil { 72 return err 73 } 74 75 container.AddMountPointWithVolume(destination, &volumeWrapper{v: v, s: daemon.volumes}, true) 76 } 77 return daemon.populateVolumes(ctx, container) 78 } 79 80 // populateVolumes copies data from the container's rootfs into the volume for non-binds. 81 // this is only called when the container is created. 82 func (daemon *Daemon) populateVolumes(ctx context.Context, c *container.Container) error { 83 for _, mnt := range c.MountPoints { 84 if mnt.Volume == nil { 85 continue 86 } 87 88 if mnt.Type != mounttypes.TypeVolume || !mnt.CopyData { 89 continue 90 } 91 92 if err := daemon.populateVolume(ctx, c, mnt); err != nil { 93 return err 94 } 95 } 96 return nil 97 } 98 99 func (daemon *Daemon) populateVolume(ctx context.Context, c *container.Container, mnt *volumemounts.MountPoint) error { 100 ctrDestPath, err := c.GetResourcePath(mnt.Destination) 101 if err != nil { 102 return err 103 } 104 105 if _, err := os.Stat(ctrDestPath); err != nil { 106 if os.IsNotExist(err) { 107 return nil 108 } 109 return err 110 } 111 112 volumePath, cleanup, err := mnt.Setup(ctx, c.MountLabel, daemon.idMapping.RootPair(), nil) 113 if err != nil { 114 if errdefs.IsNotFound(err) { 115 return nil 116 } 117 log.G(ctx).WithError(err).Debugf("can't copy data from %s:%s, to %s", c.ID, mnt.Destination, volumePath) 118 return errors.Wrapf(err, "failed to populate volume") 119 } 120 defer mnt.Cleanup(compatcontext.WithoutCancel(ctx)) 121 defer cleanup(compatcontext.WithoutCancel(ctx)) 122 123 log.G(ctx).Debugf("copying image data from %s:%s, to %s", c.ID, mnt.Destination, volumePath) 124 if err := c.CopyImagePathContent(volumePath, ctrDestPath); err != nil { 125 return err 126 } 127 128 return nil 129 }