Skip to content

Commit

Permalink
Merge pull request #10788 from infiniteregrets/multi-pull
Browse files Browse the repository at this point in the history
support pulling multiple images sequentially in a single podman pull
  • Loading branch information
openshift-merge-robot authored Jul 6, 2021
2 parents 2681484 + 59abb77 commit ba29b30
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 66 deletions.
28 changes: 14 additions & 14 deletions cmd/podman/images/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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,
Expand Down Expand Up @@ -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()
}
131 changes: 80 additions & 51 deletions docs/source/markdown/podman-pull.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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]]*

Expand All @@ -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**

Expand All @@ -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...
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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...
Expand All @@ -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 <[email protected]>
18 changes: 17 additions & 1 deletion test/e2e/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit ba29b30

Please sign in to comment.