func (b *Builder) processImageFrom(img *image.Image) error { b.image = img.ID().String() if img.Config != nil { b.runConfig = img.Config } // The default path will be blank on Windows (set by HCS) if len(b.runConfig.Env) == 0 && container.DefaultPathEnv != "" { b.runConfig.Env = append(b.runConfig.Env, "PATH="+container.DefaultPathEnv) } // Process ONBUILD triggers if they exist if nTriggers := len(b.runConfig.OnBuild); nTriggers != 0 { word := "trigger" if nTriggers > 1 { word = "triggers" } fmt.Fprintf(b.Stderr, "# Executing %d build %s...\n", nTriggers, word) } // Copy the ONBUILD triggers, and remove them from the config, since the config will be committed. onBuildTriggers := b.runConfig.OnBuild b.runConfig.OnBuild = []string{} // parse the ONBUILD triggers by invoking the parser for _, step := range onBuildTriggers { ast, err := parser.Parse(strings.NewReader(step)) if err != nil { return err } for i, n := range ast.Children { switch strings.ToUpper(n.Value) { case "ONBUILD": return fmt.Errorf("Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") case "MAINTAINER", "FROM": return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", n.Value) } if err := b.dispatch(i, n); err != nil { return err } } } return nil }
func (ic *imageCache) GetCache(parentID string, cfg *containertypes.Config) (string, error) { imgID, err := ic.localImageCache.GetCache(parentID, cfg) if err != nil { return "", err } if imgID != "" { for _, s := range ic.sources { if ic.isParent(s.ID(), image.ID(imgID)) { return imgID, nil } } } var parent *image.Image lenHistory := 0 if parentID != "" { parent, err = ic.daemon.imageStore.Get(image.ID(parentID)) if err != nil { return "", errors.Wrapf(err, "unable to find image %v", parentID) } lenHistory = len(parent.History) } for _, target := range ic.sources { if !isValidParent(target, parent) || !isValidConfig(cfg, target.History[lenHistory]) { continue } if len(target.History)-1 == lenHistory { // last if parent != nil { if err := ic.daemon.imageStore.SetParent(target.ID(), parent.ID()); err != nil { return "", errors.Wrapf(err, "failed to set parent for %v to %v", target.ID(), parent.ID()) } } return target.ID().String(), nil } imgID, err := ic.restoreCachedImage(parent, target, cfg) if err != nil { return "", errors.Wrapf(err, "failed to restore cached image from %q to %v", parentID, target.ID()) } ic.sources = []*image.Image{target} // avoid jumping to different target, tuned for safety atm return imgID.String(), nil } return "", nil }
func newImage(image *image.Image, size int64) *types.Image { newImage := new(types.Image) newImage.ParentID = image.Parent.String() newImage.ID = image.ID().String() newImage.Created = image.Created.Unix() newImage.Size = size newImage.VirtualSize = size if image.Config != nil { newImage.Labels = image.Config.Labels } return newImage }
func newImage(image *image.Image, virtualSize int64) *types.ImageSummary { newImage := new(types.ImageSummary) newImage.ParentID = image.Parent.String() newImage.ID = image.ID().String() newImage.Created = image.Created.Unix() newImage.Size = -1 newImage.VirtualSize = virtualSize newImage.SharedSize = -1 newImage.Containers = -1 if image.Config != nil { newImage.Labels = image.Config.Labels } return newImage }
func (ic *imageCache) restoreCachedImage(parent, target *image.Image, cfg *containertypes.Config) (image.ID, error) { var history []image.History rootFS := image.NewRootFS() lenHistory := 0 if parent != nil { history = parent.History rootFS = parent.RootFS lenHistory = len(parent.History) } history = append(history, target.History[lenHistory]) if layer := getLayerForHistoryIndex(target, lenHistory); layer != "" { rootFS.Append(layer) } config, err := json.Marshal(&image.Image{ V1Image: image.V1Image{ DockerVersion: dockerversion.Version, Config: cfg, Architecture: target.Architecture, OS: target.OS, Author: target.Author, Created: history[len(history)-1].Created, }, RootFS: rootFS, History: history, OSFeatures: target.OSFeatures, OSVersion: target.OSVersion, }) if err != nil { return "", errors.Wrap(err, "failed to marshal image config") } imgID, err := ic.daemon.imageStore.Create(config) if err != nil { return "", errors.Wrap(err, "failed to create cache image") } if parent != nil { if err := ic.daemon.imageStore.SetParent(imgID, parent.ID()); err != nil { return "", errors.Wrapf(err, "failed to set parent for %v to %v", target.ID(), parent.ID()) } } return imgID, nil }
// Create creates a new container from the given configuration with a given name. func (daemon *Daemon) create(params types.ContainerCreateConfig) (retC *container.Container, retErr error) { var ( container *container.Container img *image.Image imgID image.ID err error ) if params.Config.Image != "" { img, err = daemon.GetImage(params.Config.Image) if err != nil { return nil, err } imgID = img.ID() } if err := daemon.mergeAndVerifyConfig(params.Config, img); err != nil { return nil, err } if err := daemon.mergeAndVerifyLogConfig(¶ms.HostConfig.LogConfig); err != nil { return nil, err } if container, err = daemon.newContainer(params.Name, params.Config, imgID); err != nil { return nil, err } defer func() { if retErr != nil { if err := daemon.cleanupContainer(container, true); err != nil { logrus.Errorf("failed to cleanup container on create error: %v", err) } } }() if err := daemon.setSecurityOptions(container, params.HostConfig); err != nil { return nil, err } container.HostConfig.StorageOpt = params.HostConfig.StorageOpt // Set RWLayer for container after mount labels have been set if err := daemon.setRWLayer(container); err != nil { return nil, err } rootUID, rootGID, err := idtools.GetRootUIDGID(daemon.uidMaps, daemon.gidMaps) if err != nil { return nil, err } if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil { return nil, err } if err := daemon.setHostConfig(container, params.HostConfig); err != nil { return nil, err } defer func() { if retErr != nil { if err := daemon.removeMountPoints(container, true); err != nil { logrus.Error(err) } } }() if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig); err != nil { return nil, err } var endpointsConfigs map[string]*networktypes.EndpointSettings if params.NetworkingConfig != nil { endpointsConfigs = params.NetworkingConfig.EndpointsConfig } if err := daemon.updateContainerNetworkSettings(container, endpointsConfigs); err != nil { return nil, err } if err := container.ToDisk(); err != nil { logrus.Errorf("Error saving new container to disk: %v", err) return nil, err } if err := daemon.Register(container); err != nil { return nil, err } daemon.LogContainerEvent(container, "create") return container, nil }
// Create creates a new container from the given configuration with a given name. func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (retC *container.Container, retErr error) { var ( container *container.Container img *image.Image imgID image.ID err error ) if params.Config.Image != "" { img, err = daemon.GetImage(params.Config.Image) if err != nil { return nil, err } imgID = img.ID() } if err := daemon.mergeAndVerifyConfig(params.Config, img); err != nil { return nil, err } if err := daemon.mergeAndVerifyLogConfig(¶ms.HostConfig.LogConfig); err != nil { return nil, err } if container, err = daemon.newContainer(params.Name, params.Config, imgID, managed); err != nil { return nil, err } defer func() { if retErr != nil { if err := daemon.cleanupContainer(container, true, true); err != nil { logrus.Errorf("failed to cleanup container on create error: %v", err) } } }() if err := daemon.setSecurityOptions(container, params.HostConfig); err != nil { return nil, err } container.HostConfig.StorageOpt = params.HostConfig.StorageOpt // Set RWLayer for container after mount labels have been set if err := daemon.setRWLayer(container); err != nil { return nil, err } rootUID, rootGID, err := idtools.GetRootUIDGID(daemon.uidMaps, daemon.gidMaps) if err != nil { return nil, err } if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil { return nil, err } if err := idtools.MkdirAs(container.CheckpointDir(), 0700, rootUID, rootGID); err != nil { return nil, err } if err := daemon.setHostConfig(container, params.HostConfig); err != nil { return nil, err } if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig); err != nil { return nil, err } var endpointsConfigs map[string]*networktypes.EndpointSettings if params.NetworkingConfig != nil { endpointsConfigs = params.NetworkingConfig.EndpointsConfig } // Make sure NetworkMode has an acceptable value. We do this to ensure // backwards API compatibility. container.HostConfig = runconfig.SetDefaultNetModeIfBlank(container.HostConfig) daemon.updateContainerNetworkSettings(container, endpointsConfigs) if err := container.ToDisk(); err != nil { logrus.Errorf("Error saving new container to disk: %v", err) return nil, err } if err := daemon.Register(container); err != nil { return nil, err } daemon.LogContainerEvent(container, "create") return container, nil }
// Create creates a new container from the given configuration with a given name. func (daemon *Daemon) create(params *ContainerCreateConfig) (retC *container.Container, retErr error) { var ( container *container.Container img *image.Image imgID image.ID err error ) if params.Config.Image != "" { img, err = daemon.GetImage(params.Config.Image) if err != nil { return nil, err } imgID = img.ID() } if err := daemon.mergeAndVerifyConfig(params.Config, img); err != nil { return nil, err } if container, err = daemon.newContainer(params.Name, params.Config, imgID); err != nil { return nil, err } defer func() { if retErr != nil { if err := daemon.ContainerRm(container.ID, &ContainerRmConfig{ForceRemove: true}); err != nil { logrus.Errorf("Clean up Error! Cannot destroy container %s: %v", container.ID, err) } } }() if err := daemon.Register(container); err != nil { return nil, err } rootUID, rootGID, err := idtools.GetRootUIDGID(daemon.uidMaps, daemon.gidMaps) if err != nil { return nil, err } if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil { return nil, err } if err := daemon.setHostConfig(container, params.HostConfig); err != nil { return nil, err } defer func() { if retErr != nil { if err := daemon.removeMountPoints(container, true); err != nil { logrus.Error(err) } } }() if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig, img); err != nil { return nil, err } if err := container.ToDiskLocking(); err != nil { logrus.Errorf("Error saving new container to disk: %v", err) return nil, err } daemon.LogContainerEvent(container, "create") return container, nil }
// Create creates a new container from the given configuration with a given name. func (daemon *Daemon) create(params types.ContainerCreateConfig) (retC *container.Container, retErr error) { var ( container *container.Container img *image.Image imgID image.ID err error ) if params.Config.Image != "" { img, err = daemon.GetImage(params.Config.Image) if err != nil { return nil, err } imgID = img.ID() } if err := daemon.mergeAndVerifyConfig(params.Config, img); err != nil { return nil, err } if container, err = daemon.newContainer(params.Name, params.Config, imgID); err != nil { return nil, err } defer func() { if retErr != nil { if err := daemon.ContainerRm(container.ID, &types.ContainerRmConfig{ForceRemove: true}); err != nil { logrus.Errorf("Clean up Error! Cannot destroy container %s: %v", container.ID, err) } } }() logCfg := container.GetLogConfig(daemon.defaultLogConfig) if err := logger.ValidateLogOpts(logCfg.Type, logCfg.Config); err != nil { return nil, err } if err := daemon.setSecurityOptions(container, params.HostConfig); err != nil { return nil, err } // Set RWLayer for container after mount labels have been set if err := daemon.setRWLayer(container); err != nil { return nil, err } if err := daemon.Register(container); err != nil { return nil, err } rootUID, rootGID, err := idtools.GetRootUIDGID(daemon.uidMaps, daemon.gidMaps) if err != nil { return nil, err } if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil { return nil, err } if err := daemon.setHostConfig(container, params.HostConfig); err != nil { return nil, err } defer func() { if retErr != nil { if err := daemon.removeMountPoints(container, true); err != nil { logrus.Error(err) } } }() if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig); err != nil { return nil, err } var endpointsConfigs map[string]*networktypes.EndpointSettings if params.NetworkingConfig != nil { endpointsConfigs = params.NetworkingConfig.EndpointsConfig } if err := daemon.updateContainerNetworkSettings(container, endpointsConfigs); err != nil { return nil, err } if err := container.ToDiskLocking(); err != nil { logrus.Errorf("Error saving new container to disk: %v", err) return nil, err } daemon.LogContainerEvent(container, "create") return container, nil }
func getImageIDAndError(img *image.Image, err error) (string, error) { if img == nil || err != nil { return "", err } return img.ID().String(), nil }
// Create creates a new container from the given configuration with a given name. func (daemon *Daemon) create(params types.ContainerCreateConfig) (retC *container.Container, retErr error) { var ( container *container.Container img *image.Image imgID image.ID err error ) if params.Config.Image != "" { //获取镜像 img, err = daemon.GetImage(params.Config.Image) if err != nil { return nil, err } //获取镜像ID号 imgID = img.ID() } //合并并且检查参数 if err := daemon.mergeAndVerifyConfig(params.Config, img); err != nil { return nil, err } //创建一个新的容器,此时需要跟踪分析newContainer方法,该方法在daemon/daemon.go中。 //该方法返回的是container,是一个这样的结构: /* type Container struct { //这是通用的参数 CommonContainer // 这个是平台特殊的参数,只在类unix系统上有意义。 AppArmorProfile string HostnamePath string HostsPath string ShmPath string ResolvConfPath string SeccompProfile string NoNewPrivileges bool } */ //创建容器实例,实际上只是在代码中创建,并没有创建文件系统和namespace。 //实际上,创建容器的过程中最多也就创建到文件系统,namespace只有在容器 //运行时候才会生效。 if container, err = daemon.newContainer(params.Name, params.Config, imgID); err != nil { return nil, err } //如果创建容器出错,就试图删除容器。 defer func() { if retErr != nil { if err := daemon.ContainerRm(container.ID, &types.ContainerRmConfig{ForceRemove: true}); err != nil { logrus.Errorf("Clean up Error! Cannot destroy container %s: %v", container.ID, err) } } }() //配置容器的安全设置,例如apparmor,selinux等。 if err := daemon.setSecurityOptions(container, params.HostConfig); err != nil { return nil, err } // Set RWLayer for container after mount labels have been set // 设置可读写层,就是获取layID等信息,包括镜像层、容器层。 //详情请见setRWLayer函数,就在本文件中。 if err := daemon.setRWLayer(container); err != nil { return nil, err } //向daemon注册容器: //daemon.containers.Add(c.ID, c) if err := daemon.Register(container); err != nil { return nil, err } rootUID, rootGID, err := idtools.GetRootUIDGID(daemon.uidMaps, daemon.gidMaps) if err != nil { return nil, err } //设置容器root目录(元数据目录/var/lib/docker/containers)的权限。 if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil { return nil, err } //这个方法主要做两件事情: //挂载volumes; //设置容器之间的链接links; if err := daemon.setHostConfig(container, params.HostConfig); err != nil { return nil, err } defer func() { if retErr != nil { if err := daemon.removeMountPoints(container, true); err != nil { logrus.Error(err) } } }() //这一步是处理和平台相关的操作,具体在daemon/create_unix.go文件中 /* func (daemon *Daemon) createContainerPlatformSpecificSettings(container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig) error { if err := daemon.Mount(container); err != nil { return err } defer daemon.Unmount(container) rootUID, rootGID := daemon.GetRemappedUIDGID() if err := container.SetupWorkingDirectory(rootUID, rootGID); err != nil { return err } for spec := range config.Volumes { name := stringid.GenerateNonCryptoID() destination := filepath.Clean(spec) // Skip volumes for which we already have something mounted on that // destination because of a --volume-from. if container.IsDestinationMounted(destination) { continue } path, err := container.GetResourcePath(destination) if err != nil { return err } stat, err := os.Stat(path) if err == nil && !stat.IsDir() { return fmt.Errorf("cannot mount volume over existing file, file exists %s", path) } v, err := daemon.volumes.CreateWithRef(name, hostConfig.VolumeDriver, container.ID, nil, nil) if err != nil { return err } if err := label.Relabel(v.Path(), container.MountLabel, true); err != nil { return err } container.AddMountPointWithVolume(destination, v, true) } return daemon.populateVolumes(container) } */ //在这一步骤里面进行一些跟平台相关的设置,主要为mount目录文件,以及volume挂载。 if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig); err != nil { return nil, err } //网络endpoints的配置 var endpointsConfigs map[string]*networktypes.EndpointSettings if params.NetworkingConfig != nil { endpointsConfigs = params.NetworkingConfig.EndpointsConfig } //更新网路配置,在daemon/container_operations.go中,调用了libnetwork模块,需要仔细研究。 //这里仅仅是更新container.NetworkSettings.Networks[]数组中的网络模式。并没有真正创建网络。 if err := daemon.updateContainerNetworkSettings(container, endpointsConfigs); err != nil { return nil, err } //将容器的配置保存到磁盘。但是这个和另外一个todisk的区别是什么? if err := container.ToDiskLocking(); err != nil { logrus.Errorf("Error saving new container to disk: %v", err) return nil, err } //记录容器的事件日志。 daemon.LogContainerEvent(container, "create") return container, nil }