github.com/containerd/nerdctl@v1.7.7/cmd/nerdctl/container_create.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 main 18 19 import ( 20 "fmt" 21 "runtime" 22 23 "github.com/containerd/nerdctl/pkg/api/types" 24 "github.com/containerd/nerdctl/pkg/clientutil" 25 "github.com/containerd/nerdctl/pkg/cmd/container" 26 "github.com/containerd/nerdctl/pkg/containerutil" 27 "github.com/spf13/cobra" 28 ) 29 30 func newCreateCommand() *cobra.Command { 31 shortHelp := "Create a new container. Optionally specify \"ipfs://\" or \"ipns://\" scheme to pull image from IPFS." 32 longHelp := shortHelp 33 switch runtime.GOOS { 34 case "windows": 35 longHelp += "\n" 36 longHelp += "WARNING: `nerdctl create` is experimental on Windows and currently broken (https://github.com/containerd/nerdctl/issues/28)" 37 case "freebsd": 38 longHelp += "\n" 39 longHelp += "WARNING: `nerdctl create` is experimental on FreeBSD and currently requires `--net=none` (https://github.com/containerd/nerdctl/blob/main/docs/freebsd.md)" 40 } 41 var createCommand = &cobra.Command{ 42 Use: "create [flags] IMAGE [COMMAND] [ARG...]", 43 Args: cobra.MinimumNArgs(1), 44 Short: shortHelp, 45 Long: longHelp, 46 RunE: createAction, 47 ValidArgsFunction: runShellComplete, 48 SilenceUsage: true, 49 SilenceErrors: true, 50 } 51 createCommand.Flags().SetInterspersed(false) 52 setCreateFlags(createCommand) 53 return createCommand 54 } 55 56 func processContainerCreateOptions(cmd *cobra.Command) (opt types.ContainerCreateOptions, err error) { 57 opt.Stdout = cmd.OutOrStdout() 58 opt.Stderr = cmd.ErrOrStderr() 59 opt.GOptions, err = processRootCmdFlags(cmd) 60 if err != nil { 61 return 62 } 63 64 opt.NerdctlCmd, opt.NerdctlArgs = globalFlags(cmd) 65 66 // #region for basic flags 67 // The command `container start` doesn't support the flag `--interactive`. Set the default value of `opt.Interactive` false. 68 opt.Interactive = false 69 opt.TTY, err = cmd.Flags().GetBool("tty") 70 if err != nil { 71 return 72 } 73 // The nerdctl create command similar to nerdctl run -d except the container is never started. 74 // So we keep the default value of `opt.Detach` true. 75 opt.Detach = true 76 opt.Restart, err = cmd.Flags().GetString("restart") 77 if err != nil { 78 return 79 } 80 opt.Rm, err = cmd.Flags().GetBool("rm") 81 if err != nil { 82 return 83 } 84 opt.Pull, err = cmd.Flags().GetString("pull") 85 if err != nil { 86 return 87 } 88 opt.Pid, err = cmd.Flags().GetString("pid") 89 if err != nil { 90 return 91 } 92 opt.StopSignal, err = cmd.Flags().GetString("stop-signal") 93 if err != nil { 94 return 95 } 96 opt.StopTimeout, err = cmd.Flags().GetInt("stop-timeout") 97 if err != nil { 98 return 99 } 100 // #endregion 101 102 // #region for platform flags 103 opt.Platform, err = cmd.Flags().GetString("platform") 104 if err != nil { 105 return 106 } 107 // #endregion 108 109 // #region for init process flags 110 opt.InitProcessFlag, err = cmd.Flags().GetBool("init") 111 if err != nil { 112 return 113 } 114 if opt.InitProcessFlag || cmd.Flags().Changed("init-binary") { 115 var initBinary string 116 initBinary, err = cmd.Flags().GetString("init-binary") 117 if err != nil { 118 return 119 } 120 opt.InitBinary = &initBinary 121 } 122 // #endregion 123 124 // #region for isolation flags 125 opt.Isolation, err = cmd.Flags().GetString("isolation") 126 if err != nil { 127 return 128 } 129 // #endregion 130 131 // #region for resource flags 132 opt.CPUs, err = cmd.Flags().GetFloat64("cpus") 133 if err != nil { 134 return 135 } 136 opt.CPUQuota, err = cmd.Flags().GetInt64("cpu-quota") 137 if err != nil { 138 return 139 } 140 opt.CPUPeriod, err = cmd.Flags().GetUint64("cpu-period") 141 if err != nil { 142 return 143 } 144 opt.CPUShares, err = cmd.Flags().GetUint64("cpu-shares") 145 if err != nil { 146 return 147 } 148 opt.CPUSetCPUs, err = cmd.Flags().GetString("cpuset-cpus") 149 if err != nil { 150 return 151 } 152 opt.CPUSetMems, err = cmd.Flags().GetString("cpuset-mems") 153 if err != nil { 154 return 155 } 156 opt.Memory, err = cmd.Flags().GetString("memory") 157 if err != nil { 158 return 159 } 160 opt.MemoryReservationChanged = cmd.Flags().Changed("memory-reservation") 161 opt.MemoryReservation, err = cmd.Flags().GetString("memory-reservation") 162 if err != nil { 163 return 164 } 165 opt.MemorySwap, err = cmd.Flags().GetString("memory-swap") 166 if err != nil { 167 return 168 } 169 opt.MemorySwappiness64Changed = cmd.Flags().Changed("memory-swappiness") 170 opt.MemorySwappiness64, err = cmd.Flags().GetInt64("memory-swappiness") 171 if err != nil { 172 return 173 } 174 opt.KernelMemoryChanged = cmd.Flag("kernel-memory").Changed 175 opt.KernelMemory, err = cmd.Flags().GetString("kernel-memory") 176 if err != nil { 177 return 178 } 179 opt.OomKillDisable, err = cmd.Flags().GetBool("oom-kill-disable") 180 if err != nil { 181 return 182 } 183 opt.OomScoreAdjChanged = cmd.Flags().Changed("oom-score-adj") 184 opt.OomScoreAdj, err = cmd.Flags().GetInt("oom-score-adj") 185 if err != nil { 186 return 187 } 188 opt.PidsLimit, err = cmd.Flags().GetInt64("pids-limit") 189 if err != nil { 190 return 191 } 192 opt.CgroupConf, err = cmd.Flags().GetStringSlice("cgroup-conf") 193 if err != nil { 194 return 195 } 196 opt.BlkioWeight, err = cmd.Flags().GetUint16("blkio-weight") 197 if err != nil { 198 return 199 } 200 opt.Cgroupns, err = cmd.Flags().GetString("cgroupns") 201 if err != nil { 202 return 203 } 204 opt.CgroupParent, err = cmd.Flags().GetString("cgroup-parent") 205 if err != nil { 206 return 207 } 208 opt.Device, err = cmd.Flags().GetStringSlice("device") 209 if err != nil { 210 return 211 } 212 // #endregion 213 214 // #region for intel RDT flags 215 opt.RDTClass, err = cmd.Flags().GetString("rdt-class") 216 if err != nil { 217 return 218 } 219 // #endregion 220 221 // #region for user flags 222 // If user is set we will attempt to start container with that user (must be present on the host) 223 // Otherwise we will inherit permissions from the user that the containerd process is running as 224 opt.User, err = cmd.Flags().GetString("user") 225 if err != nil { 226 return 227 } 228 opt.Umask = "" 229 if cmd.Flags().Changed("umask") { 230 opt.Umask, err = cmd.Flags().GetString("umask") 231 if err != nil { 232 return 233 } 234 } 235 opt.GroupAdd, err = cmd.Flags().GetStringSlice("group-add") 236 if err != nil { 237 return 238 } 239 // #endregion 240 241 // #region for security flags 242 opt.SecurityOpt, err = cmd.Flags().GetStringArray("security-opt") 243 if err != nil { 244 return 245 } 246 opt.CapAdd, err = cmd.Flags().GetStringSlice("cap-add") 247 if err != nil { 248 return 249 } 250 opt.CapDrop, err = cmd.Flags().GetStringSlice("cap-drop") 251 if err != nil { 252 return 253 } 254 opt.Privileged, err = cmd.Flags().GetBool("privileged") 255 if err != nil { 256 return 257 } 258 // #endregion 259 260 // #region for runtime flags 261 opt.Runtime, err = cmd.Flags().GetString("runtime") 262 if err != nil { 263 return 264 } 265 opt.Sysctl, err = cmd.Flags().GetStringArray("sysctl") 266 if err != nil { 267 return 268 } 269 // #endregion 270 271 // #region for volume flags 272 opt.Volume, err = cmd.Flags().GetStringArray("volume") 273 if err != nil { 274 return 275 } 276 // tmpfs needs to be StringArray, not StringSlice, to prevent "/foo:size=64m,exec" from being split to {"/foo:size=64m", "exec"} 277 opt.Tmpfs, err = cmd.Flags().GetStringArray("tmpfs") 278 if err != nil { 279 return 280 } 281 opt.Mount, err = cmd.Flags().GetStringArray("mount") 282 if err != nil { 283 return 284 } 285 opt.VolumesFrom, err = cmd.Flags().GetStringArray("volumes-from") 286 if err != nil { 287 return 288 } 289 // #endregion 290 291 // #region for rootfs flags 292 opt.ReadOnly, err = cmd.Flags().GetBool("read-only") 293 if err != nil { 294 return 295 } 296 opt.Rootfs, err = cmd.Flags().GetBool("rootfs") 297 if err != nil { 298 return 299 } 300 // #endregion 301 302 // #region for env flags 303 opt.EntrypointChanged = cmd.Flags().Changed("entrypoint") 304 opt.Entrypoint, err = cmd.Flags().GetStringArray("entrypoint") 305 if err != nil { 306 return 307 } 308 opt.Workdir, err = cmd.Flags().GetString("workdir") 309 if err != nil { 310 return 311 } 312 opt.Env, err = cmd.Flags().GetStringArray("env") 313 if err != nil { 314 return 315 } 316 opt.EnvFile, err = cmd.Flags().GetStringSlice("env-file") 317 if err != nil { 318 return 319 } 320 // #endregion 321 322 // #region for metadata flags 323 opt.NameChanged = cmd.Flags().Changed("name") 324 opt.Name, err = cmd.Flags().GetString("name") 325 if err != nil { 326 return 327 } 328 opt.Label, err = cmd.Flags().GetStringArray("label") 329 if err != nil { 330 return 331 } 332 opt.LabelFile, err = cmd.Flags().GetStringSlice("label-file") 333 if err != nil { 334 return 335 } 336 opt.CidFile, err = cmd.Flags().GetString("cidfile") 337 if err != nil { 338 return 339 } 340 opt.PidFile = "" 341 if cmd.Flags().Changed("pidfile") { 342 opt.PidFile, err = cmd.Flags().GetString("pidfile") 343 if err != nil { 344 return 345 } 346 } 347 // #endregion 348 349 // #region for logging flags 350 // json-file is the built-in and default log driver for nerdctl 351 opt.LogDriver, err = cmd.Flags().GetString("log-driver") 352 if err != nil { 353 return 354 } 355 opt.LogOpt, err = cmd.Flags().GetStringArray("log-opt") 356 if err != nil { 357 return 358 } 359 // #endregion 360 361 // #region for shared memory flags 362 opt.IPC, err = cmd.Flags().GetString("ipc") 363 if err != nil { 364 return 365 } 366 opt.ShmSize, err = cmd.Flags().GetString("shm-size") 367 if err != nil { 368 return 369 } 370 // #endregion 371 372 // #region for gpu flags 373 opt.GPUs, err = cmd.Flags().GetStringArray("gpus") 374 if err != nil { 375 return 376 } 377 // #endregion 378 379 // #region for ulimit flags 380 opt.Ulimit, err = cmd.Flags().GetStringSlice("ulimit") 381 if err != nil { 382 return 383 } 384 // #endregion 385 386 // #region for ipfs flags 387 opt.IPFSAddress, err = cmd.Flags().GetString("ipfs-address") 388 if err != nil { 389 return 390 } 391 // #endregion 392 393 // #region for image pull and verify options 394 imageVerifyOpt, err := processImageVerifyOptions(cmd) 395 if err != nil { 396 return 397 } 398 opt.ImagePullOpt = types.ImagePullOptions{ 399 GOptions: opt.GOptions, 400 VerifyOptions: imageVerifyOpt, 401 IPFSAddress: opt.IPFSAddress, 402 Stdout: opt.Stdout, 403 Stderr: opt.Stderr, 404 } 405 // #endregion 406 407 return opt, nil 408 } 409 410 func createAction(cmd *cobra.Command, args []string) error { 411 createOpt, err := processContainerCreateOptions(cmd) 412 if err != nil { 413 return err 414 } 415 416 if (createOpt.Platform == "windows" || createOpt.Platform == "freebsd") && !createOpt.GOptions.Experimental { 417 return fmt.Errorf("%s requires experimental mode to be enabled", createOpt.Platform) 418 } 419 client, ctx, cancel, err := clientutil.NewClientWithPlatform(cmd.Context(), createOpt.GOptions.Namespace, createOpt.GOptions.Address, createOpt.Platform) 420 if err != nil { 421 return err 422 } 423 defer cancel() 424 425 netFlags, err := loadNetworkFlags(cmd) 426 if err != nil { 427 return fmt.Errorf("failed to load networking flags: %s", err) 428 } 429 430 netManager, err := containerutil.NewNetworkingOptionsManager(createOpt.GOptions, netFlags, client) 431 if err != nil { 432 return err 433 } 434 435 c, gc, err := container.Create(ctx, client, args, netManager, createOpt) 436 if err != nil { 437 if gc != nil { 438 gc() 439 } 440 return err 441 } 442 // defer setting `nerdctl/error` label in case of error 443 defer func() { 444 if err != nil { 445 containerutil.UpdateErrorLabel(ctx, c, err) 446 } 447 }() 448 449 fmt.Fprintln(createOpt.Stdout, c.ID()) 450 return nil 451 }