diff options
-rw-r--r-- | cmd/podman/images/pull.go | 28 | ||||
-rw-r--r-- | docs/source/markdown/podman-pull.1.md | 131 | ||||
-rw-r--r-- | test/e2e/pull_test.go | 18 |
3 files changed, 111 insertions, 66 deletions
diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go index a831ea848..a4e3515db 100644 --- a/cmd/podman/images/pull.go +++ b/cmd/podman/images/pull.go @@ -10,6 +10,7 @@ import ( "github.com/containers/image/v5/types" "github.com/containers/podman/v3/cmd/podman/common" "github.com/containers/podman/v3/cmd/podman/registry" + "github.com/containers/podman/v3/cmd/podman/utils" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/util" "github.com/pkg/errors" @@ -32,8 +33,8 @@ var ( // Command: podman pull pullCmd = &cobra.Command{ - Use: "pull [options] IMAGE", - Args: cobra.ExactArgs(1), + Use: "pull [options] IMAGE [IMAGE...]", + Args: cobra.MinimumNArgs(1), Short: "Pull an image from a registry", Long: pullDescription, RunE: imagePull, @@ -154,17 +155,16 @@ func imagePull(cmd *cobra.Command, args []string) error { } // Let's do all the remaining Yoga in the API to prevent us from // scattering logic across (too) many parts of the code. - pullReport, err := registry.ImageEngine().Pull(registry.GetContext(), args[0], pullOptions.ImagePullOptions) - if err != nil { - return err - } - - if len(pullReport.Images) > 1 { - fmt.Println("Pulled Images:") - } - for _, img := range pullReport.Images { - fmt.Println(img) + var errs utils.OutputErrors + for _, arg := range args { + pullReport, err := registry.ImageEngine().Pull(registry.GetContext(), arg, pullOptions.ImagePullOptions) + if err != nil { + errs = append(errs, err) + continue + } + for _, img := range pullReport.Images { + fmt.Println(img) + } } - - return nil + return errs.PrintErrors() } diff --git a/docs/source/markdown/podman-pull.1.md b/docs/source/markdown/podman-pull.1.md index 084327efd..10661e16e 100644 --- a/docs/source/markdown/podman-pull.1.md +++ b/docs/source/markdown/podman-pull.1.md @@ -4,24 +4,20 @@ podman\-pull - Pull an image from a registry ## SYNOPSIS -**podman pull** [*options*] *source* +**podman pull** [*options*] *source* [*source*...] -**podman image pull** [*options*] *source* +**podman image pull** [*options*] *source* [*source*...] **podman pull** [*options*] [*transport*]*name*[:*tag*|@*digest*] **podman image pull** [*options*] [*transport*]*name*[:*tag*|@*digest*] ## DESCRIPTION -Copies an image from a registry onto the local machine. The **podman pull** command pulls an -image. If the image reference in the command line argument does not contain a registry, it is referred to as a`short-name` reference. If the image is a 'short-name' reference, Podman will prompt the user for the specific container registry to pull the image from, if an alias for the short-name has not been specified in the short-name-aliases.conf. If an image tag is not specified, **podman pull** defaults to the image with the **latest** tag (if it exists) and pulls it. After the image is pulled, podman will print the full image ID. **podman pull** can also pull an image using its digest **podman pull** *image*@*digest*. **podman pull** can be used to pull images from archives and local storage using different transports. - -## Image storage -Images are stored in local image storage. +podman pull copies an image from a registry onto the local machine. The command can pull one or more images. If the image reference in the command line argument does not contain a registry, it is referred to as a`short-name` reference. If the image is a 'short-name' reference, Podman will prompt the user for the specific container registry to pull the image from, if an alias for the short-name has not been specified in the `short-name-aliases.conf`. If an image tag is not specified, **podman pull** defaults to the image with the **latest** tag (if it exists) and pulls it. After the image is pulled, podman will print the full image ID. **podman pull** can also pull images using a digest **podman pull** *image*@*digest* and can also be used to pull images from archives and local storage using different transports. +*IMPORTANT: Images are stored in local image storage.* ## SOURCE - - SOURCE is the location from the container image is pulled from. It supports all transports from `containers-transports(5)`. If no transport is specified, the input is subject to short-name resolution and the `docker` (i.e., container registry) transport is used. For remote clients, `docker` is the only supported transport. +SOURCE is the location from the container image is pulled from. It supports all transports from **[containers-transports(5)](https://github.com/containers/image/blob/main/docs/containers-transports.5.md)**. If no transport is specified, the input is subject to short-name resolution and the `docker` (i.e., container registry) transport is used. For remote clients, `docker` is the only supported transport. ``` # Pull from a container registry @@ -47,28 +43,27 @@ $ podman pull oci-archive:/tmp/myimage ``` ## OPTIONS - #### **--all-tags**, **a** All tagged images in the repository will be pulled. -Note: When using the all-tags flag, Podman will not iterate over the search registries in the containers-registries.conf(5) but will always use docker.io for unqualified image names. +*IMPORTANT: When using the all-tags flag, Podman will not iterate over the search registries in the **[containers-registries.conf(5)](https://github.com/containers/image/blob/main/docs/containers-registries.conf.5.md)** but will always use docker.io for unqualified image names.* #### **--arch**=*ARCH* Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. #### **--authfile**=*path* -Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. -If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using `docker login`. +Path of the authentication file. If the authorization state is not found there, `$HOME/.docker/config.json` is checked, which is set using `docker login`. -Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE -environment variable. `export REGISTRY_AUTH_FILE=path` +Default is `${XDG\_RUNTIME\_DIR}/containers/auth.json`, which is set using `podman login`. + +*IMPORTANT: The default path of the authentication file can be overwritten by setting the `REGISTRY\_AUTH\_FILE` environment variable. `export REGISTRY_AUTH_FILE=path`* #### **--cert-dir**=*path* Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. -Please refer to containers-certs.d(5) for details. (This option is not available with the remote Podman client) +Please refer to **[containers-certs.d(5)](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)** for details. (This option is not available with the remote Podman client) #### **--creds**=*[username[:password]]* @@ -84,15 +79,17 @@ solely for scripting compatibility. #### **--help**, **-h** -Print usage statement +Print the usage statement. #### **--os**=*OS* + Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. #### **--platform**=*OS/ARCH* -Specify the platform for selecting the image. (Conflicts with --arch and --os) -The `--platform` option can be used to override the current architecture and operating system. +Specify the platform for selecting the image. The `--platform` option can be used to override the current architecture and operating system. + +*IMPORTANT: Conflicts with --arch and --os* #### **--quiet**, **-q** @@ -108,22 +105,72 @@ TLS verification will be used unless the target registry is listed as an insecur Use _VARIANT_ instead of the default architecture variant of the container image. Some images can use multiple variants of the arm architectures, such as arm/v5 and arm/v7. -## EXAMPLES +## FILES + +**short-name-aliases.conf** (`/var/cache/containers/short-name-aliases.conf`, `$HOME/.cache/containers/short-name-aliases.conf`) + +When users specify images that do not include the container registry where the +image is stored, this is called a short name. The use of unqualified-search registries entails an ambiguity as it is unclear from which registry a given image, referenced by a short name, may be pulled from. + +Using short names is subject to the risk of hitting squatted registry namespaces. If the unqualified-search registries are set to ["public-registry.com", "my-private-registry.com"] an attacker may take over a namespace of `public-registry.com` such that an image may be pulled from `public-registry.com` instead of the intended source `my-private-registry.com`. + +While it is highly recommended to always use fully-qualified image references, existing deployments using short names may not be easily changed. To circumvent the aforementioned ambiguity, so called short-name aliases can be configured that point to a fully-qualified image reference. Distributions often ship a default shortnames.conf expansion file in /etc/containers/registries.conf.d/ directory. Administrators can use this directory to add their own local short-name expansion files. +When pulling an image, if the user does not specify the complete registry, container engines attempt to expand the short-name into a full name. If the command is executed with a tty, the user will be prompted to select a registry from the +default list unqualified registries defined in registries.conf. The user's selection is then stored in a cache file to be used in all future short-name expansions. Rootfull short-names are stored in /var/cache/containers/short-name-aliases.conf. Rootless short-names are stored in the $HOME/.cache/containers/short-name-aliases.conf file. + +For more information on short-names, see `containers-registries.conf(5)` + +**registries.conf** (`/etc/containers/registries.conf`) + +registries.conf is the configuration file which specifies which container registries should be consulted when completing image names which do not include a registry or domain portion. + +NOTE: Use the environment variable `TMPDIR` to change the temporary storage location of downloaded container images. Podman defaults to use `/var/tmp`. + + +## EXAMPLES +Pull a single image with short name resolution. ``` $ podman pull alpine:latest -Trying to pull registry.access.redhat.com/alpine:latest... Failed -Trying to pull registry.fedoraproject.org/alpine:latest... Failed -Trying to pull docker.io/library/alpine:latest...Getting image source signatures -Copying blob sha256:88286f41530e93dffd4b964e1db22ce4939fffa4a4c665dab8591fbab03d4926 - 1.90 MB / 1.90 MB [========================================================] 0s -Copying config sha256:76da55c8019d7a47c347c0dceb7a6591144d232a7dd616242a367b8bed18ecbc - 1.48 KB / 1.48 KB [========================================================] 0s +Resolved "alpine" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf) +Trying to pull docker.io/library/alpine:latest... +Getting image source signatures +Copying blob 5843afab3874 done +Copying config d4ff818577 done +Writing manifest to image destination +Storing signatures +d4ff818577bc193b309b355b02ebc9220427090057b54a59e73b79bdfe139b83 +``` + +Pull multiple images with/without short name resolution. +``` +podman pull busybox:musl alpine quay.io/libpod/cirros +Trying to pull docker.io/library/busybox:musl... +Getting image source signatures +Copying blob 0c52b060233b [--------------------------------------] 0.0b / 0.0b +Copying config 9ad2c435a8 done Writing manifest to image destination Storing signatures -04660052281190168dbb2362eb15bf7067a8dc642d2498055e0e72efa961a4b6 +9ad2c435a887e3f723654e09b48563de44aa3c7950246b2e9305ec85dd3422db +Trying to pull docker.io/library/alpine:latest... +Getting image source signatures +Copying blob 5843afab3874 [--------------------------------------] 0.0b / 0.0b +Copying config d4ff818577 done +Writing manifest to image destination +Storing signatures +d4ff818577bc193b309b355b02ebc9220427090057b54a59e73b79bdfe139b83 +Trying to pull quay.io/libpod/cirros:latest... +Getting image source signatures +Copying blob 8da581cc9286 done +Copying blob 856628d95d17 done +Copying blob f513001ba4ab done +Copying config 3c82e4d066 done +Writing manifest to image destination +Storing signatures +3c82e4d066cf6f9e50efaead6e3ff7fddddf5527826afd68e5a969579fc4db4a ``` +Pull an image using its digest. ``` $ podman pull alpine@sha256:d7342993700f8cd7aba8496c2d0e57be0666e80b4c441925fc6f9361fa81d10e Trying to pull docker.io/library/alpine@sha256:d7342993700f8cd7aba8496c2d0e57be0666e80b4c441925fc6f9361fa81d10e... @@ -135,6 +182,7 @@ Storing signatures d6e46aa2470df1d32034c6707c8041158b652f38d2a9ae3d7ad7e7532d22ebe0 ``` +Pull an image by specifiying an authentication file. ``` $ podman pull --authfile temp-auths/myauths.json docker://docker.io/umohnani/finaltest Trying to pull docker.io/umohnani/finaltest:latest...Getting image source signatures @@ -147,6 +195,7 @@ Storing signatures 03290064078cb797f3e0a530e78c20c13dd22a3dd3adf84a5da2127b48df0438 ``` +Pull an image by authenticating to a registry. ``` $ podman pull --creds testuser:testpassword docker.io/umohnani/finaltest Trying to pull docker.io/umohnani/finaltest:latest...Getting image source signatures @@ -159,6 +208,7 @@ Storing signatures 03290064078cb797f3e0a530e78c20c13dd22a3dd3adf84a5da2127b48df0438 ``` +Pull an image using tls verification. ``` $ podman pull --tls-verify=false --cert-dir image/certs docker.io/umohnani/finaltest Trying to pull docker.io/umohnani/finaltest:latest...Getting image source signatures @@ -171,6 +221,7 @@ Storing signatures 03290064078cb797f3e0a530e78c20c13dd22a3dd3adf84a5da2127b48df0438 ``` +Pull an image by overriding the host architecture. ``` $ podman pull --arch=arm arm32v7/debian:stretch Trying to pull docker.io/arm32v7/debian:stretch... @@ -182,30 +233,8 @@ Storing signatures 3cba58dad5d9b35e755b48b634acb3fdd185ab1c996ac11510cc72c17780e13c ``` -## FILES - -**short-name-aliases.conf** (`/var/cache/containers/short-name-aliases.conf`, `$HOME/.cache/containers/short-name-aliases.conf`) - -When users specify images that do not include the container registry where the -image is stored, this is called a short name. The use of unqualified-search registries entails an ambiguity as it is unclear from which registry a given image, referenced by a short name, may be pulled from. - -Using short names is subject to the risk of hitting squatted registry namespaces. If the unqualified-search registries are set to ["public-registry.com", "my-private-registry.com"] an attacker may take over a namespace of `public-registry.com` such that an image may be pulled from `public-registry.com` instead of the intended source `my-private-registry.com`. - -While it is highly recommended to always use fully-qualified image references, existing deployments using short names may not be easily changed. To circumvent the aforementioned ambiguity, so called short-name aliases can be configured that point to a fully-qualified image reference. Distributions often ship a default shortnames.conf expansion file in /etc/containers/registries.conf.d/ directory. Administrators can use this directory to add their own local short-name expansion files. - -When pulling an image, if the user does not specify the complete registry, container engines attempt to expand the short-name into a full name. If the command is executed with a tty, the user will be prompted to select a registry from the -default list unqualified registries defined in registries.conf. The user's selection is then stored in a cache file to be used in all future short-name expansions. Rootfull short-names are stored in /var/cache/containers/short-name-aliases.conf. Rootless short-names are stored in the $HOME/.cache/containers/short-name-aliases.conf file. - -For more information on short-names, see `containers-registries.conf(5)` - -**registries.conf** (`/etc/containers/registries.conf`) - -registries.conf is the configuration file which specifies which container registries should be consulted when completing image names which do not include a registry or domain portion. - -NOTE: Use the environment variable `TMPDIR` to change the temporary storage location of downloaded container images. Podman defaults to use `/var/tmp`. - ## SEE ALSO -podman(1), podman-push(1), podman-login(1), containers-certs.d(5), containers-registries.conf(5), containers-transports(5) +**[podman(1)](podman.1.md)**, **[podman-push(1)](podman-push.1.md)**, **[podman-login(1)](podman-login.1.md)**, **[containers-certs.d(5](https://github.com/containers/image/blob/main/docs/containers-certs.d.5.md)**, **[containers-registries.conf(5)](https://github.com/containers/image/blob/main/docs/containers-registries.d.5.md)**, **[containers-transports(5)](https://github.com/containers/image/blob/main/docs/containers-transports.5.md)** ## HISTORY July 2017, Originally compiled by Urvashi Mohnani <umohnani@redhat.com> diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go index c60ad9487..048f19b1e 100644 --- a/test/e2e/pull_test.go +++ b/test/e2e/pull_test.go @@ -35,6 +35,23 @@ var _ = Describe("Podman pull", func() { }) + It("podman pull multiple images with/without tag/digest", func() { + session := podmanTest.Podman([]string{"pull", "busybox:musl", "alpine", "alpine:latest", "quay.io/libpod/cirros", "quay.io/libpod/testdigest_v2s2@sha256:755f4d90b3716e2bf57060d249e2cd61c9ac089b1233465c5c2cb2d7ee550fdb"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"pull", "busybox:latest", "docker.io/library/ibetthisdoesnotexistfr:random", "alpine"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(125)) + expectedError := "Error initializing source docker://ibetthisdoesnotexistfr:random" + found, _ := session.ErrorGrepString(expectedError) + Expect(found).To(Equal(true)) + + session = podmanTest.Podman([]string{"rmi", "busybox", "alpine", "testdigest_v2s2", "quay.io/libpod/cirros"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman pull from docker a not existing image", func() { session := podmanTest.Podman([]string{"pull", "ibetthisdoesntexistthere:foo"}) session.WaitWithDefaultTimeout() @@ -385,7 +402,6 @@ var _ = Describe("Podman pull", func() { session := podmanTest.Podman([]string{"pull", "--all-tags", "k8s.gcr.io/pause"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - Expect(session.LineInOutputStartsWith("Pulled Images:")).To(BeTrue()) session = podmanTest.Podman([]string{"images"}) session.WaitWithDefaultTimeout() |