// Create is the entrypoint to create a container from a spec, and if successfully // created, start it too. Table below shows the fields required for HCS JSON calling parameters, // where if not populated, is omitted. // +-----------------+--------------------------------------------+---------------------------------------------------+ // | | Isolation=Process | Isolation=Hyper-V | // +-----------------+--------------------------------------------+---------------------------------------------------+ // | VolumePath | \\?\\Volume{GUIDa} | | // | LayerFolderPath | %root%\windowsfilter\containerID | %root%\windowsfilter\containerID (servicing only) | // | Layers[] | ID=GUIDb;Path=%root%\windowsfilter\layerID | ID=GUIDb;Path=%root%\windowsfilter\layerID | // | SandboxPath | | %root%\windowsfilter | // | HvRuntime | | ImagePath=%root%\BaseLayerID\UtilityVM | // +-----------------+--------------------------------------------+---------------------------------------------------+ // // Isolation=Process example: // // { // "SystemType": "Container", // "Name": "5e0055c814a6005b8e57ac59f9a522066e0af12b48b3c26a9416e23907698776", // "Owner": "docker", // "IsDummy": false, // "VolumePath": "\\\\\\\\?\\\\Volume{66d1ef4c-7a00-11e6-8948-00155ddbef9d}", // "IgnoreFlushesDuringBoot": true, // "LayerFolderPath": "C:\\\\control\\\\windowsfilter\\\\5e0055c814a6005b8e57ac59f9a522066e0af12b48b3c26a9416e23907698776", // "Layers": [{ // "ID": "18955d65-d45a-557b-bf1c-49d6dfefc526", // "Path": "C:\\\\control\\\\windowsfilter\\\\65bf96e5760a09edf1790cb229e2dfb2dbd0fcdc0bf7451bae099106bfbfea0c" // }], // "HostName": "5e0055c814a6", // "MappedDirectories": [], // "HvPartition": false, // "EndpointList": ["eef2649d-bb17-4d53-9937-295a8efe6f2c"], // "Servicing": false //} // // Isolation=Hyper-V example: // //{ // "SystemType": "Container", // "Name": "475c2c58933b72687a88a441e7e0ca4bd72d76413c5f9d5031fee83b98f6045d", // "Owner": "docker", // "IsDummy": false, // "IgnoreFlushesDuringBoot": true, // "Layers": [{ // "ID": "18955d65-d45a-557b-bf1c-49d6dfefc526", // "Path": "C:\\\\control\\\\windowsfilter\\\\65bf96e5760a09edf1790cb229e2dfb2dbd0fcdc0bf7451bae099106bfbfea0c" // }], // "HostName": "475c2c58933b", // "MappedDirectories": [], // "SandboxPath": "C:\\\\control\\\\windowsfilter", // "HvPartition": true, // "EndpointList": ["e1bb1e61-d56f-405e-b75d-fd520cefa0cb"], // "HvRuntime": { // "ImagePath": "C:\\\\control\\\\windowsfilter\\\\65bf96e5760a09edf1790cb229e2dfb2dbd0fcdc0bf7451bae099106bfbfea0c\\\\UtilityVM" // }, // "Servicing": false //} func (clnt *client) Create(containerID string, checkpoint string, checkpointDir string, spec specs.Spec, options ...CreateOption) error { clnt.lock(containerID) defer clnt.unlock(containerID) logrus.Debugln("libcontainerd: client.Create() with spec", spec) configuration := &hcsshim.ContainerConfig{ SystemType: "Container", Name: containerID, Owner: defaultOwner, IgnoreFlushesDuringBoot: false, HostName: spec.Hostname, HvPartition: false, } if spec.Windows.Resources != nil { if spec.Windows.Resources.CPU != nil { if spec.Windows.Resources.CPU.Shares != nil { configuration.ProcessorWeight = uint64(*spec.Windows.Resources.CPU.Shares) } if spec.Windows.Resources.CPU.Percent != nil { configuration.ProcessorMaximum = int64(*spec.Windows.Resources.CPU.Percent) * 100 // ProcessorMaximum is a value between 1 and 10000 } } if spec.Windows.Resources.Memory != nil { if spec.Windows.Resources.Memory.Limit != nil { configuration.MemoryMaximumInMB = int64(*spec.Windows.Resources.Memory.Limit) / 1024 / 1024 } } if spec.Windows.Resources.Storage != nil { if spec.Windows.Resources.Storage.Bps != nil { configuration.StorageBandwidthMaximum = *spec.Windows.Resources.Storage.Bps } if spec.Windows.Resources.Storage.Iops != nil { configuration.StorageIOPSMaximum = *spec.Windows.Resources.Storage.Iops } } } var layerOpt *LayerOption for _, option := range options { if s, ok := option.(*ServicingOption); ok { configuration.Servicing = s.IsServicing continue } if f, ok := option.(*FlushOption); ok { configuration.IgnoreFlushesDuringBoot = f.IgnoreFlushesDuringBoot continue } if h, ok := option.(*HyperVIsolationOption); ok { configuration.HvPartition = h.IsHyperV configuration.SandboxPath = h.SandboxPath continue } if l, ok := option.(*LayerOption); ok { layerOpt = l } if n, ok := option.(*NetworkEndpointsOption); ok { configuration.EndpointList = n.Endpoints configuration.AllowUnqualifiedDNSQuery = n.AllowUnqualifiedDNSQuery continue } if c, ok := option.(*CredentialsOption); ok { configuration.Credentials = c.Credentials continue } } // We must have a layer option with at least one path if layerOpt == nil || layerOpt.LayerPaths == nil { return fmt.Errorf("no layer option or paths were supplied to the runtime") } if configuration.HvPartition { // Find the upper-most utility VM image, since the utility VM does not // use layering in RS1. // TODO @swernli/jhowardmsft at some point post RS1 this may be re-locatable. var uvmImagePath string for _, path := range layerOpt.LayerPaths { fullPath := filepath.Join(path, "UtilityVM") _, err := os.Stat(fullPath) if err == nil { uvmImagePath = fullPath break } if !os.IsNotExist(err) { return err } } if uvmImagePath == "" { return errors.New("utility VM image could not be found") } configuration.HvRuntime = &hcsshim.HvRuntime{ImagePath: uvmImagePath} } else { configuration.VolumePath = spec.Root.Path } configuration.LayerFolderPath = layerOpt.LayerFolderPath for _, layerPath := range layerOpt.LayerPaths { _, filename := filepath.Split(layerPath) g, err := hcsshim.NameToGuid(filename) if err != nil { return err } configuration.Layers = append(configuration.Layers, hcsshim.Layer{ ID: g.ToString(), Path: layerPath, }) } // Add the mounts (volumes, bind mounts etc) to the structure mds := make([]hcsshim.MappedDir, len(spec.Mounts)) for i, mount := range spec.Mounts { mds[i] = hcsshim.MappedDir{ HostPath: mount.Source, ContainerPath: mount.Destination, ReadOnly: false, } for _, o := range mount.Options { if strings.ToLower(o) == "ro" { mds[i].ReadOnly = true } } } configuration.MappedDirectories = mds hcsContainer, err := hcsshim.CreateContainer(containerID, configuration) if err != nil { return err } // Construct a container object for calling start on it. container := &container{ containerCommon: containerCommon{ process: process{ processCommon: processCommon{ containerID: containerID, client: clnt, friendlyName: InitFriendlyName, }, commandLine: strings.Join(spec.Process.Args, " "), }, processes: make(map[string]*process), }, ociSpec: spec, hcsContainer: hcsContainer, } container.options = options for _, option := range options { if err := option.Apply(container); err != nil { logrus.Errorf("libcontainerd: %v", err) } } // Call start, and if it fails, delete the container from our // internal structure, start will keep HCS in sync by deleting the // container there. logrus.Debugf("libcontainerd: Create() id=%s, Calling start()", containerID) if err := container.start(); err != nil { clnt.deleteContainer(containerID) return err } logrus.Debugf("libcontainerd: Create() id=%s completed successfully", containerID) return nil }
func main() { if len(os.Args) != 2 { fmt.Print(` This sample create a new container runs ping and then destroys the container. Usage: sample.exe <base container Id> To get the base container id for "microsoft/windowsservercore" use the following PS snippet: Split-Path -Leaf (docker inspect microsoft/windowsservercore | ConvertFrom-Json).GraphDriver.Data.Dir `) os.Exit(1) } windowsbaseId := os.Args[1] di := hcsshim.DriverInfo{ HomeDir: homeDir, Flavour: filterDriver, } imgData, err := hcsshim.GetSharedBaseImages() panicIf(err) fmt.Println(imgData) hcsNets, err := hcsshim.HNSListNetworkRequest("GET", "", "") panicIf(err) fmt.Println(hcsNets) virtualNetworkId := "" for _, n := range hcsNets { if n.Name == "nat" { virtualNetworkId = n.Id } } // https://github.com/docker/libnetwork/blob/f9a1590164b878e668eabf889dd79fb6af8eaced/drivers/windows/windows.go#L284 endpointRequest := hcsshim.HNSEndpoint{ VirtualNetwork: virtualNetworkId, } endpointRequestJson, err := json.Marshal(endpointRequest) panicIf(err) endpoint, err := hcsshim.HNSEndpointRequest("POST", "", string(endpointRequestJson)) panicIf(err) fmt.Println(*endpoint) windowsservercorePath, err := hcsshim.GetLayerMountPath(di, windowsbaseId) panicIf(err) fmt.Println(windowsservercorePath) layerChain, err := GetLayerChain(windowsservercorePath) panicIf(err) fmt.Println(layerChain) newContainerId := stringid.GenerateNonCryptoID() layerFolderPath, volumeMountPath, err := CreateAndActivateContainerLayer(di, newContainerId, windowsservercorePath) panicIf(err) containerConfig := hcsshim.ContainerConfig{ SystemType: "Container", Name: newContainerId, Owner: "Garden", LayerFolderPath: layerFolderPath, VolumePath: volumeMountPath, IgnoreFlushesDuringBoot: true, EndpointList: []string{endpoint.Id}, } // https://github.com/docker/docker/blob/cf58eb437c4229e876f2d952a228b603a074e584/libcontainerd/client_windows.go#L111-L121 for _, layerPath := range layerChain { id, err := hcsshim.NameToGuid(GetLayerId(layerPath)) panicIf(err) containerConfig.Layers = append(containerConfig.Layers, hcsshim.Layer{ Path: layerPath, ID: id.ToString(), }) } c, err := hcsshim.CreateContainer(newContainerId, &containerConfig) panicIf(err) fmt.Println(c) err = c.Start() panicIf(err) stats, err := c.Statistics() panicIf(err) fmt.Println(stats) processConfig := hcsshim.ProcessConfig{ CommandLine: "ping 127.0.0.1", WorkingDirectory: "C:\\", //CreateStdErrPipe: true, //CreateStdInPipe: true, //CreateStdOutPipe: true, } p, err := c.CreateProcess(&processConfig) panicIf(err) fmt.Println(p) err = p.Wait() panicIf(err) err = c.Shutdown() warnIf(err) err = c.Terminate() warnIf(err) endpoint, err = hcsshim.HNSEndpointRequest("DELETE", endpoint.Id, "") warnIf(err) err = hcsshim.UnprepareLayer(di, newContainerId) warnIf(err) err = hcsshim.DeactivateLayer(di, newContainerId) warnIf(err) err = hcsshim.DestroyLayer(di, newContainerId) warnIf(err) }
// Create is the entrypoint to create a container from a spec, and if successfully // created, start it too. func (clnt *client) Create(containerID string, spec Spec, options ...CreateOption) error { logrus.Debugln("libcontainerd: client.Create() with spec", spec) configuration := &hcsshim.ContainerConfig{ SystemType: "Container", Name: containerID, Owner: defaultOwner, VolumePath: spec.Root.Path, IgnoreFlushesDuringBoot: spec.Windows.FirstStart, LayerFolderPath: spec.Windows.LayerFolder, HostName: spec.Hostname, } if spec.Windows.Networking != nil { configuration.EndpointList = spec.Windows.Networking.EndpointList } if spec.Windows.Resources != nil { if spec.Windows.Resources.CPU != nil { if spec.Windows.Resources.CPU.Shares != nil { configuration.ProcessorWeight = *spec.Windows.Resources.CPU.Shares } if spec.Windows.Resources.CPU.Percent != nil { configuration.ProcessorMaximum = *spec.Windows.Resources.CPU.Percent * 100 // ProcessorMaximum is a value between 1 and 10000 } } if spec.Windows.Resources.Memory != nil { if spec.Windows.Resources.Memory.Limit != nil { configuration.MemoryMaximumInMB = *spec.Windows.Resources.Memory.Limit / 1024 / 1024 } } if spec.Windows.Resources.Storage != nil { if spec.Windows.Resources.Storage.Bps != nil { configuration.StorageBandwidthMaximum = *spec.Windows.Resources.Storage.Bps } if spec.Windows.Resources.Storage.Iops != nil { configuration.StorageIOPSMaximum = *spec.Windows.Resources.Storage.Iops } } } if spec.Windows.HvRuntime != nil { configuration.VolumePath = "" // Always empty for Hyper-V containers configuration.HvPartition = true configuration.HvRuntime = &hcsshim.HvRuntime{ ImagePath: spec.Windows.HvRuntime.ImagePath, } // Images with build version < 14350 don't support running with clone, but // Windows cannot automatically detect this. Explicitly block cloning in this // case. if build := buildFromVersion(spec.Platform.OSVersion); build > 0 && build < 14350 { configuration.HvRuntime.SkipTemplate = true } } if configuration.HvPartition { configuration.SandboxPath = filepath.Dir(spec.Windows.LayerFolder) } else { configuration.VolumePath = spec.Root.Path configuration.LayerFolderPath = spec.Windows.LayerFolder } for _, option := range options { if s, ok := option.(*ServicingOption); ok { configuration.Servicing = s.IsServicing break } } for _, layerPath := range spec.Windows.LayerPaths { _, filename := filepath.Split(layerPath) g, err := hcsshim.NameToGuid(filename) if err != nil { return err } configuration.Layers = append(configuration.Layers, hcsshim.Layer{ ID: g.ToString(), Path: layerPath, }) } // Add the mounts (volumes, bind mounts etc) to the structure mds := make([]hcsshim.MappedDir, len(spec.Mounts)) for i, mount := range spec.Mounts { mds[i] = hcsshim.MappedDir{ HostPath: mount.Source, ContainerPath: mount.Destination, ReadOnly: mount.Readonly} } configuration.MappedDirectories = mds hcsContainer, err := hcsshim.CreateContainer(containerID, configuration) if err != nil { return err } // Construct a container object for calling start on it. container := &container{ containerCommon: containerCommon{ process: process{ processCommon: processCommon{ containerID: containerID, client: clnt, friendlyName: InitFriendlyName, }, commandLine: strings.Join(spec.Process.Args, " "), }, processes: make(map[string]*process), }, ociSpec: spec, hcsContainer: hcsContainer, } container.options = options for _, option := range options { if err := option.Apply(container); err != nil { logrus.Errorf("libcontainerd: %v", err) } } // Call start, and if it fails, delete the container from our // internal structure, start will keep HCS in sync by deleting the // container there. logrus.Debugf("libcontainerd: Create() id=%s, Calling start()", containerID) if err := container.start(); err != nil { clnt.deleteContainer(containerID) return err } logrus.Debugf("libcontainerd: Create() id=%s completed successfully", containerID) return nil }
func main() { if len(os.Args) != 2 { fmt.Print(` This sample create a new container runs ping and then destroys the container. Usage: sample.exe <base container Id> To get the base container id for "microsoft/windowsservercore" use the following PS snippet: Split-Path -Leaf (docker inspect microsoft/windowsservercore | ConvertFrom-Json).GraphDriver.Data.Dir `) os.Exit(1) } windowsbaseId := os.Args[1] guid, err := hcsshim.NameToGuid(windowsbaseId) panicIf(err) windowsbaseGuid := guid.ToString() di := hcsshim.DriverInfo{ HomeDir: homeDir, Flavour: filterDriver, } imgData, err := hcsshim.GetSharedBaseImages() panicIf(err) fmt.Println(imgData) windowsservercorePath, err := hcsshim.GetLayerMountPath(di, windowsbaseId) panicIf(err) fmt.Println(windowsservercorePath) newContainerId := stringid.GenerateNonCryptoID() layerFolderPath, volumeMountPath, err := CreateAndActivateContainerLayer(di, newContainerId, windowsservercorePath) panicIf(err) containerConfig := hcsshim.ContainerConfig{ SystemType: "Container", Name: newContainerId, Owner: "Garden", LayerFolderPath: layerFolderPath, VolumePath: volumeMountPath, Layers: []hcsshim.Layer{ hcsshim.Layer{Path: windowsservercorePath, ID: windowsbaseGuid}, }, IgnoreFlushesDuringBoot: true, } c, err := hcsshim.CreateContainer(newContainerId, &containerConfig) panicIf(err) fmt.Println(c) err = c.Start() panicIf(err) stats, err := c.Statistics() panicIf(err) fmt.Println(stats) processConfig := hcsshim.ProcessConfig{ CommandLine: "ping 127.0.0.1", WorkingDirectory: "C:\\", //CreateStdErrPipe: true, //CreateStdInPipe: true, //CreateStdOutPipe: true, } p, err := c.CreateProcess(&processConfig) panicIf(err) fmt.Println(p) err = p.Wait() panicIf(err) err = c.Shutdown() warnIf(err) err = c.Terminate() warnIf(err) err = hcsshim.UnprepareLayer(di, newContainerId) warnIf(err) err = hcsshim.DeactivateLayer(di, newContainerId) warnIf(err) err = hcsshim.DestroyLayer(di, newContainerId) warnIf(err) }