github.com/containerd/nerdctl/v2@v2.0.0-beta.5.0.20240520001846-b5758f54fa28/pkg/cmd/container/run_windows.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package container 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "strings" 24 25 "github.com/containerd/containerd" 26 "github.com/containerd/containerd/containers" 27 "github.com/containerd/containerd/oci" 28 "github.com/containerd/nerdctl/v2/pkg/api/types" 29 "github.com/docker/go-units" 30 "github.com/opencontainers/runtime-spec/specs-go" 31 ) 32 33 const ( 34 // HostProcessInheritUser inherits permissions of containerd process 35 hostProcessInheritUser = "microsoft.com/hostprocess-inherit-user" 36 37 // HostProcessContainer will launch a host process container 38 hostProcessContainer = "microsoft.com/hostprocess-container" 39 uvmMemorySizeInMB = "io.microsoft.virtualmachine.computetopology.memory.sizeinmb" 40 uvmCPUCount = "io.microsoft.virtualmachine.computetopology.processor.count" 41 ) 42 43 func setPlatformOptions( 44 ctx context.Context, 45 client *containerd.Client, 46 id, uts string, 47 internalLabels *internalLabels, 48 options types.ContainerCreateOptions, 49 ) ([]oci.SpecOpts, error) { 50 var opts []oci.SpecOpts 51 if options.CPUs > 0.0 { 52 opts = append(opts, oci.WithWindowsCPUCount(uint64(options.CPUs))) 53 } 54 55 if options.Memory != "" { 56 mem64, err := units.RAMInBytes(options.Memory) 57 if err != nil { 58 return nil, fmt.Errorf("failed to parse memory bytes %q: %w", options.Memory, err) 59 } 60 opts = append(opts, oci.WithMemoryLimit(uint64(mem64))) 61 } 62 63 switch options.Isolation { 64 case "hyperv": 65 if options.Memory != "" { 66 mem64, err := units.RAMInBytes(options.Memory) 67 if err != nil { 68 return nil, fmt.Errorf("failed to parse memory bytes %q: %w", options.Memory, err) 69 } 70 UVMMemmory := map[string]string{ 71 uvmMemorySizeInMB: fmt.Sprintf("%v", mem64), 72 } 73 opts = append(opts, oci.WithAnnotations(UVMMemmory)) 74 } 75 76 if options.CPUs > 0.0 { 77 UVMCPU := map[string]string{ 78 uvmCPUCount: fmt.Sprintf("%v", options.CPUs), 79 } 80 opts = append(opts, oci.WithAnnotations(UVMCPU)) 81 } 82 opts = append(opts, oci.WithWindowsHyperV) 83 case "host": 84 hpAnnotations := map[string]string{ 85 hostProcessContainer: "true", 86 } 87 88 // If user is set we will attempt to start container with that user (must be present on the host) 89 // Otherwise we will inherit permissions from the user that the containerd process is running as 90 if options.User == "" { 91 hpAnnotations[hostProcessInheritUser] = "true" 92 } 93 94 opts = append(opts, oci.WithAnnotations(hpAnnotations)) 95 case "process": 96 // override the default isolation mode in the case where 97 // the containerd default_runtime is set to hyper-v 98 opts = append(opts, WithWindowsProcessIsolated()) 99 case "default": 100 // no op 101 // use containerd's default runtime option `default_runtime` set in the config.toml 102 default: 103 return nil, fmt.Errorf("unknown isolation value %q. valid values are 'host', 'process' or 'default'", options.Isolation) 104 } 105 106 opts = append(opts, 107 oci.WithWindowNetworksAllowUnqualifiedDNSQuery(), 108 oci.WithWindowsIgnoreFlushesDuringBoot()) 109 110 for _, dev := range options.Device { 111 idType, devID, ok := strings.Cut(dev, "://") 112 if !ok { 113 return nil, errors.New("devices must be in the format IDType://ID") 114 } 115 if idType == "" { 116 return nil, errors.New("devices must have a non-empty IDType") 117 } 118 opts = append(opts, oci.WithWindowsDevice(idType, devID)) 119 } 120 121 return opts, nil 122 } 123 124 func WithWindowsProcessIsolated() oci.SpecOpts { 125 return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { 126 if s.Windows == nil { 127 s.Windows = &specs.Windows{} 128 } 129 if s.Windows.HyperV != nil { 130 s.Windows.HyperV = nil 131 } 132 return nil 133 } 134 }