mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
8936789919
There has been a lot of discussion (issues 4242 and 5262) about making `FROM scratch` either a special case or making `FROM` optional, implying starting from an empty file system. This patch makes the build command `FROM scratch` special cased from now on and if used does not pull/set the the initial layer of the build to the ancient image ID (511136ea..) but instead marks the build as having no base image. The next command in the dockerfile will create an image with a parent image ID of "". This means every image ever can now use one fewer layer! This also makes the image name `scratch` a reserved name by the TagStore. You will not be able to tag an image with this name from now on. If any users currently have an image tagged as `scratch`, they will still be able to use that image, but will not be able to tag a new image with that name. Goodbye '511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158', it was nice knowing you. Fixes #4242 Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
140 lines
3.8 KiB
Go
140 lines
3.8 KiB
Go
package daemon
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/docker/docker/engine"
|
|
"github.com/docker/docker/graph"
|
|
"github.com/docker/docker/image"
|
|
"github.com/docker/docker/pkg/parsers"
|
|
"github.com/docker/docker/runconfig"
|
|
"github.com/docker/libcontainer/label"
|
|
)
|
|
|
|
func (daemon *Daemon) ContainerCreate(job *engine.Job) engine.Status {
|
|
var name string
|
|
if len(job.Args) == 1 {
|
|
name = job.Args[0]
|
|
} else if len(job.Args) > 1 {
|
|
return job.Errorf("Usage: %s", job.Name)
|
|
}
|
|
config := runconfig.ContainerConfigFromJob(job)
|
|
if config.Memory != 0 && config.Memory < 4194304 {
|
|
return job.Errorf("Minimum memory limit allowed is 4MB")
|
|
}
|
|
if config.Memory > 0 && !daemon.SystemConfig().MemoryLimit {
|
|
job.Errorf("Your kernel does not support memory limit capabilities. Limitation discarded.\n")
|
|
config.Memory = 0
|
|
}
|
|
if config.Memory > 0 && !daemon.SystemConfig().SwapLimit {
|
|
job.Errorf("Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
|
config.MemorySwap = -1
|
|
}
|
|
|
|
var hostConfig *runconfig.HostConfig
|
|
if job.EnvExists("HostConfig") {
|
|
hostConfig = runconfig.ContainerHostConfigFromJob(job)
|
|
} else {
|
|
// Older versions of the API don't provide a HostConfig.
|
|
hostConfig = nil
|
|
}
|
|
|
|
container, buildWarnings, err := daemon.Create(config, hostConfig, name)
|
|
if err != nil {
|
|
if daemon.Graph().IsNotExist(err) {
|
|
_, tag := parsers.ParseRepositoryTag(config.Image)
|
|
if tag == "" {
|
|
tag = graph.DEFAULTTAG
|
|
}
|
|
return job.Errorf("No such image: %s (tag: %s)", config.Image, tag)
|
|
}
|
|
return job.Error(err)
|
|
}
|
|
if !container.Config.NetworkDisabled && daemon.SystemConfig().IPv4ForwardingDisabled {
|
|
job.Errorf("IPv4 forwarding is disabled.\n")
|
|
}
|
|
container.LogEvent("create")
|
|
|
|
job.Printf("%s\n", container.ID)
|
|
|
|
for _, warning := range buildWarnings {
|
|
job.Errorf("%s\n", warning)
|
|
}
|
|
|
|
return engine.StatusOK
|
|
}
|
|
|
|
// Create creates a new container from the given configuration with a given name.
|
|
func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.HostConfig, name string) (*Container, []string, error) {
|
|
var (
|
|
container *Container
|
|
warnings []string
|
|
img *image.Image
|
|
imgID string
|
|
err error
|
|
)
|
|
|
|
if config.Image != "" {
|
|
img, err = daemon.repositories.LookupImage(config.Image)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err = img.CheckDepth(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
imgID = img.ID
|
|
}
|
|
|
|
if warnings, err = daemon.mergeAndVerifyConfig(config, img); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if hostConfig != nil && hostConfig.SecurityOpt == nil {
|
|
hostConfig.SecurityOpt, err = daemon.GenerateSecurityOpt(hostConfig.IpcMode)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
if container, err = daemon.newContainer(name, config, imgID); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := daemon.Register(container); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := daemon.createRootfs(container); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if hostConfig != nil {
|
|
if err := daemon.setHostConfig(container, hostConfig); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
if err := container.Mount(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
defer container.Unmount()
|
|
if err := container.prepareVolumes(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := container.ToDisk(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return container, warnings, nil
|
|
}
|
|
|
|
func (daemon *Daemon) GenerateSecurityOpt(ipcMode runconfig.IpcMode) ([]string, error) {
|
|
if ipcMode.IsHost() {
|
|
return label.DisableSecOpt(), nil
|
|
}
|
|
if ipcContainer := ipcMode.Container(); ipcContainer != "" {
|
|
c := daemon.Get(ipcContainer)
|
|
if c == nil {
|
|
return nil, fmt.Errorf("no such container to join IPC: %s", ipcContainer)
|
|
}
|
|
if !c.IsRunning() {
|
|
return nil, fmt.Errorf("cannot join IPC of a non running container: %s", ipcContainer)
|
|
}
|
|
|
|
return label.DupSecOpt(c.ProcessLabel), nil
|
|
}
|
|
return nil, nil
|
|
}
|